#include<iostream>
#include<vector>
#include<queue>
using namespace std;

const long long MOD = 1000000007;
long long S;

vector<long long> use_e;

vector<pair<long long, long long> > G[1001];
bool visited[1001];
long long pathmax[2001];
long long diff[2001];
long long lower=0, equ=0, upper=0;

struct UnionFind{
    vector<long long> root;
    vector<long long> sizes;
    UnionFind(long long n): root(n + 1), sizes(n + 1,1){
        for(long long i = 0; i <= n; i++) root[i] = i;
    }
    long long find(long long x){
        if(x == root[x]) return x;
        return root[x] = find(root[x]);
    }
    void unite(long long x, long long y){
        x = find(x);
        y = find(y);
        if(x == y) return;
        if(sizes[x] < sizes[y]) swap(x,y);
        root[y] = x;
        sizes[x] += sizes[y];
        sizes[y] = 0;
    }
    bool same(long long x, long long y){
        return find(x) == find(y);
    }
};

struct edge{
    long long v1, v2;
    long long w;
};

void kruskal(long long V, long long E, struct edge *e){
    
    auto compare = [](pair<long long, long long> pair1, pair<long long, long long> pair2){
        return pair1.second > pair2.second;
    };
    
    priority_queue<
    pair<long long, long long>,
    vector<pair<long long, long long> >,
    decltype(compare)
    > pq{compare};

    UnionFind uf(V);

    S=0;

    long long i;
    pair<long long, long long> p;
    for(i = 1; i <= E; i++) pq.push(make_pair(i, e[i].w));
    for(i = 0; i < V-1;){
        if(pq.empty()) break;
        else{
            p = pq.top();
            pq.pop();
        }
        if(!uf.same(e[p.first].v1,e[p.first].v2)){
            uf.unite(e[p.first].v1,e[p.first].v2);
            S+=e[p.first].w;
            use_e.push_back(p.first);
            G[e[p.first].v1].push_back(make_pair(e[p.first].v2,e[p.first].w));
            G[e[p.first].v2].push_back(make_pair(e[p.first].v1,e[p.first].w));
            i++;
        }
    }
}

struct edge e[2000 + 1];

long long dfs(long long v, long long v2, long long max_w){
    if(v2==v) return max_w;
    long long i;
    long long to, wei, val;
    for(i=0; i<G[v].size(); i++){
        to=G[v][i].first;
        wei=G[v][i].second;
        if(visited[to]==0){
            visited[to]=1;
            val=dfs(to,v2,max(max_w,wei));
            if(val>0) return val;
        }
    }
    return -1;
}

int main(){
    //input
    long long V, E;
    cin >> V >> E;
    long long X;
    cin >> X;
    long long j;
    for(j = 1; j <= E; j++){
        cin >> e[j].v1 >> e[j].v2 >> e[j].w;
    }

    //calc
    long long nibeki[E+1];
    nibeki[0]=1;
    for(j=1; j<=E; j++){
        nibeki[j]=2*nibeki[j-1];
        nibeki[j]%=MOD;
    }
    kruskal(V, E, e);
    long long D=X-S;
    for(j=1; j<=E; j++){
        fill(visited,visited+V+1,0);
        visited[e[j].v1]=1;
        pathmax[j]=dfs(e[j].v1,e[j].v2,0);
    }
    for(j=1; j<=E; j++){
        diff[j]=e[j].w-pathmax[j];
    }
    for(j=0; j<use_e.size(); j++){
        diff[use_e[j]]=-1;
    }
    for(j=1; j<=E; j++){
        if(diff[j]<0) continue;
        if(diff[j]<D){
            lower++;
        }else if(diff[j]>D){
            upper++;
        }else{
            equ++;
        }
    }
    if(D<0){
        cout << 0 << endl;
    }else if(D>0){
        cout << (((long long)2)*(nibeki[equ]-1)*nibeki[upper])%MOD << endl;
    }else{
        cout <<  ( (((long long)2)*(nibeki[equ]-1)*nibeki[upper])%MOD + ((nibeki[V-1]-(long long)2)*nibeki[E-V+1])%MOD )%MOD << endl;
    }
    system("pause");
    return 0;
}

Measured memory_bytes: 3924