#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
typedef pair<ll, P> PP;

const ll MOD = 1000000007;

ll modpow(ll x, ll n){
    ll res = 1, r = x;
    while(n){
        if(n & 1) res = res * r % MOD;
        r = r * r % MOD;
        n >>= 1;
    }
    return res;
}

template <typename T>
struct Edge
{
    int to;
    T cost;
};

template <typename T>
struct WeightedGraph
{
    int n;
    vector<vector<Edge<T>>> g;
    
    WeightedGraph(int n) : n(n){
        g.resize(n);
    }
    
    void init(int n_){
        n = n_;
        g.resize(n_);
    }
    
    void add_edge(int from, int to, T cost){
        g[from].push_back((Edge<T>){to, cost});
    }
};

template <typename T>
struct WeightedTree
{
    int n;
    int root;
    vector<vector<Edge<T>>> t;
    vector<int> par;
    vector<int> dpt;
    vector<T> p;

    void init(WeightedGraph<T> &g, int root_){
        n = g.n;
        root = root_;
        t.resize(n);
        par.resize(n);
        dpt.resize(n);
        p.resize(n);
        fill(dpt.begin(), dpt.end(), -1);
        queue<int> que;
        par[root] = -1;
        dpt[root] = 0;
        que.push(root);
        while(que.size()){
            int pa = que.front();
            que.pop();
            for(Edge<T> e : g.g[pa]){
                int ch = e.to;
                if(dpt[ch] == -1){
                    t[pa].push_back(e);
                    par[ch] = pa;
                    p[ch] = e.cost;
                    dpt[ch] = dpt[pa] + 1;
                    que.push(ch);
                }
            }
        }
    }
    
    WeightedTree(){}
    
    WeightedTree(WeightedGraph<T> &g, int root_){
        init(g, root_);
    }
};

template <typename T>
struct LCA
{
    int k;
    int n;
    vector<int> dpt;
    vector<vector<int>> par;    // par[j][i] : the (2^j)th parent of i;
    
    LCA(WeightedTree<T> &t){
        n = t.n;
        for(k = 1; k <= n; k++){
            if((1 << (k - 1)) >= n) break;
        }
        dpt = t.dpt;
        par.resize(k);
        for(int j = 0; j < k; j++) par[j].resize(n);
        for(int i = 0; i < n; i++) par[0][i] = t.par[i];
        for(int j = 1; j < k; j++){
            for(int i = 0; i < n; i++){
                if(par[j - 1][i] == -1) par[j][i] = -1;
                else par[j][i] = par[j - 1][par[j - 1][i]];
            }
        }
    }
    
    int query(int u, int v){
        if(dpt[u] < dpt[v]) swap(u, v);
        int r = dpt[u] - dpt[v];
        for(int j = k - 1; j >= 0; j--) if((r >> j) & 1) u = par[j][u];
        if(u == v) return u;
        for(int j = k - 1; j >= 0; j--) if(par[j][u] != par[j][v]) u = par[j][u], v = par[j][v];
        return par[0][u];
    }
};

class UnionFind
{
    vector<int> par, rank;
    
public:
    UnionFind(int n){
        par.resize(n);
        rank.resize(n);
        for(int i = 0; i < n; i++){
            par[i] = i;
            rank[i] = 0;
        }
    }
    
    int find(int i){
        if(i == par[i]) return i;
        return par[i] = find(par[i]);
    }
    
    bool same(int i, int j){
        return find(i) == find(j);
    }
    
    void unite(int i, int j){
        if(same(i, j)) return;
        i = find(i), j = find(j);
        if(rank[i] < rank[j]) par[i] = j;
        else{
            par[j] = i;
            if(rank[i] == rank[j]) rank[i]++;
        }
    }
};

int main()
{
    int n, m;
    cin >> n >> m;
    ll x;
    cin >> x;
    PP p[2003];
    for(int i = 0; i < m; i++){
        int u, v;
        ll w;
        cin >> u >> v >> w;
        u--; v--;
        p[i] = PP(w, P(u, v));
    }
    sort(p, p + m);
    WeightedGraph<ll> g(n);
    UnionFind uf(n);
    vector<int> r;
    ll s = 0;
    for(int i = 0; i < m; i++){
        int u = p[i].second.first;
        int v = p[i].second.second;
        if(uf.same(u, v)){
            r.push_back(i);
        }
        else{
            ll w = p[i].first;
            g.add_edge(u, v, w);
            g.add_edge(v, u, w);
            uf.unite(u, v);
            s += w;
        }
    }
    if(s > x){
        cout << 0 << endl;
        return 0;
    }
    WeightedTree<ll> t(g, 0);
    LCA<ll> lca(t);
    if(s == x){
        int c = n - 1;
        for(int i : r){
            int u = p[i].second.first;
            int v = p[i].second.second;
            ll w = p[i].first;
            int a = lca.query(u, v);
            ll d = 0;
            while(u != a){
                d = max(d, t.p[u]);
                u = t.par[u];
            }
            while(v != a){
                d = max(d, t.p[v]);
                v = t.par[v];
            }
            if(d == w) c++;
        }
        cout << (modpow(2, c) + MOD - 2) % MOD * modpow(2, m - c) % MOD << endl;
    }
    else{
        int y[3]{0};
        for(int i : r){
            int u = p[i].second.first;
            int v = p[i].second.second;
            ll w = p[i].first;
            int a = lca.query(u, v);
            ll d = 0;
            while(u != a){
                d = max(d, t.p[u]);
                u = t.par[u];
            }
            while(v != a){
                d = max(d, t.p[v]);
                v = t.par[v];
            }
            if(w - d < x - s){
                y[0]++;
            }
            else if(w - d == x - s){
                y[1]++;
            }
            else{
                y[2]++;
            }
        }
        cout << (modpow(2, y[1]) + MOD - 1) * 2 % MOD * modpow(2, y[2]) % MOD << endl;
    }
}

Measured memory_bytes: 512