#include <bits/stdc++.h>

#define VARNAME(x) #x
#define show(x) cerr << #x << " = " << x << endl

using namespace std;
using ll = long long;
using ld = long double;

constexpr ll MOD = 1000000007LL;

template <typename T>
constexpr T INF = numeric_limits<T>::max() / 10;

class DisjointSets
{
public:
    DisjointSets(const int v) : parent(v), rank(v, 0) { iota(parent.begin(), parent.end(), 0); }
    bool same(const int a, const int b) { return find(a) == find(b); }
    int find(const int a) { return parent[a] == a ? a : parent[a] = find(parent[a]); }
    void unite(int a, int b)
    {
        a = find(a);
        b = find(b);
        if (a == b) {
            return;
        }
        if (rank[a] < rank[b]) {
            swap(a, b);
        }
        rank[a] += rank[b];
        parent[b] = a;
    }

private:
    vector<int> parent;
    vector<int> rank;
};

struct Edge
{
    bool operator<(const Edge& e) const
    {
        return cost < e.cost;
    }
    int from;
    int to;
    ll cost;
};

struct CostGraph
{
    using T = ll;
    CostGraph(const int v) : V{v}, edge(v), rev_edge(v) {}
    struct Edge
    {
        Edge(const int from, const int to, const T cost) : from{from}, to{to}, cost{cost} {}
        const int from;
        const int to;
        const T cost;
        bool operator<(const Edge& e) const { return cost != e.cost ? cost < e.cost : to < e.to; }
    };
    void addEdge(const int from, const int to, const T cost)
    {
        edge[from].push_back(Edge{from, to, cost});
        rev_edge[to].push_back(Edge(to, from, cost));
    }
    const int V;
    vector<vector<Edge>> edge;
    vector<vector<Edge>> rev_edge;
};

ll rec(const CostGraph& g, const int s, const int t, const ll mini, const int prev)
{
    if (s == t) {
        return mini;
    }
    ll ans = INF<ll>;
    for (const auto& e : g.edge[s]) {
        if (prev != e.to) {
            ans = min(ans, rec(g, e.to, t, min(mini, e.cost), s));
        }
    }
    return ans;
}
ll mincut(const CostGraph& g, const int s, const int t)
{
    return rec(g, s, t, INF<ll>, -1);
}

int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);
    int N, M;
    cin >> N >> M;
    ll X;
    cin >> X;
    DisjointSets uf(N);
    vector<Edge> edge(M);
    for (int i = 0; i < M; i++) {
        int u, v;
        cin >> u >> v;
        u--, v--;
        ll w;
        cin >> w;
        edge[i] = {u, v, w};
    }
    sort(edge.begin(), edge.end());
    int equal = 0;
    int white = 0;
    ll mst = 0;
    vector<int> color(M, -1);
    CostGraph g(N);
    for (int i = 0; i < M; i++) {
        const int u = edge[i].from;
        const int v = edge[i].to;
        const ll w = edge[i].cost;
        if (not uf.same(u, v)) {
            mst += w;
            uf.unite(u, v);
            g.addEdge(u, v, -w);
            g.addEdge(v, u, -w);
            color[i] = 0;
        }
    }
    for (int i = 0; i < M; i++) {
        if (color[i] == -1) {
            const int u = edge[i].from;
            const int v = edge[i].to;
            const ll w = edge[i].cost;
            const ll maxcut = -mincut(g, u, v);
            const ll next = mst - maxcut + w;
            if (next < X) {
                color[i] = 0;
            } else {
                white++;
                if (next == X) equal++;
            }
        }
    }
    vector<ll> power(M + 1, 1);
    for (int i = 1; i <= M; i++) {
        power[i] = power[i - 1] * 2 % MOD;
    }
    ll ans = (X == mst ? (power[N - 1] + MOD - 2) * power[M - N + 1] % MOD : 0);
    (ans += (2 * (power[equal] + MOD - 1) % MOD) * (power[white - equal]) % MOD) %= MOD;
    cout << ans << endl;
    return 0;
}


Measured memory_bytes: 512