#include "bits/stdc++.h"
using namespace std;

#define DEBUG(x) cout<<#x<<": "<<x<<endl;
#define DEBUG_VEC(v) cout<<#v<<":";for(int i=0;i<v.size();i++) cout<<" "<<v[i]; cout<<endl

typedef long long ll;
#define vi vector<int>
#define vl vector<ll>
#define vii vector< vector<int> >
#define vll vector< vector<ll> >
#define vs vector<string>
#define pii pair<int,int>
#define pis pair<int,string>
#define psi pair<string,int>
#define pll pair<ll,ll>
#define fi first
#define se second
#define rep(i,n) for(int i=0;i<(int)(n);i++)
#define rep1(i,n) for(int i=1;i<=(int)(n);i++)
#define all(c) c.begin(),c.end()
const int inf = 1000000001;
const ll INF = 2e18;
const ll MOD = 1000000007;
const ll mod = 1000000009;
const double pi = 3.14159265358979323846;
#define Sp(p) cout<<setprecision(15)<< fixed<<p<<endl;
int dx[4] = { 1,0,-1,0 }, dy[4] = { 0,1,0,-1 };
int dx2[8] = { 1,1,0,-1,-1,-1,0,1 }, dy2[8] = { 0,1,1,1,0,-1,-1,-1 };


const int N = 1010;
const int M = 2010;
int n;
vector< pair<ll, pll> > edges(M);
vector<vector<pll> > G(N);
vector<bool> used(M, false);
vll maxpath(N, vl(N));

class UnionFind {
public:
	int n;
	vi par; //親
	vi ran; //木の深さ
	vi num; //要素数

	UnionFind(int _n) {
		n = _n;
		par.resize(n); ran.resize(n); num.resize(n);
		for (int i = 0; i < n; i++) {
			par[i] = i; ran[i] = 0; num[i] = 1;
		}
	}

	//木の根を求める
	int find(int x) {
		if (par[x] == x) {
			return x;
		}
		else {
			return par[x] = find(par[x]);
		}
	}

	//xとyの属する集合を併合
	void unite(int x, int y) {
		x = find(x); y = find(y);
		int numsum = num[x] + num[y];
		if (x == y) {
			return;
		}
		if (ran[x]<ran[y]) {
			par[x] = y;
		}
		else {
			par[y] = x;
			if (ran[x] == ran[y]) {
				ran[x]++;
			}
		}
		num[x] = num[y] = numsum;
	}

	//xとyが同じ集合に属するか否か
	bool same(int x, int y) {
		return find(x) == find(y);
	}

};


ll kruskal() {
	sort(edges.begin(), edges.end());
	UnionFind uf(n);
	ll res = 0;
	for (int i = 0; i < edges.size(); i++) {
		if (!uf.same(edges[i].second.first, edges[i].second.second)) {
			uf.unite(edges[i].second.first, edges[i].second.second);
			res += edges[i].first;
			used[i] = true;
		}
	}
	return res;
}

void dfs(int root, int parent, int now, ll ma) {
	maxpath[root][now] = maxpath[now][root] = ma;
	rep(i, G[now].size()) {
		int child = G[now][i].first;
		if (child == parent) {
			continue;
		}
		ll nextma = max(ma, G[now][i].second);
		dfs(root, now, child, nextma);
	}
}

ll mod_pow(ll x, ll p, ll M) {
	ll a = 1;
	while (p) {
		if (p % 2)
			a = a*x%M;
		x = x*x%M;
		p /= 2;
	}
	return a;
}


int main() {
	int m;
	cin >> n >> m;
	ll x;
	cin >> x;
	edges.resize(m);
	rep(i, m) {
		int u, v;
		ll w;
		cin >> u >> v >> w;
		u--; v--;
		edges[i].first = w;
		edges[i].second.first = u;
		edges[i].second.second = v;
	}
	ll s = kruskal();
	rep(i, m) {
		if (used[i]) {
			int u = edges[i].second.first, v = edges[i].second.second;
			ll w = edges[i].first;
			G[u].push_back(pll(v, w)); G[v].push_back(pll(u, w));
		}
	}
	rep(i, n) {
		dfs(i, -1, i, 0);
	}
	int lower = 0, equal = 0, upper = 0;
	rep(i, m) {
		if (used[i]) {
			continue;
		}
		int u = edges[i].second.first, v = edges[i].second.second;
		ll w = edges[i].first;
		if (s + (w - maxpath[u][v]) < x) {
			lower++;
		}
		else if (s + (w - maxpath[u][v]) > x) {
			upper++;
		}
		else {
			equal++;
		}
	}
	if (s > x) {
		cout << 0 << endl;
	}
	else if (s < x) {
		ll ans = 2 * (mod_pow(2, equal, MOD) - 1) % MOD*mod_pow(2, upper, MOD) % MOD;
		while (ans < 0) {
			ans += MOD;
		}
		cout << ans << endl;
	}
	else {
		ll ans = 0;
		ans += 2 * (mod_pow(2, equal, MOD) - 1) % MOD*mod_pow(2, upper, MOD) % MOD;
		ans += (mod_pow(2, n - 1, MOD) - 2)*mod_pow(2, m - (n - 1), MOD) % MOD;
		ans %= MOD;
		while (ans < 0) {
			ans += MOD;
		}
		cout << ans << endl;
	}
}

Measured memory_bytes: 8448