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

constexpr ll MOD = (ll)1e9 + 7;

ll MODpow(ll n, ll m) {
    ll result = 1;
    while (m) {
        if (m % 2 == 1) {
            result *= n;
            result %= MOD;
        }

        m /= 2;
        n *= n;
        n %= MOD;
    }

    return result;
}

class UnionFind {
public:
    UnionFind(ll n) {
        par_.resize(n);
        iota(par_.begin(), par_.end(), (ll)0);
        rank_.resize(n, 0);
    }

    //根を求める
    ll find(ll x) {
        return (par_[x] == x ? x : par_[x] = find(par_[x]));
    }

    //xとyの属する集合を併合
    void unite(ll x, ll y) {
        x = find(x);
        y = find(y);
        if (x == y) {
            return;
        }
        if (rank_[x] < rank_[y]) {
            par_[x] = y;
        } else {
            par_[y] = x;
            if (rank_[x] == rank_[y]) {
                rank_[x]++;
            }
        }
    }

    //xとyが同じ集合に属するか否かを判定
    bool same(ll x, ll y) {
        return (find(x) == find(y));
    }
private:
    vector<ll> par_, rank_;
};

ll N, M, X;
vector<vector<ll>> pathMax;
vector<vector<ll>> costT;
void dfs(ll curr, ll pre, ll start, ll max_cost) {
    pathMax[start][curr] = max_cost;
    for (ll i = 0; i < N; i++) {
        if (i == pre || costT[curr][i] == INT_MAX) {
            continue;
        }

        dfs(i, curr, start, max(max_cost, costT[curr][i]));
    }
}

int main() {
    cin >> N >> M >> X;
    
    struct Edge {
        ll node1, node2, cost;
        bool operator<(const Edge& rhs)const {
            return cost > rhs.cost;
        }
    };
    priority_queue<Edge> edges;
    vector<vector<ll>> costG(N, vector<ll>(N, INT_MAX));
    
    for (ll i = 0; i < M; i++) {
        ll U, V, W;
        cin >> U >> V >> W;
        U--; V--;
        costG[U][V] = costG[V][U] = W;
        edges.push({ U, V, W });
    }

    //最小全域木を構成
    UnionFind uf(N);
    costT.resize(N, vector<ll>(N, INT_MAX));
    ll S = 0;
    while (!edges.empty()) {
        auto t = edges.top();
        edges.pop();
        if (!uf.same(t.node1, t.node2)) {
            uf.unite(t.node1, t.node2);
            costT[t.node1][t.node2] = t.cost;
            costT[t.node2][t.node1] = t.cost;
            S += t.cost;
        }
    }

    pathMax.resize(N, vector<ll>(N, 0));
    for (ll i = 0; i < N; i++) {
        dfs(i, -1, i, 0);
    }

    ll D = X - S;
    ll lower = 0, equal = 0, upper = 0;
    for (ll i = 0; i < N; i++) {
        for (ll j = i + 1; j < N; j++) {
            //Gに含まれるがTに含まれない辺について考える
            if (costG[i][j] != INT_MAX && costT[i][j] == INT_MAX) {
                ll diff = costG[i][j] - pathMax[i][j];
                if (diff < D) {
                    lower++;
                } else if (diff == D) {
                    equal++;
                } else {
                    upper++;
                }
            }
        }
    }

    ll ans;
    if (D < 0) {
        ans = 0;
    } else if (D == 0) {
        ans = ((MODpow(2, N - 1) - 2 + MOD) % MOD * MODpow(2, M - N + 1) % MOD
                + (MODpow(2, equal) - 1 + MOD) % MOD * MODpow(2, upper + 1) % MOD) % MOD;
    } else {
        ans = (MODpow(2, equal) - 1 + MOD) % MOD * MODpow(2, upper + 1) % MOD;
    }
    cout << ans << endl;
}

Measured memory_bytes: 25856