#pragma GCC optimize("Ofast")
#pragma GCC optimize("no-stack-protector")
//#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,popcnt,abm,mmx,tune=native")
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <stdio.h>
#include <cstdio>
#include <math.h>
#include <cmath>
#include <string>
#include <cstring>
#include <queue>
#include <deque>
#include <random>
#include <iomanip>
#include <bitset>
                        
using namespace std;
                        
template<typename T> void uin(T &a, T b) {
    if (b < a) {
        a = b;
    }
}
                        
template<typename T> void uax(T &a, T b) {
    if (b > a) {
        a = b;
    }
}

#define int long long
#define ghost signed
#define left left228
#define right right228
#define complex complex228
#define count count228
#define sin sin228
#define list list228

const int MOD = 1e9 + 7;
const int N = 10 * 1000;

int mod(int x) {
	x %= MOD;
	if (x < 0) x += MOD;
	return x;
}

int fp(int a, int b) {
	int res = 1;
	while (b) {
		if (b & 1) res = mod(res * a);
		a = mod(a * a);
		b >>= 1;
	}
	return res;
}

int p[N][20], MX[N][20], tin[N], tout[N], timer = 0;
vector< pair<int, int> > g[N];

void dfs(int v, int weight, int par = 1) {
	MX[v][0] = weight;
	p[v][0] = par;
	for (int k = 1; k < 20; ++k) {
		p[v][k] = p[p[v][k - 1]][k - 1];
		MX[v][k] = max(MX[v][k - 1], MX[p[v][k - 1]][k - 1]);
	}
	tin[v] = timer++;
	for (pair<int, int> go : g[v]) {
		int to = go.first, w = go.second;
		if (to != par) dfs(to, w, v);
	}
	tout[v] = timer++;
}
bool anc(int u, int v) {
	return tin[u] <= tin[v] && tout[u] >= tout[v];
}
int get_lca(int u, int v) {
	if (anc(u, v)) return u;
	if (anc(v, u)) return v;
	for (int k = 19; k + 1; --k) {
		if (!anc(p[u][k], v)) u = p[u][k];
	}
	return p[u][0];
}
int get_up(int u, int v) {
	int mx = 0;
	for (int k = 19; k >= 0; --k) {
		if (!anc(p[u][k], v)) {
			uax(mx, MX[u][k]);
			u = p[u][k];
		}
	}
	if (u != v) uax(mx, MX[u][0]);
	return mx;
}
int get_max(int u, int v) {
	int lca = get_lca(u, v);
	return max(get_up(u, lca), get_up(v, lca));
}

struct Edge
{
	int u, v, c;
	Edge() {}
	Edge(int _u, int _v, int _c) {u = _u, v = _v, c = _c;}
};
bool operator<(Edge fir, Edge sec) { return fir.c < sec.c; }

namespace DSU
{
	const int N = 10000;
	int p[N], sz[N];
	void init(int n) {
		for (int i = 1; i <= n; ++i) p[i] = i, sz[i] = 1;
	}
	int getp(int v) {
		if (v == p[v]) return v;
		p[v] = getp(p[v]);
		return p[v];
	}
	void join(int u, int v) {
		u = getp(u), v = getp(v);
		if (u != v) {
			if (sz[u] < sz[v]) {
				p[u] = v;
				sz[v] += sz[u];
			} else {
				p[v] = u;
				sz[u] += sz[v];
			}
		}
	}
	bool con(int u, int v) { return getp(u) == getp(v); }
}


ghost main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
	int n, m;
	cin >> n >> m;
	int x;
	cin >> x;
	vector< Edge > edges;
	for (int i = 0; i < m; ++i) {
		int u, v, w;
		cin >> u >> v >> w;
		edges.emplace_back(u, v, w);
	}
	sort(edges.begin(), edges.end());
	DSU::init(n);
	int MST = 0;
	for (auto e : edges) {
		int u = e.u, v = e.v, c = e.c;
		if (!DSU::con(u, v)) {
			DSU::join(u, v);
			MST += c;
			g[u].emplace_back(v, c);
			g[v].emplace_back(u, c);
		}
	}
	if (x < MST) {
		cout << 0 << '\n';
		return 0;
	}
	dfs(1, 0);
	int LESS = 0, EQUAL = 0, MORE = 0;
	for (auto e : edges) {
		int u = e.u, v = e.v, c = e.c;
		int mx = get_max(u, v);
		if (MST + c - mx < x) ++LESS;
		else if (MST + c - mx == x) ++EQUAL;
		else ++MORE;
	}
	if (LESS == 0) {
		int res = mod((fp(2, EQUAL) - 2) * fp(2, MORE));
		cout << res << '\n';
		return 0;
	}
	int res = mod(mod(2 * (fp(2, EQUAL) - 1)) * fp(2, MORE));
	cout << res << '\n';
    return 0;
} // kek ;
// Ого! Кажетсья это $#@!
 



















Measured memory_bytes: 1024