#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <algorithm>
#include <set>
#include <map>
#include <bitset>
#include <cmath>
#include <functional>
#include <iomanip>
#define vll vector<ll>
#define vvvl vector<vvl>
#define vvl vector<vector<ll>>
#define VV(a, b, c, d) vector<vector<d> >(a, vector<d>(b, c))
#define VVV(a, b, c, d) vector<vvl>(a, vvl(b, vll (c, d)));
#define re(c, b) for(ll c=0;c<b;c++)
#define all(obj) (obj).begin(), (obj).end()
typedef long long int ll;
typedef long double ld;
using namespace std;


//-------------------------------------------------------------------
#include <sstream>
#include <fstream>
ifstream ifs;
void initi(string s){ifs.open(s);}
vector<string> split(const string &str, char sep){
    vector<string> v;
    stringstream ss(str);
    string buffer;
    while(getline(ss, buffer, sep)) v.push_back(buffer);
    return v;
}
ll read(){
  string str;
  getline(ifs, str);
  return stoll(str);
}
string read_str(){
  string str;
  getline(ifs, str);
  return str;
}
vector<ll> read_vec(){
  string str;
  getline(ifs, str);
  std::vector<ll> num;
  vector<string> data = split(str, ' ');
  for(int i=0;i<data.size();i++) num.push_back(stoll(data[i]));
  return num;
}
vvl read_mat(ll h){
  string str;
  vvl num = VV(h, 0, 0, ll);
  for(int i=0;i<h;i++){
    getline(ifs, str);
    vector<string> data = split(str, ' ');
    for(int j=0;j<data.size();j++) num[i].push_back(stoll(data[j]));
  }
  return num;
}
//-------------------------------------------------------------------

#define P 1000000007
#define N_MAX 10000000
ll fac[N_MAX+1];
ll inv[N_MAX+1];
ll finv[N_MAX+1];

ll comb(ll n, ll k){
  if(n<0||k<0||n<k) return 0;
  return (((fac[n]*finv[n-k])%P)*finv[k])%P;
}

void init(){
  fac[0] = finv[0] = fac[1] = finv[1] = inv[1] = 1;
  for(int i = 2; i <= N_MAX; i++){
    fac[i] = (fac[i-1]*i)%P;
    inv[i] = ((-(P/i)*inv[P%i])%P+P)%P;
    finv[i] = (finv[i-1]*inv[i])%P;
  }
}
ll pp(ll a, ll b){
  return (a * b)%P;
}
ll mpow(ll a, ll b, ll p = -1){
  ll ret = 1, num = a;
  if(p==-1){
    while(b>0){
      if(b%2) ret *= num;
      num = num * num;
      b /= 2;
    }
  }else{
    while(b>0){
      if(b%2) ret = (ret*num)%p;
      num = (num*num)%p;
      b /= 2;
    }
  }
  return ret;
}
struct UF{
  std::vector<int> par, dep, sz;
  UF(int n){
    par.resize(n+1), dep.resize(n+1), sz.resize(n+1);
    init(n);
  }
  void init(int nu) {
    for(int iu=0;iu<=nu;iu++){
      par[iu] = iu;
      dep[iu] = 0;
      sz[iu] = 1;
    }
  }
  int find(int xu){
    if(par[xu] == xu) return xu;
    return par[xu] = find(par[xu]);
  }
  void unite(int xu, int yu){
    xu=find(xu);
    yu=find(yu);
    if(xu == yu) return;
    if(dep[xu] < dep[yu]){
      sz[yu] += sz[xu];
      par[xu] = yu;
    }else{
      par[yu] = xu;
      sz[xu] += sz[yu];
      if(dep[xu] == dep[yu]) dep[xu]++;
    }
  }
  bool same(int xu, int yu){ return find(xu) == find(yu);}
  int get_size(int x){return sz[find(x)];}
};

struct LazySegmentTree {
private:
    int n;
    vector<int> node, lazy;
    vector<bool> lazyFlag;

public:
    LazySegmentTree(vector<int> v) {
        int sz = (int)v.size();
        n = 1; while(n < sz) n *= 2;
        node.resize(2*n-1);
        lazy.resize(2*n-1, 0);
        lazyFlag.resize(2*n-1, false);
        for(int i=0; i<sz; i++) node[i+n-1] = v[i];
        for(int i=n-2; i>=0; i--) node[i] = min(node[i*2+1], node[i*2+2]);
    }

    void lazyEvaluate(int k, int l, int r) {
        if(lazyFlag[k]) {
            node[k] = lazy[k];
            if(r - l > 1) {
                lazy[k*2+1] = lazy[k*2+2] = lazy[k];
                lazyFlag[k*2+1] = lazyFlag[k*2+2] = true;
            }
            lazyFlag[k] = false;
        }
    }

    void update(int a, int b, int x, int k=0, int l=0, int r=-1) {
        if(r < 0) r = n;
        lazyEvaluate(k, l, r);
        if(b <= l || r <= a) return;
        if(a <= l && r <= b) {
            lazy[k] = x;
            lazyFlag[k] = true;
            lazyEvaluate(k, l, r);
        }
        else {
            update(a, b, x, 2*k+1, l, (l+r)/2);
            update(a, b, x, 2*k+2, (l+r)/2, r);
            node[k] = max(node[2*k+1], node[2*k+2]);
        }
    }

    int find(int a, int b, int k=0, int l=0, int r=-1) {
        if(r < 0) r = n;
        lazyEvaluate(k, l, r);
        if(b <= l || r <= a) return (ll)0;
        if(a <= l && r <= b) return node[k];
        int vl = find(a, b, 2*k+1, l, (l+r)/2);
        int vr = find(a, b, 2*k+2, (l+r)/2, r);
        return max(vl, vr);
    }
};

template< typename G >
struct HeavyLightDecomposition {
  G &g;
  vector<ll> sz, in, out, head, rev, par;
  HeavyLightDecomposition(G &g) :
      g(g), sz(4000), in(g.size()), out(g.size()), head(g.size()), rev(g.size()), par(g.size()) {}

  void dfs_sz(ll idx, ll p) {
    par[idx] = p;
    sz[idx] = 1;
    if(g[idx].size() && g[idx][0] == p) swap(g[idx][0], g[idx].back());
    for(auto &to : g[idx]) {
      if(to == p) continue;
      dfs_sz(to, idx);
      sz[idx] += sz[to];
      if(sz[g[idx][0]] < sz[to]) swap(g[idx][0], to);
    }
  }

  void dfs_hld(ll idx, ll par, ll &times) {
    in[idx] = times++;
    rev[in[idx]] = idx;
    for(auto &to : g[idx]) {
      if(to == par) continue;
      head[to] = (g[idx][0] == to ? head[idx] : to);
      dfs_hld(to, idx, times);
    }
    out[idx] = times;
  }
  void build() {
    dfs_sz(0, -1);
    ll t = 0;
    dfs_hld(0, -1, t);
  }
  ll la(ll v, ll k) {
    while(1) {
      int u = head[v];
      if(in[v] - k >= in[u]) return rev[in[v] - k];
      k -= in[v] - in[u] + 1;
      v = par[u];
    }
  }
  ll lca(ll u, ll v) {
    for(;; v = par[head[v]]) {
      if(in[u] > in[v]) swap(u, v);
      if(head[u] == head[v]) return u;
    }
  }
  template< typename T, typename Q, typename F >
  T query(ll u, ll v, const T &ti, const Q &q, const F &f, bool edge = false) {
    T l = ti, r = ti;
    for(;; v = par[head[v]]) {
      if(in[u] > in[v]) swap(u, v), swap(l, r);
      if(head[u] == head[v]) break;
      l = f(q(in[head[v]], in[v] + 1), l);
    }
    return f(f(q(in[u] + edge, in[v] + 1), l), r);
//  return {f(q(in[u] + edge, in[v] + 1), l), r};
  }

  template< typename Q >
  void add(ll u, ll v, const Q &q, bool edge = false) {
    for(;; v = par[head[v]]) {
      if(in[u] > in[v]) swap(u, v);
      if(head[u] == head[v]) break;
      q(in[head[v]], in[v] + 1);
    }
    q(in[u] + edge, in[v] + 1);
  }
};

//-------------------------------------------------------------------
int main(int argc, char const *argv[]) {
  init();
  //initi("01.txt");
  //vll o = read_vec();
  //ll n = o[0], m = o[1];
  ll n, m;std::cin >> n >> m;
  vvl G = VV(n, 0, 0, ll);
  ll X;// = read();
  std::cin >> X;
  vvl dat = VV(m, 3, 0, ll);
  re(i, m){
    scanf("%lld %lld %lld", &dat[i][1], &dat[i][2], &dat[i][0]);
    dat[i][1]--, dat[i][2]--;
    //vll tmp = read_vec();
    //dat[i] = vll{tmp[2], tmp[0]-1, tmp[1]-1};
  }
  sort(all(dat));
  set<ll> omit;
  vvl es;
  ll c = 0;
  UF ff(n+1);
  for(int i=0;i<m;i++){
    ll x = dat[i][1], y = dat[i][2];
    if(!ff.same(x, y)){
      c += dat[i][0];
      G[x].push_back(y);
      G[y].push_back(x);
      es.push_back(vll{x, y, dat[i][0]});
      omit.insert(i);
      ff.unite(x, y);
    }
  }

  ll z = 0;
  UF uf(n+1);
  ll now = 0;
  while(now<m){
    ll nowcos = dat[now][0];
    vvl un;
    while(now<m&&dat[now][0]==nowcos){
      ll x = dat[now][1], y = dat[now][2];
      if(!uf.same(x, y)) {
        z++;
        un.push_back(vll{x, y});
      }
      now++;
    }
    for(auto q:un) uf.unite(q[0], q[1]);
  }

  if(c>X){
    std::cout << 0 << '\n';
    return 0;
  }
  if(c==X){
    ll al = mpow(2, m, P);
    ll mi = pp(2, mpow(2, m-z, P));
    std::cout << (al - mi + P)%P << '\n';
    return 0;
  }
  //変えられるのは1辺のみ
  //変更することでad値が増える辺の数をaとすると、
  //最小全域木を構成する全ての辺z個が同じ色(白)
  //かつ、a個のうち少なくとも一つが黒
  //増加がad未満の残りの辺は白
  //adより大きい物は自由 := b

  HeavyLightDecomposition<vvl> hld(G);
  hld.build();
  LazySegmentTree seg(vector<int>(3000, 0));

  for(auto e:es){
    hld.add(e[0], e[1], [&](ll A, ll B){
      seg.update(A, B, e[2]);}
    ,true);
  }

  ll ad = X - c;
  ll O = 0;
  ll a = 0, b = 0;
  for(int i=0;i<m;i++){
    ll x = dat[i][1], y = dat[i][2];
    ll q = hld.query(x, y, O,
    [&](ll A, ll B){ return seg.find(A, B);},
    [&](ll C, ll D){ return max(C, D);}
    ,true);
    ll pl = dat[i][0] - q;
    if(omit.find(i)==omit.end()){
      if(pl==ad) a++;
      else if(pl>ad) b++;
    }
  }
  //std::cout << a << " " << b << '\n';
  ll k = (mpow(2, a, P) - 1 + P)%P;
  std::cout << pp(2, pp(k, mpow(2, b, P))) << '\n';
  return 0;
}


Measured memory_bytes: 235136