#include <bits/stdc++.h>
using namespace std;
mt19937_64 mt(time(0));
const int MAXN = 2000 + 10;
const int mod = 1e9 + 7;
const int inv2 = (mod + 1) / 2;
vector<pair<int, int> > edges[MAXN];
int dp[MAXN][MAXN], slope[MAXN];
struct Frac {
  long long x, y;
  Frac(long long x_, long long y_) : x(x_), y(y_) {
    assert(y != 0);
    if (y < 0) {
      x = -x;
      y = -y;
    }
  }
  bool operator<(const Frac& other) const {
    return (long double)x * other.y < (long double)y * other.x;
  }
};
int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  cout.precision(10);
  cout << fixed;
  int n, m, q;
  cin >> n >> m >> q;
  for (int i = 0; i < m; i++) {
    int u, v, w;
    cin >> u >> v >> w;
    edges[u].emplace_back(v, w);
    edges[v].emplace_back(u, w);
    slope[u] = max(slope[u], w);
    slope[v] = max(slope[v], w);
  }
  long long ret = 0;
  memset(dp, -1, sizeof(dp));
  dp[0][1] = 0;
  int path = 1;
  for (; path <= min(q, n - 1); path++) {
    int tmp = 0;
    for (int i = 1; i <= n; i++) {
      if (dp[path - 1][i] == -1) continue;
      dp[path][i] = max(dp[path][i], dp[path - 1][i] + slope[i]);
      tmp = max(tmp, dp[path][i]);
      for (pair<int, int> item : edges[i]) {
        dp[path][item.first] =
            max(dp[path][item.first], dp[path - 1][i] + item.second);
        tmp = max(tmp, dp[path][item.first]);
      }
    }
    ret = (ret + tmp) % mod;
  }
  q -= path - 1;
  if (q == 0) {
    cout << ret << '\n';
    return 0;
  }
  vector<pair<int, int> > cands;
  for (int i = 1; i <= n; i++) {
    cands.emplace_back(slope[i], dp[path - 1][i]);
  }
  sort(cands.begin(), cands.end(),
       [](const pair<int, int>& a, const pair<int, int>& b) {
         if (a.first != b.first) return a.first < b.first;
         return a.second > b.second;
       });
  cands.erase(unique(cands.begin(), cands.end(),
                     [](const pair<int, int>& a, const pair<int, int>& b) {
                       return a.first == b.first;
                     }),
              cands.end());
  deque<pair<int, int> > lines;
  deque<Frac> points;
  for (const pair<int, int>& cand : cands) {
    while (!points.empty()) {
      Frac point(lines.back().second - cand.second,
                 cand.first - lines.back().first);
      if (points.back() < point) break;
      points.pop_back();
      lines.pop_back();
    }
    lines.emplace_back(cand);
    if (lines.size() >= 2) {
      points.emplace_back(cand.second - lines[lines.size() - 2].second,
                          lines[lines.size() - 2].first - cand.first);
    }
  }
  long long cur = 1;
  while (cur <= q) {
    while (!points.empty()) {
      if (points.front() < Frac(cur, 1)) {
        points.pop_front();
        lines.pop_front();
      } else
        break;
    }
    long long end = q;
    if (!points.empty()) {
      long long tmp = points.front().x / points.front().y;
      end = min((long long)q, tmp);
    }
    long long a = lines.front().first * cur + lines.front().second;
    long long b = lines.front().first * end + lines.front().second;
    ret = ((a + b) % mod * (end - cur + 1) % mod * inv2 % mod + ret) % mod;
    cur = end + 1;
  }
  cout << ret << '\n';
  return 0;
}
