#include <bits/stdc++.h>
using namespace std;
template <class T>
using vec = std::vector<T>;
template <class T>
using vec2d = std::vector<std::vector<T>>;
template <class T>
vec2d<T> makeVec2d(const int n1, const int n2, const T initValue) {
  return vec2d<T>(n1, vec<T>(n2, initValue));
}
bool __hack = std::ios::sync_with_stdio(false);
auto __hack1 = cin.tie(nullptr);
namespace template_util {
constexpr int bytecount(uint64_t x) { return x ? 1 + bytecount(x >> 8) : 0; }
template <int N>
struct bytetype {};
template <uint64_t N>
struct minimal_uint : bytetype<bytecount(N)> {};
}  // namespace template_util
template <class T>
T next(istream& in) {
  T ret;
  in >> ret;
  return ret;
}
template <class T>
struct Point {
  T x, y;
  Point(const T& x, const T& y) : x(x), y(y) {}
  void swap(Point& other) {
    ::swap(x, other.x);
    ::swap(y, other.y);
  }
};
template <class T>
void swap(Point<T>& p1, Point<T>& p2) {
  p1.swap(p2);
}
const int64_t MOD = (int64_t)1e9 + 7;
const int64_t INF = numeric_limits<int64_t>::max() / 4;
int getChange(const Point<int64_t>& v1, const Point<int64_t>& v2) {
  int64_t x = (v2.y - v1.y) / (v1.x - v2.x);
  if (x < 0) return 0;
  if (x >= 1000000001) return 1000000001;
  return (int)x;
}
int64_t getSum(const Point<int64_t>& v, int from, int to) {
  int64_t d = to - from + 1;
  int64_t res = (v.y * d) % MOD;
  if (res < 0) res += MOD;
  int64_t cur = (from + to) * d / 2;
  cur %= MOD;
  cur *= v.x;
  cur %= MOD;
  res += cur;
  if (res >= MOD) res -= MOD;
  return res;
}
void solve(istream& in, ostream& out) {
  auto n = next<int>(in);
  auto m = next<int>(in);
  auto q = next<int>(in);
  vec2d<pair<int, int64_t>> g(n);
  vec<int64_t> weightMax(n, 0);
  for (int i = 0; i < (m); ++i) {
    auto a = next<int>(in) - 1;
    auto b = next<int>(in) - 1;
    auto w = next<int64_t>(in);
    g[a].push_back({b, w});
    g[b].push_back({a, w});
    weightMax[a] = max(weightMax[a], w);
    weightMax[b] = max(weightMax[b], w);
  }
  vec2d<int64_t> dst = makeVec2d<int64_t>(n, m + 1, -INF);
  dst[0][0] = 0;
  for (int i = (1); i < (m + 1); ++i) {
    for (int v = 0; v < (n); ++v) {
      if (dst[v][i - 1] < 0) continue;
      for (auto top : g[v]) {
        auto to = top.first;
        auto w = top.second;
        dst[to][i] = max(dst[to][i], dst[v][i - 1] + w);
      }
    }
  }
  int64_t res = 0;
  for (int d = 0; d < (m + 1); ++d) {
    int64_t best = 0;
    for (int i = 0; i < (n); ++i) {
      if (dst[i][d] < 0) continue;
      best = max(best, dst[i][d]);
    }
    res += best;
    while (res >= MOD) res -= MOD;
  }
  vec<Point<int64_t>> points;
  for (int i = 0; i < (n); ++i) {
    if (dst[i][m] >= 0) {
      points.push_back(
          Point<int64_t>(weightMax[i], dst[i][m] - m * weightMax[i]));
    }
  }
  sort(points.begin(), points.end(),
       [](const Point<int64_t>& a, const Point<int64_t>& b) -> bool {
         return a.x < b.x || (a.x == b.x && a.y < b.y);
       });
  ;
  ;
  int from = m + 1;
  int ptr = 0;
  while (from <= q) {
    int upTo = q;
    if (ptr + 1 < points.size()) {
      if (points[ptr].x == points[ptr + 1].x) {
        ++ptr;
        continue;
      }
    }
    for (int i = (ptr + 1); i < (points.size()); ++i) {
      int ch = getChange(points[ptr], points[i]);
      if (upTo > ch) {
        upTo = ch;
      }
      upTo = min(upTo, ch);
    }
    if (upTo < from) {
      ++ptr;
      continue;
    }
    res += getSum(points[ptr], from, upTo);
    if (res >= MOD) res -= MOD;
    from = upTo + 1;
    ++ptr;
  }
  out << res << "\n";
}
int main() {
  solve(cin, cout);
  return 0;
}
