#include <bits/stdc++.h>
using namespace std;
template <typename T> inline void read(T &x){
    char c;
    bool nega=0;
    while((!isdigit(c=getchar()))&&(c!='-'));
    if(c=='-'){
        nega=1;
        c=getchar();
    }
    x=c-48;
    while(isdigit(c=getchar())) x=x*10+c-48;
    if(nega) x=-x;
}
template <typename T> inline void writep(T x){
    if(x>9) writep(x/10);
    putchar(x%10+48);
}
template <typename T> inline void write(T x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    writep(x);
}
template <typename T> inline void writeln(T x){
    write(x);
    putchar('\n');
}
#define pb push_back
#define mp make_pair
#define NMAX 2005

typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const ll base=1e9+7;
struct data{
    ll u,v,w,id;
    inline bool operator < (const data &other) const{
        return w<other.w;
    }
} edge[NMAX];
vector <data> adj[NMAX];
int n,m;
ll X,WG[NMAX];
int p[NMAX];
bool mark[NMAX];
int par[NMAX],d[NMAX];
vector <pll> G[NMAX];
inline int findroot(int u){
    if(p[u]<0) return u;
    return p[u]=findroot(p[u]);
}
inline void Union(int u,int v){
    if(u==v) return;
    if(p[u]<p[v]){
        p[u]+=p[v];
        p[v]=u;
    }
    else{
        p[v]+=p[u];
        p[u]=v;
    }
}
ll pw(int p){
    if(p==0) return 1;
    if(p==1) return 2;
    ll tmp=pw(p/2);
    if(p&1) return ((tmp*tmp)%base*2)%base;
    return (tmp*tmp)%base;
}
inline void build_MST(int u){
    for(auto v:G[u]){
        if(v.first!=par[u]){
            par[v.first]=u;
            WG[v.first]=v.second;
            d[v.first]=d[u]+1;
            build_MST(v.first);
        }
    }
}
inline int go_up(int u,int v){
    if(d[u]<d[v]) swap(u,v);
    ll res=0;
    while(d[u]>d[v]) res=max(res,WG[u]),u=par[u];
    while(u!=v){
        res=max(res,WG[u]);u=par[u];
        res=max(res,WG[v]);v=par[v];
    }
    return res;
}

int main(){
   // freopen("E.inp","r",stdin);
    memset(p,-1,sizeof(p));
    read(n);read(m);
    read(X);
    for(int i=1;i<=m;i++){
        int u,v,w;
        read(u);read(v);read(w);
        adj[u].pb({v,w});
        adj[v].pb({u,w});
        edge[i]={u,v,w,i};
    }
    sort(edge+1,edge+m+1);
    ll spanning=0;
    for(int i=1;i<=m;i++){
        int pu=findroot(edge[i].u),pv=findroot(edge[i].v);
        if(pu==pv) continue;
        Union(pu,pv);
        spanning+=edge[i].w;
        mark[i]=true;
        G[edge[i].u].pb({edge[i].v,edge[i].w});
        G[edge[i].v].pb({edge[i].u,edge[i].w});
    }
    ll res=0;
    build_MST(1);
    if(spanning==X){
        res=(pw(n-1)-2)*pw(m-n+1)%base;
    }
    vector <ll> rem;
    for(int i=1;i<=m;i++){
        if(!mark[i]){
            ll u=edge[i].u,v=edge[i].v;
            ll mx=go_up(u,v);
            rem.pb(spanning-mx+edge[i].w);
 //           cout<<edge[i].u<<" "<<edge[i].v<<" "<<edge[i].id<<" "<<edge[i].w<<" ";
      //      cout<<spanning-mx+edge[i].w<<' ';
        }
   //     else cout<<"D: "<<edge[i].u<<" "<<edge[i].v<<" "<<edge[i].id<<" "<<edge[i].w<<'\n';
    }
    sort(rem.begin(),rem.end());
    //cout<<'\n';
    for(int i=0;i<rem.size();i++){
        if(rem[i]==X) //  that satisfy-spanning-tree must be the minimum weighted STree, so i+1->rem.size()-1 could be chosen arbitrary
        res=(res+(pw(m-n+1-i)))%base;
    }
    writeln(res);
}


Measured memory_bytes: 768