#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cassert>
#include <cctype>
#include <algorithm>
#include <functional>
#include <utility>
#include <vector>
using ll = long long;
const ll ha = 1000000007LL;
inline ll pow_mod(ll a, ll b) {
  ll ans = 1, res = a;
  while(b) {
    if(1LL & b) ans = ans * res % ha;
    res = res * res % ha; b >>= 1;
  }
  return ans;
}

const int maxn = 100005;
int n; int p[maxn];
int get_fa(int x) {
  if(p[x] == x) {
    return x;
  } else {
    return (p[x] = get_fa(p[x]));
  }
}
inline void merge_set(int u, int v) {
  u = get_fa(u); v = get_fa(v);
  p[u] = v;
}
inline bool is_same(int x, int y) {
  return (get_fa(x) == get_fa(y));
}
inline void init_set() {
  for(int i = 1; i <= n; i ++) p[i] = i;
}

struct Edge {
  int u, v; ll w;
  Edge(int a = 0, int b = 0, ll c = -0x7fffffffffLL) {
    u = a; v = b; w = c;
  }
  bool operator <(const Edge &res) const {
    return w < res.w;
  }
};
std::vector<Edge> G[maxn];
inline void ins_edge(int u, int v, ll w) {
  G[u].push_back(Edge(u, v, w));
  G[v].push_back(Edge(v, u, w));
}

int dep[maxn], anc[maxn][19];
Edge maxv[maxn][19];
void dfs(int x, int depth = 1, Edge up = Edge()) {
  const int fa = up.u;
#ifdef LOCAL
  // printf("Visiting (%d, %d, %d)\n", x, depth, fa);
#endif
  dep[x] = depth; anc[x][0] = fa;
  maxv[x][0] = up;
  for(auto e : G[x]) {
    int v = e.v;
    if(v != fa) {
      dfs(v, depth + 1, e);
    }
  }
}
void process() {
  dfs(1);
  for(int j = 1; (1 << j) < n; j ++) {
    for(int i = 1; i <= n; i ++) {
      const int a = anc[i][j - 1];
      if(a) {
        anc[i][j] = anc[a][j - 1];
        maxv[i][j] = std::max(maxv[i][j - 1], maxv[a][j - 1]);
      }
    }
  }
}
ll get_max(int u, int v) {
  if(dep[u] < dep[v]) std::swap(u, v);
  ll ret = -0x7fffffffffLL;
  for(int j = 18; j >= 0; j --) {
    const int a = anc[u][j];
    if(dep[a] >= dep[v]) {
      ret = std::max(ret, maxv[u][j].w);
      u = a;
    }
  }
  if(u == v) return ret;
  for(int j = 18; j >= 0; j --) {
    const int a = anc[u][j], a2 = anc[v][j];
    if(a != a2) {
      ret = std::max(ret, maxv[u][j].w);
      ret = std::max(ret, maxv[v][j].w);
      u = a; v = a2;
    }
  }
  ret = std::max(ret, maxv[u][0].w);
  ret = std::max(ret, maxv[v][0].w);
  return ret;
}

std::vector<Edge> E, E2;
inline ll kruskal() {
  init_set();
  std::sort(E.begin(), E.end());
  ll ans = 0;
  for(auto e : E) {
    int u = e.u, v = e.v; ll w = e.w;
    if(is_same(u, v)) {
      E2.push_back(e);
    } else {
#ifdef LOCAL
      printf("New Edge (%d, %d, %lld)\n", u, v, w);
#endif
      merge_set(u, v);
      ans += w;
      ins_edge(u, v, w);
    }
  }
  return ans;
}

int main() {
  int m; ll X; scanf("%d%d%lld", &n, &m, &X);
  for(int i = 1; i <= m; i ++) {
    int u, v; ll w;
    scanf("%d%d%lld", &u, &v, &w);
    E.push_back(Edge(u, v, w));
  }
  ll dv = kruskal();
  if(dv > X) {
    puts("0"); return 0;
  }
  process();
  ll delta = X - dv;
  int equal = 0, upper = 0;
  for(auto e : E2) {
    ll th = e.w - get_max(e.u, e.v);
    if(th == delta) {
      equal ++;
    } else if(th > delta) {
      upper ++;
    }
  }
  ll ans = 2LL * (pow_mod(2, equal) - 1LL) % ha * pow_mod(2, upper) % ha;
  if(delta == 0LL) {
    ans = (ans + (pow_mod(2, n - 1) - 2LL + ha) * pow_mod(2, m - n + 1)) % ha;
  }
  printf("%lld\n", ans);
  return 0;
}

Measured memory_bytes: 34048