use std::io::*;
use std::str::FromStr;

#[allow(dead_code)]
fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

#[allow(dead_code)]
struct UnionFind {
    parent: Vec<i32>,
}

#[allow(dead_code)]
impl UnionFind {
    fn new(n: usize) -> UnionFind {
        UnionFind { parent: vec![-1; n] }
    }
    fn root(&mut self, x: usize) -> usize {
        let p = self.parent[x];
        return if p < 0 {
            x
        } else {
            self.parent[x] = self.root(p as usize) as i32;
            self.parent[x] as usize
        }
    }
    fn union_set(&mut self, x: usize, y: usize) -> bool {
        let mut x = self.root(x);
        let mut y = self.root(y);
        if x == y { return false; }
        if self.parent[y] < self.parent[x] { std::mem::swap(&mut x, &mut y); }
        self.parent[x] += self.parent[y];
        self.parent[y] = x as i32;
        true
    }
    fn find_set(&mut self, x: usize, y: usize) -> bool {
        self.root(x) == self.root(y)
    }
    fn size(&mut self, x: usize) -> usize {
        let r = self.root(x);
        -self.parent[r] as usize
    }
}


type Weight = i64;
#[allow(dead_code)]
#[derive(Clone, Debug, Eq, PartialEq)]
struct Edge {
    index: usize,
    src: usize,
    dest: usize,
    weight: Weight,
}
#[allow(dead_code)]
impl Edge {
    fn new(index: usize, src: usize, dest: usize, weight: Weight) -> Edge {
        Edge {
            index: index,
            src: src,
            dest: dest,
            weight: weight,
        }
    }
}
impl std::cmp::Ord for Edge {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        (self.weight, self.src, self.dest).cmp(&(other.weight, other.src, other.dest))
    }
}
impl std::cmp::PartialOrd for Edge {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}
type Edges = Vec<Edge>;
type Graph = Vec<Edges>;
#[allow(dead_code)]
fn graph_new(n: usize) -> Graph {
    vec![vec![]; n]
}
#[allow(dead_code)]
fn add_bi_edge(graph: &mut Graph, index: &mut usize, src: usize, dest: usize, weight: Weight) {
    graph[src].push(Edge::new(*index, src, dest, weight));
    graph[dest].push(Edge::new(*index, dest, src, weight));
    *index += 1;
}
#[allow(dead_code)]
fn add_uni_edge(graph: &mut Graph, index: &mut usize, src: usize, dest: usize, weight: Weight) {
    graph[src].push(Edge::new(*index, src, dest, weight));
    *index += 1;
}

const MOD: i64 = 1e+9 as i64 + 7;

fn calc(n: usize, m: usize, x: i64, edges: &mut Edges) -> i64 {
    edges.sort();
    let mut ufind = UnionFind::new(n);
    let mut min_weights = vec![vec![1e+15 as i64; n]; n];
    let mut min_plus = vec![0 as i64; m];
    let mut sum = 0;
    for edge in edges {
        if ufind.find_set(edge.src, edge.dest) {
            min_plus[edge.index] = edge.weight - min_weights[edge.src][edge.dest];
        } else {
            sum += edge.weight;
            let mut left = vec![];
            let mut right = vec![];
            for i in 0..n {
                if ufind.find_set(edge.src, i) { left.push(i); }
                if ufind.find_set(edge.dest, i) { right.push(i); }
            }
            for l in left.iter() {
                for r in right.iter() {
                    min_weights[*l][*r] = edge.weight;
                    min_weights[*r][*l] = edge.weight;
                }
            }
            ufind.union_set(edge.src, edge.dest);
        }
    }
    min_plus.sort();
    let mut ans = 1;
    if x == sum {
        let min_cnt = min_plus.iter().filter(|&v| *v == 0 ).count();
        let cnt = min_plus.iter().filter(|&v| *v > x - sum ).count();
        for _ in 0..min_cnt { ans = (ans * 2) % MOD; }
        ans = (ans - 2 + MOD) % MOD;
        for _ in 0..cnt { ans = (ans * 2) % MOD; }
    } else {
        let min_cnt = min_plus.iter().filter(|&v| *v == x - sum ).count();
        let cnt = min_plus.iter().filter(|&v| *v > x - sum ).count();
        for _ in 0..min_cnt { ans = (ans * 2) % MOD; }
        ans = (ans * 2 - 2 + MOD) % MOD;
        for _ in 0..cnt { ans = (ans * 2) % MOD; }
    }
    ans
}
fn main() {
    let n: usize = read();
    let m: usize = read();
    let x: i64 = read();
    let mut edges: Edges = vec![];
    let mut e = 0;
    for _ in 0..m {
        let mut f: usize = read();
        let mut t: usize = read();
        let w: i64 = read();
        f -= 1; t -= 1;
        edges.push(Edge::new(e, f, t, w));
        e += 1;
    }
    println!("{}", calc(n, m, x, &mut edges));
}

#[test]
fn hoge() {
    let n: usize = 4;
    let m: usize = 5;
    let x: i64 = 3;
    let mut edges: Edges = vec![];
    for i in 0..n {
        for j in i+1..n {
            if edges.len() == m { break; }
            let cnt = edges.len();
            let mut w = 1;
            if cnt == 3 { w = 3; }
            edges.push(Edge::new(cnt, i, j, w as i64));
        }
    }
    let ans = calc(n, m, x, &mut edges);
    println!("{}", ans);
}

Measured memory_bytes: 12540