#include using i32 = std::int32_t; using u32 = std::uint32_t; using i64 = std::int64_t; using u64 = std::uint64_t; using i128 = __int128_t; using u128 = __uint128_t; using isize = std::ptrdiff_t; using usize = std::size_t; class rep { struct Iter { usize itr; constexpr Iter(const usize pos) noexcept : itr(pos) {} constexpr void operator++() noexcept { ++itr; } constexpr bool operator!=(const Iter& other) const noexcept { return itr != other.itr; } constexpr usize operator*() const noexcept { return itr; } }; const Iter first, last; public: explicit constexpr rep(const usize first, const usize last) noexcept : first(first), last(std::max(first, last)) {} constexpr Iter begin() const noexcept { return first; } constexpr Iter end() const noexcept { return last; } }; template struct RecLambda : private F { template explicit constexpr RecLambda(G&& g) : F(std::forward(g)) {} template constexpr decltype(auto) operator()(Args&&... args) const { return F::operator()(*this, std::forward(args)...); } }; template explicit RecLambda(G&&) -> RecLambda>; template bool setmin(T& lhs, const T& rhs) { if (lhs > rhs) { lhs = rhs; return true; } return false; } template bool setmax(T& lhs, const T& rhs) { if (lhs < rhs) { lhs = rhs; return true; } return false; } template constexpr T totient(T x) { T ret = x; for (T i = 2; i * i <= x; ++i) { if (x % i == 0) { ret /= i; ret *= i - 1; while (x % i == 0) x /= i; } } if (x > 1) { ret /= x; ret *= x - 1; } return ret; } template constexpr T rem_euclid(T value, const T& mod) { return (value %= mod) >= 0 ? value : value + mod; } template * = nullptr> class StaticModint { using Mint = StaticModint; static inline constexpr u32 PHI = totient(MOD); u32 v; public: static constexpr u32 mod() noexcept { return MOD; } template and std::is_integral_v>* = nullptr> static constexpr T normalize(const T x) noexcept { return rem_euclid>(x, MOD); } template and std::is_integral_v>* = nullptr> static constexpr T normalize(const T x) noexcept { return x % MOD; } constexpr StaticModint() noexcept : v(0) {} template constexpr StaticModint(const T x) noexcept : v(normalize(x)) {} template static constexpr Mint raw(const T x) noexcept { Mint ret; ret.v = x; return ret; } constexpr u32 get() const noexcept { return v; } constexpr Mint neg() const noexcept { return raw(v == 0 ? 0 : MOD - v); } constexpr Mint inv() const noexcept { return pow(PHI - 1); } constexpr Mint pow(u64 exp) const noexcept { Mint ret(1), mult(*this); for (; exp > 0; exp >>= 1) { if (exp & 1) ret *= mult; mult *= mult; } return ret; } constexpr Mint operator-() const noexcept { return neg(); } constexpr Mint operator~() const noexcept { return inv(); } constexpr Mint operator+(const Mint& rhs) const noexcept { return Mint(*this) += rhs; } constexpr Mint& operator+=(const Mint& rhs) noexcept { if ((v += rhs.v) >= MOD) v -= MOD; return *this; } constexpr Mint operator-(const Mint& rhs) const noexcept { return Mint(*this) -= rhs; } constexpr Mint& operator-=(const Mint& rhs) noexcept { if (v < rhs.v) v += MOD; v -= rhs.v; return *this; } constexpr Mint operator*(const Mint& rhs) const noexcept { return Mint(*this) *= rhs; } constexpr Mint& operator*=(const Mint& rhs) noexcept { v = (u64)v * rhs.v % MOD; return *this; } constexpr Mint operator/(const Mint& rhs) const noexcept { return Mint(*this) /= rhs; } constexpr Mint& operator/=(const Mint& rhs) noexcept { return *this *= rhs.inv(); } constexpr bool operator==(const Mint& rhs) const noexcept { return v == rhs.v; } constexpr bool operator!=(const Mint& rhs) const noexcept { return v != rhs.v; } friend std::ostream& operator<<(std::ostream& stream, const Mint& rhs) { return stream << rhs.v; } }; using Modint1000000007 = StaticModint<1000000007>; using Modint998244353 = StaticModint<998244353>; template using Vec = std::vector; using Fp = Modint1000000007; void D_main() { usize N, M; i64 K; std::cin >> N >> M >> K; Vec>> graph(N); for (const auto i : rep(0, M)) { usize x, y; i64 z; std::cin >> x >> y >> z; x -= 1; y -= 1; graph[x].emplace_back(y, z); graph[y].emplace_back(x, z); } const auto solve = [&](const i64 Max) { Vec A(N), B(N); // A[i] * x + B[i] Vec seen; Vec> edge; seen.reserve(N); edge.reserve(M); const auto dfs = RecLambda([&](auto&& dfs, const usize u) -> void { seen.push_back(u); for (const auto [v, s] : graph[u]) { edge.emplace_back(u, v, s); if (A[v] == 0) { A[v] = -A[u]; B[v] = s - B[u]; dfs(v); } } }); Fp ret = 1; for (const auto src : rep(0, N)) { if (A[src] != 0) { continue; } A[src] = 1; dfs(src); ret *= [&] { std::optional val; for (const auto [u, v, s] : edge) { if (A[u] == A[v]) { if ((s - B[u] - B[v]) % 2 != 0) { return Fp(0); } val = (s - B[u] - B[v]) / (A[u] + A[v]); } else { if (B[u] + B[v] != s) { return Fp(0); } } } if (val) { const auto x = val.value(); for (const auto u : seen) { const auto y = A[u] * x + B[u]; if (!(1 <= y and y <= Max)) { return Fp(0); } } for (const auto [u, v, s] : edge) { if (A[u] * x + B[u] + A[v] * x + B[v] != s) { return Fp(0); } } return Fp(1); } i64 low = 1, high = Max; for (const auto u : seen) { if (A[u] == 1) { setmin(high, Max - B[u]); setmax(low, 1 - B[u]); } else { setmin(high, -(1 - B[u])); setmax(low, -(Max - B[u])); } } return Fp(std::max(high - low + 1, 0)); }(); seen.clear(); edge.clear(); } return ret; }; std::cout << solve(K) - solve(K - 1) << '\n'; } int main() { std::ios_base::sync_with_stdio(false); std::cin.tie(nullptr); D_main(); return 0; }