#include <bits/stdc++.h>

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

#define sf scanf
#define pf printf
#define pb push_back
#define mp make_pair
#define PI ( acos(-1.0) )
#define mod 1000000007LL
#define IN freopen("C.in","r",stdin)
#define OUT freopen("output.txt","w",stdout)
#define FOR(i,a,b) for(i=a ; i<=b ; i++)
#define DBG pf("Hi\n")
#define INF 1000000000
#define i64 long long int
#define eps (1e-8)
#define xx first
#define yy second
#define ln 17
#define off 2

using namespace __gnu_pbds;
using namespace std ;

typedef tree< i64, null_type, less<i64>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;
typedef pair<i64, i64> pii;

#define maxn 2005

struct edge{
    int u , v , w , id ;
    bool operator<(const edge other)const{ return w < other.w ; }
};

vector <edge> e ;

namespace MST{
    int par[maxn] ;
    int findPar(int u)
    {
        if( par[u] != u ) return par[u] = findPar( par[u] ) ;
        return u ;
    }

    i64 findMST( int n , vector < edge > &e )
    {
        //after this function , e[0] to e[n-2] will contain the treeEdges
        //and other would be non-tree Edges

        sort( e.begin() , e.end() ) ;
        for(int i=1 ; i<=n ; i++) par[i] = i ;

        vector <edge> treeEdge , otherEdge ;

        i64 ans = 0 ;

        for(int i=0 ; i< e.size() ; i++ )
        {
            int u = e[i].u , v = e[i].v , w = e[i].w ;
            int pu = findPar(u) , pv = findPar(v) ;
            if( pu==pv ) otherEdge.pb(e[i]) ;
            else{
                ans += w ;
                par[pu] = pv ;
                treeEdge.pb(e[i]) ;
            }
        }
        e.clear() ;
        for(int i=0 ; i<treeEdge.size() ; i++) e.pb( treeEdge[i] ) ;
        for(int i=0 ; i<otherEdge.size() ; i++) e.pb( otherEdge[i] ) ;
        return ans ;
    }
}

vector <int> comp[1005] ;
int par[1005] ;

int findPar( int u  )
{
    if( par[u] == u ) return u ;
    return par[u] = findPar( par[u] ) ;
}

int Map[1005][1005] ;

int Merge(int u, int v , int w)
{
    int pu = findPar(u) , pv = findPar(v) ;
    if(pu==pv) return pu ;
    par[pv] = pu ;
    for(auto u:comp[pu])
    {
        for(auto v: comp[pv])
        {
            Map[ u ][ v ] = w ;
            Map[ v ][ u ] = w ;
        }
    }
    for( auto v : comp[pv] )
    {
        comp[pu].pb(v) ;
    }
    comp[pv].clear() ;
    return pu ;
}

int p[5005] ;

int main()
{
    int n , m ;

    scanf("%d %d",&n,&m) ;

    p[0] = 1 ;
    for(int i=1 ; i<=m ; i++) p[i] = (1LL*p[i-1]*2)%mod ;

    i64 x ;
    scanf("%lld",&x) ;

    for(int i=1; i<=m ; i++)
    {
        int u , v , w ;
        scanf("%d %d %d",&u,&v,&w) ;
        e.push_back( {u,v,w,i} ) ;
    }

    i64 mstCost = MST::findMST(n,e) ;

    if( mstCost > x )
    {
        printf("0\n") ;
        return 0 ;
    }

    sort( e.begin() , e.end() ) ;

    for(int i=1 ; i<=n ; i++)
    {
        par[i] = i ;
        comp[i].pb(i) ;
    }

    int treeEdge = 0 , other = 0 ;

    for(int i=0 ; i<m ; i++)
    {
        int l = i , r = i ;
        while( r+1 < m && e[r+1].w == e[r].w ) r++ ;
        i = r ;

        for(int j=l ; j<=r ; j++)
        {
            int u = e[j].u , v = e[j].v , w = e[j].w ;

            if( findPar(u) != findPar(v) ) treeEdge++ ;
            else{
                if( mstCost - Map[u][v] + w < x ) treeEdge++ ;
                else if(  mstCost - Map[u][v] + w == x ) other++ ;
            }
        }

        for(int j=l ; j<=r ; j++)
        {
            int u = e[j].u , v = e[j].v , w = e[j].w ;
            Merge(u,v,w) ;
        }
    }

   // printf("%lld %lld %d %d\n",mstCost,x,treeEdge,other) ;

    if( mstCost == x )
    {
        int ans = (p[m] - 2*p[ m - treeEdge ])%mod ;
        ans = (ans%mod + mod)%mod ;
        printf("%d\n",ans) ;
    }
    else{
        int ans = (1LL*2*( p[other] - 1 ))%mod ;
        ans = ( 1LL*ans*p[ m-treeEdge-other] )%mod ;
        ans = (ans%mod + mod)%mod ;
        printf("%d\n",ans) ;
    }

    return 0 ;
}


Measured memory_bytes: 5760