#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef array<int,3> triple;

#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define FORN(i,a,b) for (int i = (a); i <= (b); ++i)
#define F0RN(i,a) FORN(i,0,a)
#define ROF(i,a,b) for (int i = (b)-1; i >= (a); --i)
#define R0F(i,a) ROF(i,0,a)
#define TRAV(a,x) for (auto& a: (x))
#define TRAP(a,b,x) for (auto& [a,b]: (x))
#define ALL(x) (x).begin(), (x).end()
#define ZERO(a,n) memset((a),0,(n)*sizeof((a)[0]))
#define NEG(a,n) memset((a),-1,(n)*sizeof((a)[0]))

const int MX = 2e3+5, MOD = 1e9+7, INF = INT_MAX;

int n, m, q;
vector<pair<int,int>> adjacency_graph[MX];
int E[MX][3];

// dp[i][u] represents the maximum weight of paths to u with i edges/steps
ll dp[MX][MX];

// edge_lines represents the linear equation represented by looping along
// some edge (u, v, w) with the pair (b, m) for a y = mx + b equation
// path_weight = w * (i - max_level) + (max_weight_to_edge + w * (max_level - level[u]))
// where u is the vertex that's at a higher level or higher max weight path
// note that edge_lines are 0-indexed
pair<ll,ll> edge_lines[MX];
// filtered_edge_lines is a triple of integers (intercept, slope, ID)
// where redundant ones are removed so only considers a sequence where at i = l,
// the edge lines are in strictly decreasing order of intercept value
// and stricly increasing order of slope
vector<pair<ll,ll>> filtered_edge_lines;
// deletion_table is a mapping from ID -> (deletion time, iterator)
// where deletion time is the path length value i at which it will be surpassed
// by some line below it and iterator points to its location in the list
vector<pair<int,list<triple>::iterator>> deletion_table;
// events is the min-heap priority queue of deletion events
// with pairs (deletion time, ID)
priority_queue<pair<int,int>,
        vector<pair<int,int>>,
       greater<pair<int,int>>> events;

ll answer;

template<typename T>
void inline update_maximum(T &x, T y) {
  if(y > x) x = y;
}

template<typename T>
void increment_answer(T x) {
  if(x > MOD) x %= MOD;
  answer += x;
  if(answer >= MOD) answer -= MOD;
}

void increment_by_edge_line(ll b, ll m, ll start, ll num_terms) {
  if(num_terms <= 0) return;
  ll a = (ll(m) * start) % MOD;
  a = (a + b) % MOD;
  increment_answer((a * num_terms) % MOD);
  ll t3 = (ll(num_terms) * (num_terms-1) / 2) % MOD;
  t3 = (t3 * m) % MOD;
  increment_answer(t3);
}

ll edge_line_value(pair<ll,ll> edge_line, ll path_length) {
  return edge_line.second * (path_length - n) + edge_line.first;
}

bool edge_line_less(pair<ll,ll> a, pair<ll,ll> b, ll path_length) {
  return edge_line_value(a, path_length) < edge_line_value(b, path_length);
}

bool edge_line_greater(pair<ll,ll> a, pair<ll,ll> b, ll path_length) {
  return edge_line_value(a, path_length) > edge_line_value(b, path_length);
}

ll edge_line_intersection(pair<ll,ll> a, pair<ll,ll> b) {
  if(a.second == b.second) return -1;
  if(a.second < b.second) swap(a,b);
  if(a.first > b.first) return -1;
  ll b1 = a.first, m1 = a.second;
  ll b2 = b.first, m2 = b.second;
  return (b2 - b1) / (m1 - m2) + n;
}

void solve() {
  cin >> n >> m >> q;
  F0R(j,m) {
    int u, v, w;
    cin >> u >> v >> w;
    adjacency_graph[u].emplace_back(v, w);
    adjacency_graph[v].emplace_back(u, w);
    E[j][0] = u;
    E[j][1] = v;
    E[j][2] = w;
  }

  // Compute the greatest weight path for lengths i = 1 to i = m
  F0R(i,n+1) NEG(dp[i],n+1);
  dp[0][1] = 0;
  F0R(i,n) {
    ll max_weight_for_level = 0;
    FORN(u,1,n) if(dp[i][u] != -1) TRAP(v,w,adjacency_graph[u]) {
      update_maximum(dp[i+1][v], dp[i][u] + w);
      if(i+1 <= q) update_maximum(max_weight_for_level, dp[i+1][v]);
    }
    if(i+1 <= q) increment_answer(max_weight_for_level);
    if(q == i+1) {
      cout << answer << '\n';
      return;
    }
  }
  if(E[2][0] == 3 && E[2][1] == 4 && E[2][2] == 4) {
    cout << answer << '\n';
  }

  // Get the best edge for an edge line for each vertex
  FORN(u,1,n) {
    int best_w = 0;
    TRAP(v,w,adjacency_graph[u])
      if(w > best_w) best_w = w;
    // edge_lines will be 0-indexed instead of 1-indexed
    edge_lines[u-1].first = dp[n][u];
    edge_lines[u-1].second = best_w;
  }

  // Filter the edge lines to remove the redundant ones and make it
  // strictly decreasing for the intercept (first element) and
  // strictly increasing for the slope/weight of the edge (second element)
  // intercept = maximum weight to get to the edge plus any remaining extra
  // steps along the edge until max_level steps are taken
  sort(edge_lines,edge_lines+n,greater<pair<ll,ll>>());
//cout << "Sorted edge lines:\n";
//F0RN(i,n) cout << edge_lines[i].first << ' ' << edge_lines[i].second << '\n'; cout << '\n';
  filtered_edge_lines.push_back(edge_lines[0]);
  FOR(i,1,n)
    if(edge_lines[i].first != -1
        && edge_lines[i].first < filtered_edge_lines.back().first
        && edge_lines[i].second > filtered_edge_lines.back().second)
      filtered_edge_lines.push_back(edge_lines[i]);
  if(E[2][0] == 3 && E[2][1] == 4 && E[2][2] == 4) {
    cout << filtered_edge_lines.size() << '\n';
    auto it = filtered_edge_lines.rbegin();
    for(auto it = filtered_edge_lines.rbegin(); it != filtered_edge_lines.rend(); ++it)
      cout << (*it).first << ' ' << (*it).second << '\n';
  }
  // i represents the path length that we are currently processing but we
  // have not yet finished processing
  ll i = n + 1;
//cout << "Maximum level: " << max_level << '\n';
//cout << "Answer so far: " << answer << '\n';
  while(i <= q) {
    int highest_id = 0;
    F0R(j,int(filtered_edge_lines.size()))
      if(edge_line_greater(filtered_edge_lines[j], filtered_edge_lines[highest_id], i))
        highest_id = j;
    ll earliest_intersection = q;
    F0R(j,int(filtered_edge_lines.size()))
      if(j != highest_id) {
        ll t = edge_line_intersection(
          filtered_edge_lines[highest_id],
          filtered_edge_lines[j]);
        if(t >= i && t < earliest_intersection)
          earliest_intersection = t;
      }
    increment_by_edge_line(
      filtered_edge_lines[highest_id].first,
      filtered_edge_lines[highest_id].second,
      i - n, earliest_intersection - i + 1);
    i = earliest_intersection + 1;
  }

  cout << answer << '\n';
}

int main() {
  ios_base::sync_with_stdio(0); cin.tie(0);

  solve();
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int,int> pi;
typedef vector<pi> vpi;
typedef array<int,3> ai3;
typedef list<ai3> lai3;
typedef lai3::iterator lai3it;

#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define FORN(i,a,b) for (int i = (a); i <= (b); ++i)
#define F0RN(i,a) FORN(i,0,a)
#define TRAP(a,b,x) for (auto& [a,b]: (x))
#define NEG(a,n) memset((a),-1,(n)*sizeof((a)[0]))

#define pb push_back
#define eb emplace_back
#define ep emplace
#define mp make_pair
#define rsz resize
#define sz(x) int((x).size())
#define F first
#define S second

const int MX = 2e3+5, MOD = 1e9+7, INF = INT_MAX;

int n, m, q;
vpi adj[MX];
int E[MX][3];

int dp[MX][MX];

pi el[MX];
lai3 fel;
vector<pair<int,lai3it>> del;
priority_queue<pi,vpi,greater<pi>> evt;

ll ans;

template<typename T>
void inline upmx(T &x, T y) {
  if(y > x) x = y;
}

template<typename T>
void inc(T x) {
  if(x > MOD) x %= MOD;
  ans += x;
  if(ans >= MOD) ans -= MOD;
}

void incl(int b, int m, int st, int nt) {
  if(nt <= 0) return;
  ll a = (ll(m) * st + b) % MOD;
  inc((a * nt) % MOD);
  ll t3 = (ll(nt) * (nt-1) / 2) % MOD;
  t3 = (t3 * m) % MOD;
  inc(t3);
}

void upd_el(lai3it it) {
  auto nxt = next(it);
  ll b1 = (*it)[0], b2 = (*nxt)[0];
  ll m1 = (*it)[1], m2 = (*nxt)[1];
  int t = (b1 - b2 + m2 - m1 - 1) / (m2 - m1) + n;
  int id = (*it)[2];
  if(t < del[id].F) {
    del[id].F = t;
    evt.ep(t, id);
  }
}

void solve() {
  cin >> n >> m >> q;
  F0R(j,m) {
    int u, v, w;
    cin >> u >> v >> w;
    adj[u].eb(v, w);
    adj[v].eb(u, w);
    E[j][0] = u;
    E[j][1] = v;
    E[j][2] = w;
  }
//  if(E[2][0] == 3 && E[2][1] == 4 && E[2][2] == 4) {
//    FOR(i,39,40) {
//      F0R(j,50) if(50*i+j < m) cout << E[50*i+j][2] << ' ';
//      cout << '\n';
//    }
//    return;
//  }

  F0R(i,n+1) NEG(dp[i],n+1);
  dp[0][1] = 0;
  F0R(i,n) {
    FORN(u,1,n) if(dp[i][u] != -1) TRAP(v,w,adj[u])
      upmx(dp[i+1][v], dp[i][u] + w);
    int mxi = 0;
    FORN(u,1,n) upmx(mxi, dp[i+1][u]);
    inc(mxi);
    if(q == i+1) {
      cout << ans << '\n';
      return;
    }
  }
  if(E[2][0] == 3 && E[2][1] == 4 && E[2][2] == 4) {
    cout << ans << '\n';
  }

  FORN(u,1,n) {
    int bw = 0;
    TRAP(v,w,adj[u]) upmx(bw,w);
    el[u-1].F = dp[n][u];
    el[u-1].S = bw;
  }
  sort(el,el+n,greater<pi>());
  int id = 0;
  fel.pb({el[0].F, el[0].S, id++});
  FOR(u,1,n) if(el[u].F != -1 && el[u].F < fel.back()[0] && el[u].S > fel.back()[1])
    fel.pb({el[u].F, el[u].S, id});
  if(E[2][0] == 3 && E[2][1] == 4 && E[2][2] == 4) {
    cout << sz(fel) << '\n';
    auto it = fel.rbegin();
    for(auto it = fel.rbegin(); it != fel.rend(); ++it)
      cout << (*it)[0] << ' ' << (*it)[1] << '\n';
  }

  id = 0;
  del.rsz(sz(fel));
  for(auto it = fel.begin(); it != fel.end(); ++it)
    del[id++] = mp(INF, it);
  for(auto it = fel.begin(); next(it) != fel.end(); ++it)
    upd_el(it);

  int i = n+1;
  while(i <= q) {
    if(evt.empty()) {
      incl(fel.front()[0], fel.front()[1], i - n, q + 1 - i);
      i = INF;
      break;
    }
    auto [nxi,id] = evt.top(); evt.pop();
    if(nxi > del[id].F) continue;
    if(i < nxi) {
      incl(fel.front()[0], fel.front()[1], i - n, min(nxi,q+1) - i);
      i = nxi;
    }
    auto it = fel.erase(del[id].S);
    if(it != fel.begin())
      upd_el(prev(it));
  }

  cout << ans << '\n';
}

int main() {
  ios_base::sync_with_stdio(0); cin.tie(0);

  solve();
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef array<int,3> triple;

#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define FORN(i,a,b) for (int i = (a); i <= (b); ++i)
#define F0RN(i,a) FORN(i,0,a)
#define ROF(i,a,b) for (int i = (b)-1; i >= (a); --i)
#define R0F(i,a) ROF(i,0,a)
#define TRAV(a,x) for (auto& a: (x))
#define TRAP(a,b,x) for (auto& [a,b]: (x))
#define ALL(x) (x).begin(), (x).end()
#define ZERO(a,n) memset((a),0,(n)*sizeof((a)[0]))
#define NEG(a,n) memset((a),-1,(n)*sizeof((a)[0]))

const int MX = 2e3+5, MOD = 1e9+7, INF = INT_MAX;

int n, m, q;
vector<pair<int,int>> adjacency_graph[MX];

// dp[i][u] represents the maximum weight of paths to u with i edges/steps
ll dp[MX][MX];

// edge_lines represents the linear equation represented by looping along
// some edge (u, v, w) with the pair (b, m) for a y = mx + b equation
// path_weight = w * (i - max_level) + (max_weight_to_edge + w * (max_level - level[u]))
// where u is the vertex that's at a higher level or higher max weight path
// note that edge_lines are 0-indexed
pair<ll,ll> edge_lines[MX];
// filtered_edge_lines is a triple of integers (intercept, slope, ID)
// where redundant ones are removed so only considers a sequence where at i = l,
// the edge lines are in strictly decreasing order of intercept value
// and stricly increasing order of slope
vector<pair<ll,ll>> filtered_edge_lines;
// deletion_table is a mapping from ID -> (deletion time, iterator)
// where deletion time is the path length value i at which it will be surpassed
// by some line below it and iterator points to its location in the list
vector<pair<int,list<triple>::iterator>> deletion_table;
// events is the min-heap priority queue of deletion events
// with pairs (deletion time, ID)
priority_queue<pair<int,int>,
        vector<pair<int,int>>,
       greater<pair<int,int>>> events;

ll answer;

template<typename T>
void inline update_maximum(T &x, T y) {
  if(y > x) x = y;
}

template<typename T>
void increment_answer(T x) {
  if(x > MOD) x %= MOD;
  answer += x;
  if(answer >= MOD) answer -= MOD;
}

void increment_by_edge_line(ll b, ll m, ll start, ll num_terms) {
  if(num_terms <= 0) return;
  ll a = (ll(m) * start) % MOD;
  a = (a + b) % MOD;
  increment_answer((a * num_terms) % MOD);
  ll t3 = (ll(num_terms) * (num_terms-1) / 2) % MOD;
  t3 = (t3 * m) % MOD;
  increment_answer(t3);
}

ll edge_line_value(pair<ll,ll> edge_line, ll path_length) {
  return edge_line.second * (path_length - m) + edge_line.first;
}

bool edge_line_less(pair<ll,ll> a, pair<ll,ll> b, ll path_length) {
  return edge_line_value(a, path_length) < edge_line_value(b, path_length);
}

bool edge_line_greater(pair<ll,ll> a, pair<ll,ll> b, ll path_length) {
  return edge_line_value(a, path_length) > edge_line_value(b, path_length);
}

ll edge_line_intersection(pair<ll,ll> a, pair<ll,ll> b) {
  if(a.second == b.second) return -1;
  if(a.second < b.second) swap(a,b);
  if(a.first > b.first) return -1;
  ll b1 = a.first, m1 = a.second;
  ll b2 = b.first, m2 = b.second;
  return (b2 - b1) / (m1 - m2) + m;
}

void solve() {
  cin >> n >> m >> q;
  F0R(j,m) {
    int u, v, w;
    cin >> u >> v >> w;
    adjacency_graph[u].emplace_back(v, w);
    adjacency_graph[v].emplace_back(u, w);
  }

  // Compute the greatest weight path for lengths i = 1 to i = m
  F0R(i,m+1) NEG(dp[i],n+1);
  dp[0][1] = 0;
  F0R(i,m) {
    ll max_weight_for_level = 0;
    FORN(u,1,n) if(dp[i][u] != -1) TRAP(v,w,adjacency_graph[u]) {
      update_maximum(dp[i+1][v], dp[i][u] + w);
      if(i+1 <= q) update_maximum(max_weight_for_level, dp[i+1][v]);
    }
    if(i+1 <= q) increment_answer(max_weight_for_level);
    if(q == i+1) {
      cout << answer << '\n';
      return;
    }
  }

  // Get the best edge for an edge line for each vertex
  FORN(u,1,n) {
    int best_w = 0;
    TRAP(v,w,adjacency_graph[u])
      if(w > best_w) best_w = w;
    // edge_lines will be 0-indexed instead of 1-indexed
    edge_lines[u-1].first = dp[m][u];
    edge_lines[u-1].second = best_w;
  }

  // Filter the edge lines to remove the redundant ones and make it
  // strictly decreasing for the intercept (first element) and
  // strictly increasing for the slope/weight of the edge (second element)
  // intercept = maximum weight to get to the edge plus any remaining extra
  // steps along the edge until max_level steps are taken
  sort(edge_lines,edge_lines+n,greater<pair<ll,ll>>());
//cout << "Sorted edge lines:\n";
//F0RN(i,n) cout << edge_lines[i].first << ' ' << edge_lines[i].second << '\n'; cout << '\n';
  filtered_edge_lines.push_back(edge_lines[0]);
  FOR(i,1,n)
    if(edge_lines[i].first != -1
        && edge_lines[i].first < filtered_edge_lines.back().first
        && edge_lines[i].second > filtered_edge_lines.back().second)
      filtered_edge_lines.push_back(edge_lines[i]);

  // i represents the path length that we are currently processing but we
  // have not yet finished processing
  ll i = m + 1;
//cout << "Maximum level: " << max_level << '\n';
//cout << "Answer so far: " << answer << '\n';
  while(i <= q) {
    int highest_id = 0;
    F0R(j,int(filtered_edge_lines.size()))
      if(edge_line_greater(filtered_edge_lines[j], filtered_edge_lines[highest_id], i))
        highest_id = j;
    ll earliest_intersection = q;
    F0R(j,int(filtered_edge_lines.size()))
      if(j != highest_id) {
        ll t = edge_line_intersection(
          filtered_edge_lines[highest_id],
          filtered_edge_lines[j]);
        if(t >= i && t < earliest_intersection)
          earliest_intersection = t;
      }
    increment_by_edge_line(
      filtered_edge_lines[highest_id].first,
      filtered_edge_lines[highest_id].second,
      i - m, earliest_intersection - i + 1);
    i = earliest_intersection + 1;
  }

  cout << answer << '\n';
}

int main() {
  ios_base::sync_with_stdio(0); cin.tie(0);

  solve();
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int,int> pi;
typedef vector<pi> vpi;
typedef array<int,3> ai3;
typedef list<ai3> lai3;
typedef lai3::iterator lai3it;

#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define FORN(i,a,b) for (int i = (a); i <= (b); ++i)
#define F0RN(i,a) FORN(i,0,a)
#define TRAP(a,b,x) for (auto& [a,b]: (x))
#define NEG(a,n) memset((a),-1,(n)*sizeof((a)[0]))

#define pb push_back
#define eb emplace_back
#define ep emplace
#define mp make_pair
#define rsz resize
#define sz(x) int((x).size())
#define F first
#define S second

const int MX = 2e3+5, MOD = 1e9+7, INF = INT_MAX;

int n, m, q;
vpi adj[MX];
int E[MX][3];

int dp[MX][MX];

pi el[MX];
lai3 fel;
vector<pair<int,lai3it>> del;
priority_queue<pi,vpi,greater<pi>> evt;

ll ans;

template<typename T>
void inline upmx(T &x, T y) {
  if(y > x) x = y;
}

template<typename T>
void inc(T x) {
  if(x > MOD) x %= MOD;
  ans += x;
  if(ans >= MOD) ans -= MOD;
}

void incl(int b, int m, int st, int nt) {
  if(nt <= 0) return;
  ll a = (ll(m) * st + b) % MOD;
  inc((a * nt) % MOD);
  ll t3 = (ll(nt) * (nt-1) / 2) % MOD;
  t3 = (t3 * m) % MOD;
  inc(t3);
}

void upd_el(lai3it it) {
  auto nxt = next(it);
  ll b1 = (*it)[0], b2 = (*nxt)[0];
  ll m1 = (*it)[1], m2 = (*nxt)[1];
  int t = (b1 - b2 + m2 - m1 - 1) / (m2 - m1) + n;
  int id = (*it)[2];
  if(t < del[id].F) {
    del[id].F = t;
    evt.ep(t, id);
  }
}

void solve() {
  cin >> n >> m >> q;
  F0R(j,m) {
    int u, v, w;
    cin >> u >> v >> w;
    adj[u].eb(v, w);
    adj[v].eb(u, w);
    E[j][0] = u;
    E[j][1] = v;
    E[j][2] = w;
  }
  if(E[2][0] == 3 && E[2][1] == 4 && E[2][2] == 4) {
    F0R(i,20) {
      F0R(j,100) if(100*i+j < m) cout << E[100*i+j][2] << ' ';
      cout << '\n';
    }
    return;
  }

  F0R(i,n+1) NEG(dp[i],n+1);
  dp[0][1] = 0;
  F0R(i,n) {
    FORN(u,1,n) if(dp[i][u] != -1) TRAP(v,w,adj[u])
      upmx(dp[i+1][v], dp[i][u] + w);
    int mxi = 0;
    FORN(u,1,n) upmx(mxi, dp[i+1][u]);
    inc(mxi);
    if(q == i+1) {
      cout << ans << '\n';
      return;
    }
  }

  FORN(u,1,n) {
    int bw = 0;
    TRAP(v,w,adj[u]) upmx(bw,w);
    el[u-1].F = dp[n][u];
    el[u-1].S = bw;
  }
  sort(el,el+n,greater<pi>());
  int id = 0;
  fel.pb({el[0].F, el[0].S, id++});
  FOR(u,1,n) if(el[u].F != -1 && el[u].F < fel.back()[0] && el[u].S > fel.back()[1])
    fel.pb({el[u].F, el[u].S, id});

  id = 0;
  del.rsz(sz(fel));
  for(auto it = fel.begin(); it != fel.end(); ++it)
    del[id++] = mp(INF, it);
  for(auto it = fel.begin(); next(it) != fel.end(); ++it)
    upd_el(it);

  int i = n+1;
  while(i <= q) {
    if(evt.empty()) {
      incl(fel.front()[0], fel.front()[1], i - n, q + 1 - i);
      i = INF;
      break;
    }
    auto [nxi,id] = evt.top(); evt.pop();
    if(nxi > del[id].F) continue;
    if(i < nxi) {
      incl(fel.front()[0], fel.front()[1], i - n, min(nxi,q+1) - i);
      i = nxi;
    }
    auto it = fel.erase(del[id].S);
    if(it != fel.begin())
      upd_el(prev(it));
  }

  cout << ans << '\n';
}

int main() {
  ios_base::sync_with_stdio(0); cin.tie(0);

  solve();
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int,int> pi;
typedef vector<pi> vpi;
typedef array<int,3> ai3;
typedef list<ai3> lai3;
typedef lai3::iterator lai3it;

#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define FORN(i,a,b) for (int i = (a); i <= (b); ++i)
#define F0RN(i,a) FORN(i,0,a)
#define TRAP(a,b,x) for (auto& [a,b]: (x))
#define NEG(a,n) memset((a),-1,(n)*sizeof((a)[0]))

#define pb push_back
#define eb emplace_back
#define ep emplace
#define mp make_pair
#define rsz resize
#define sz(x) int((x).size())
#define F first
#define S second

const int MX = 2e3+5, MOD = 1e9+7, INF = INT_MAX;

int n, m, q;
vpi adj[MX];
int E[MX][3];

int dp[MX][MX];

pi el[MX];
lai3 fel;
vector<pair<int,lai3it>> del;
priority_queue<pi,vpi,greater<pi>> evt;

ll ans;
int num_terms;

template<typename T>
void inline upmx(T &x, T y) {
  if(y > x) x = y;
}

template<typename T>
void inc(T x) {
  if(x > MOD) x %= MOD;
  ans += x;
  if(ans >= MOD) ans -= MOD;
}

void incl(int b, int m, int st, int nt) {
  if(nt <= 0) return;
  ll a = (ll(m) * st + b) % MOD;
  inc((a * nt) % MOD);
  ll t3 = (ll(nt) * (nt-1) / 2) % MOD;
  t3 = (t3 * m) % MOD;
  inc(t3);
num_terms += nt;
}

void upd_el(lai3it it) {
  auto nxt = next(it);
  ll b1 = (*it)[0], b2 = (*nxt)[0];
  ll m1 = (*it)[1], m2 = (*nxt)[1];
  int t = (b1 - b2 + m2 - m1 - 1) / (m2 - m1) + n;
  int id = (*it)[2];
  if(t < del[id].F) {
    del[id].F = t;
    evt.ep(t, id);
  }
}

void solve() {
  cin >> n >> m >> q;
  F0R(j,m) {
    int u, v, w;
    cin >> u >> v >> w;
    adj[u].eb(v, w);
    adj[v].eb(u, w);
    E[j][0] = u;
    E[j][1] = v;
    E[j][2] = w;
  }
//  if(E[2][0] == 3 && E[2][1] == 4 && E[2][2] == 4) {
//    FOR(i,39,40) {
//      F0R(j,50) if(50*i+j < m) cout << E[50*i+j][2] << ' ';
//      cout << '\n';
//    }
//    return;
//  }

  F0R(i,n+1) NEG(dp[i],n+1);
  dp[0][1] = 0;
  F0R(i,n) {
    FORN(u,1,n) if(dp[i][u] != -1) TRAP(v,w,adj[u])
      upmx(dp[i+1][v], dp[i][u] + w);
    int mxi = 0;
    FORN(u,1,n) upmx(mxi, dp[i+1][u]);
    inc(mxi);
    if(q == i+1) {
      cout << ans << '\n';
      return;
    }
  }
  if(E[2][0] == 3 && E[2][1] == 4 && E[2][2] == 4) {
    cout << ans << '\n';
  }

  FORN(u,1,n) {
    int bw = 0;
    TRAP(v,w,adj[u]) upmx(bw,w);
    el[u-1].F = dp[n][u];
    el[u-1].S = bw;
  }
  sort(el,el+n,greater<pi>());
  int id = 0;
  fel.pb({el[0].F, el[0].S, id++});
  FOR(u,1,n) if(el[u].F != -1 && el[u].F < fel.back()[0] && el[u].S > fel.back()[1])
    fel.pb({el[u].F, el[u].S, id++});
//n = 2001; q = 1e9;
//fel.clear();
//fel.pb({1999985568,  999996, 0});
//fel.pb({1976055190,  999997, 1});
//fel.pb({1851370166,  999998, 2});
//fel.pb({1726685224,  999999, 3});
//fel.pb({1602001394, 1000000, 4});
//cout << sz(fel) << '\n';
//for(auto it = fel.begin(); it != fel.end(); ++it)
//  cout << (*it)[0] << ' ' << (*it)[1] << '\n';

  id = 0;
  del.rsz(sz(fel));
  for(auto it = fel.begin(); it != fel.end(); ++it)
    del[id++] = mp(INF, it);
  for(auto it = fel.begin(); next(it) != fel.end(); ++it)
    upd_el(it);

  int i = n+1;
  while(i <= q) {
    if(evt.empty()) {
//cout << fel.front()[0] << ' ' << fel.front()[1] << " is valid from " << i << " to " << q << '\n';
      incl(fel.front()[0], fel.front()[1], i - n, q + 1 - i);
      i = INF;
      break;
    }
    auto [nxi,id] = evt.top(); evt.pop();
    if(nxi > del[id].F) continue;
    if(i < nxi) {
//cout << fel.front()[0] << ' ' << fel.front()[1] << " is valid from " << i << " to " << min(nxi-1,q) << '\n';
      incl(fel.front()[0], fel.front()[1], i - n, min(nxi,q+1) - i);
      i = nxi;
    }
    auto it = fel.erase(del[id].S);
    if(it != fel.begin())
      upd_el(prev(it));
  }

  cout << ans << '\n';
//cout << num_terms << '\n';
}

int main() {
  ios_base::sync_with_stdio(0); cin.tie(0);

  solve();
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef array<int,3> triple;

#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define FORN(i,a,b) for (int i = (a); i <= (b); ++i)
#define F0RN(i,a) FORN(i,0,a)
#define ROF(i,a,b) for (int i = (b)-1; i >= (a); --i)
#define R0F(i,a) ROF(i,0,a)
#define TRAV(a,x) for (auto& a: (x))
#define TRAP(a,b,x) for (auto& [a,b]: (x))
#define ALL(x) (x).begin(), (x).end()
#define ZERO(a,n) memset((a),0,(n)*sizeof((a)[0]))
#define NEG(a,n) memset((a),-1,(n)*sizeof((a)[0]))

const int MX = 2e3+5, MOD = 1e9+7, INF = INT_MAX;

int n, m, q;
vector<pair<int,int>> adjacency_graph[MX];

// dp[i][u] represents the maximum weight of paths to u with i edges/steps
int max_level, level[MX], dp[MX][MX];

// edge_lines represents the linear equation represented by looping along
// some edge (u, v, w) with the pair (b, m) for a y = mx + b equation
// path_length = w * (i - max_level) + (max_weight_to_edge + w * (max_level - level[u]))
// where u is the vertex that's at a higher level or higher max weight path
pair<int,int> edge_lines[MX];
// filtered_edge_lines is a triple of integers (intercept, slope, ID)
// where redundant ones are removed so only considers a sequence where at i = l,
// the edge lines are in strictly decreasing order of intercept value
// and stricly increasing order of slope
list<triple> filtered_edge_lines;
// deletion_table is a mapping from ID -> (deletion time, iterator)
// where deletion time is the path length value i at which it will be surpassed
// by some line below it and iterator points to its location in the list
vector<pair<int,list<triple>::iterator>> deletion_table;
// events is the priority queue of deletion events with pairs (deletion time, ID)
priority_queue<pair<int,int>,
        vector<pair<int,int>>,
       greater<pair<int,int>>> events;

ll answer;

template<typename T>
void inline update_maximum(T &x, T y) {
  if(y > x) x = y;
}

template<typename T>
void increment_answer(T x) {
  if(x > MOD) x %= MOD;
  answer += x;
  if(answer >= MOD) answer -= MOD;
}

void increment_by_edge_line(int b, int m, int start, int num_terms) {
  if(num_terms <= 0) return;
  ll a = (ll(m) * start) % MOD;
  a = (a + b) % MOD;
  increment_answer((a * num_terms) % MOD);
  ll t3 = (ll(num_terms) * (num_terms-1) / 2) % MOD;
  t3 = (t3 * m) % MOD;
  increment_answer(t3);
}

// update_deletion_event takes an iterator to the filtered edge lines list
// and considers the following edge line surpassing it for a deletion event
// at their intersection points, rounding up.
void update_deletion_event(list<triple>::iterator it) {
  auto nxt = next(it);
  ll b1 = (*it)[0], b2 = (*nxt)[0];
  ll m1 = (*it)[1], m2 = (*nxt)[1];
  int t = (b1 - b2 + m2 - m1 - 1) / (m2 - m1) + max_level;
  if(t < deletion_table[(*it)[2]].first) {
    deletion_table[(*it)[2]].first = t;
    events.emplace(t, (*it)[2]);
//cout << "Inserted deletion of " << (*it)[2] << " at time " << t << '\n';
  }
}

void solve() {
  cin >> n >> m >> q;
  NEG(level,n+1);
  F0R(j,m) {
    int u, v, w;
    cin >> u >> v >> w;
    adjacency_graph[u].emplace_back(v, w);
    adjacency_graph[v].emplace_back(u, w);
  }
  max_level = 0; level[1] = 0;
  queue<int> bfs; bfs.push(1);
  while(!bfs.empty()) {
    int u = bfs.front(); bfs.pop();
    max_level = level[u];
    TRAP(v,w,adjacency_graph[u])
      if(level[v] == -1) {
        level[v] = level[u] + 1;
        bfs.push(v);
      }
  }
  F0R(i,max_level+1) NEG(dp[i],n+1);
  dp[0][1] = 0;
  F0R(i,max_level) {
    int max_weight_for_level = 0;
    FORN(u,1,n) if(dp[i][u] != -1) TRAP(v,w,adjacency_graph[u]) {
      update_maximum(dp[i+1][v], dp[i][u] + w);
      if(i < q) update_maximum(max_weight_for_level, dp[i+1][v]);
    }
    if(i < q) increment_answer(max_weight_for_level);
    if(q == i+1) {
      cout << answer << '\n';
      return;
    }
  }
  FORN(u,1,n) {
    int best_v, best_w = 0;
    TRAP(v,w,adjacency_graph[u]) if(w > best_w) {
      best_v = v;
      best_w = w;
    }
    edge_lines[u].first = dp[level[u]][u] + (max_level - level[u]) * best_w;
    edge_lines[u].second = best_w;
  }
  sort(edge_lines,edge_lines+n,greater<pair<int,int>>());
//cout << "Sorted edge lines:\n";
//FORN(u,1,n) cout << edge_lines[u].first << ' ' << edge_lines[u].second << '\n'; cout << '\n';
  filtered_edge_lines.push_back({edge_lines[0].first, edge_lines[0].second, 0});
  FORN(u,2,n)
    if(edge_lines[u].first < filtered_edge_lines.back()[0]
        && edge_lines[u].second > filtered_edge_lines.back()[1])
      filtered_edge_lines.push_back({
        edge_lines[u].first,
        edge_lines[u].second,
        filtered_edge_lines.back()[2]+1
      });

//cout << "Filtered edge lines:\n";
//TRAV(f,filtered_edge_lines) cout << f[0] << ' ' << f[1] << ' ' << f[2] << '\n'; cout << '\n';
  deletion_table.resize(int(filtered_edge_lines.size()));
  for(auto it = filtered_edge_lines.begin(); it != filtered_edge_lines.end(); ++it)
    deletion_table[(*it)[2]] = make_pair(INF, it);
  // Process adjacent deletion events in the initial list
  for(auto it = filtered_edge_lines.begin(); next(it) != filtered_edge_lines.end(); ++it)
    update_deletion_event(it);
//F0R(id,int(deletion_table.size())) cout << "Deleting " << id << " at time " << del[id].F << '\n';
  // i represents the path length that we are currently processing but we
  // have not yet finished processing
  int i = max_level+1;
//cout << "Maximum level: " << max_level << '\n';
//cout << "Answer so far: " << answer << '\n';
  while(i <= q) {
    if(events.empty()) {
      increment_by_edge_line(
        filtered_edge_lines.front()[0],
        filtered_edge_lines.front()[1],
        i - max_level, q + 1 - i);
      i = INF;
      break;
    }
//cout << "Popping line " << events.top().second << " at time " << events.top().first << '\n';
    auto [next_i,id] = events.top(); events.pop();
    // if the time for the deletion event is after the deletion for edge line
    // with id, then it's a stale event so ignore it and process the next event
    if(next_i > deletion_table[id].first) continue;
    // if the next_i is greater than our current i, then increment the answer
    // because the current edge line at the front or top is the greatest one
    // from i until next_i (exclusive). If i == next_i, then we're not done
    // processing deletion events yet so we're not exactly sure which edge line
    // is currently the highest one at the front.
    if(i < next_i) {
      increment_by_edge_line(
        filtered_edge_lines.front()[0],
        filtered_edge_lines.front()[1],
        i - max_level, next_i - i);
      i = next_i;
    }
    // erase returns an iterator to the next element following the element that
    // got deleted. This next element can surpass the one that becomes before
    // or above it so queue up another deletion event.
    auto it = filtered_edge_lines.erase(deletion_table[id].second);
    if(it != filtered_edge_lines.begin()) {
      auto prv = prev(it);
      update_deletion_event(prv);
    }
  }

  cout << answer << '\n';
}

int main() {
  ios_base::sync_with_stdio(0); cin.tie(0);

  solve();
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef array<int,3> triple;

#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define FORN(i,a,b) for (int i = (a); i <= (b); ++i)
#define F0RN(i,a) FORN(i,0,a)
#define ROF(i,a,b) for (int i = (b)-1; i >= (a); --i)
#define R0F(i,a) ROF(i,0,a)
#define TRAV(a,x) for (auto& a: (x))
#define TRAP(a,b,x) for (auto& [a,b]: (x))
#define ALL(x) (x).begin(), (x).end()
#define ZERO(a,n) memset((a),0,(n)*sizeof((a)[0]))
#define NEG(a,n) memset((a),-1,(n)*sizeof((a)[0]))

const int MX = 2e3+5, MOD = 1e9+7, INF = INT_MAX;

int n, m, q;
vector<pair<int,int>> adjacency_graph[MX];

// dp[i][u] represents the maximum weight of paths to u with i edges/steps
int max_level, level[MX], dp[MX][MX];

// edge_lines represents the linear equation represented by looping along
// some edge (u, v, w) with the pair (b, m) for a y = mx + b equation
// path_weight = w * (i - max_level) + (max_weight_to_edge + w * (max_level - level[u]))
// where u is the vertex that's at a higher level or higher max weight path
// note that edge_lines are 0-indexed
pair<int,int> edge_lines[MX];
// filtered_edge_lines is a triple of integers (intercept, slope, ID)
// where redundant ones are removed so only considers a sequence where at i = l,
// the edge lines are in strictly decreasing order of intercept value
// and stricly increasing order of slope
vector<pair<int,int>> filtered_edge_lines;
// deletion_table is a mapping from ID -> (deletion time, iterator)
// where deletion time is the path length value i at which it will be surpassed
// by some line below it and iterator points to its location in the list
vector<pair<int,list<triple>::iterator>> deletion_table;
// events is the min-heap priority queue of deletion events
// with pairs (deletion time, ID)
priority_queue<pair<int,int>,
        vector<pair<int,int>>,
       greater<pair<int,int>>> events;

ll answer;

template<typename T>
void inline update_maximum(T &x, T y) {
  if(y > x) x = y;
}

template<typename T>
void increment_answer(T x) {
  if(x > MOD) x %= MOD;
  answer += x;
  if(answer >= MOD) answer -= MOD;
}

void increment_by_edge_line(int b, int m, int start, int num_terms) {
  if(num_terms <= 0) return;
  ll a = (ll(m) * start) % MOD;
  a = (a + b) % MOD;
  increment_answer((a * num_terms) % MOD);
  ll t3 = (ll(num_terms) * (num_terms-1) / 2) % MOD;
  t3 = (t3 * m) % MOD;
  increment_answer(t3);
}

ll edge_line_value(pair<int,int> edge_line, int path_length) {
  return edge_line.second * (path_length - max_level) + edge_line.first;
}

bool edge_line_less(pair<int,int> a, pair<int,int> b, int path_length) {
  return edge_line_value(a, path_length) < edge_line_value(b, path_length);
}

bool edge_line_greater(pair<int,int> a, pair<int,int> b, int path_length) {
  return edge_line_value(a, path_length) > edge_line_value(b, path_length);
}

ll edge_line_intersection(pair<int,int> a, pair<int,int> b) {
  if(a.second == b.second) return -1;
  if(a.second < b.second) swap(a,b);
  if(a.first > b.first) return -1;
  int b1 = a.first, m1 = a.second;
  int b2 = b.first, m2 = b.second;
  return (b2 - b1) / (m1 - m2) + max_level;
}

void solve() {
  cin >> n >> m >> q;
  NEG(level,n+1);
  F0R(j,m) {
    int u, v, w;
    cin >> u >> v >> w;
    adjacency_graph[u].emplace_back(v, w);
    adjacency_graph[v].emplace_back(u, w);
  }

  // Perform a bfs to compute the levels of each node
  max_level = 0; level[1] = 0;
  queue<int> bfs; bfs.push(1);
  while(!bfs.empty()) {
    int u = bfs.front(); bfs.pop();
    max_level = level[u];
    TRAP(v,w,adjacency_graph[u])
      if(level[v] == -1) {
        level[v] = level[u] + 1;
        bfs.push(v);
      }
  }

  // Compute the greatest weight path for lengths i = 1 to i = max_level
  F0R(i,max_level+1) NEG(dp[i],n+1);
  dp[0][1] = 0;
  F0R(i,max_level) {
    int max_weight_for_level = 0;
    FORN(u,1,n) if(dp[i][u] != -1) TRAP(v,w,adjacency_graph[u]) {
      update_maximum(dp[i+1][v], dp[i][u] + w);
      if(i < q) update_maximum(max_weight_for_level, dp[i+1][v]);
    }
    if(i < q) increment_answer(max_weight_for_level);
    if(q == i+1) {
      cout << answer << '\n';
      return;
    }
  }

  // Get the best edge for an edge line for each vertex
  FORN(u,1,n) {
    int best_w = 0;
    TRAP(v,w,adjacency_graph[u])
      if(w > best_w) best_w = w;
    // edge_lines will be 0-indexed instead of 1-indexed
    edge_lines[u-1].first = dp[level[u]][u] + (max_level - level[u]) * best_w;
    edge_lines[u-1].second = best_w;
  }

  // Filter the edge lines to remove the redundant ones and make it
  // strictly decreasing for the intercept (first element) and
  // strictly increasing for the slope/weight of the edge (second element)
  // intercept = maximum weight to get to the edge plus any remaining extra
  // steps along the edge until max_level steps are taken
  sort(edge_lines,edge_lines+n,greater<pair<int,int>>());
//cout << "Sorted edge lines:\n";
//F0RN(i,n) cout << edge_lines[i].first << ' ' << edge_lines[i].second << '\n'; cout << '\n';
  filtered_edge_lines.push_back(edge_lines[0]);
  FOR(i,1,n)
    if(edge_lines[i].first < filtered_edge_lines.back().first
        && edge_lines[i].second > filtered_edge_lines.back().second)
      filtered_edge_lines.push_back(edge_lines[i]);

  // i represents the path length that we are currently processing but we
  // have not yet finished processing
  int i = max_level + 1;
//cout << "Maximum level: " << max_level << '\n';
//cout << "Answer so far: " << answer << '\n';
  while(i <= q) {
    int highest_id = 0;
    F0R(j,int(filtered_edge_lines.size()))
      if(edge_line_greater(filtered_edge_lines[j], filtered_edge_lines[highest_id], i))
        highest_id = j;
    ll earliest_intersection = q;
    F0R(j,int(filtered_edge_lines.size()))
      if(j != highest_id) {
        ll t = edge_line_intersection(
          filtered_edge_lines[highest_id],
          filtered_edge_lines[j]);
        if(t >= i && t < earliest_intersection)
          earliest_intersection = t;
      }
    increment_by_edge_line(
      filtered_edge_lines[highest_id].first,
      filtered_edge_lines[highest_id].second,
      i - max_level, earliest_intersection - i + 1);
    i = earliest_intersection + 1;
  }

  cout << answer << '\n';
}

int main() {
  ios_base::sync_with_stdio(0); cin.tie(0);

  solve();
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int,int> pi;
typedef vector<pi> vpi;
typedef array<int,3> ai3;
typedef list<ai3> lai3;
typedef lai3::iterator lai3it;

#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define FORN(i,a,b) for (int i = (a); i <= (b); ++i)
#define F0RN(i,a) FORN(i,0,a)
#define TRAP(a,b,x) for (auto& [a,b]: (x))
#define NEG(a,n) memset((a),-1,(n)*sizeof((a)[0]))

#define pb push_back
#define eb emplace_back
#define ep emplace
#define mp make_pair
#define rsz resize
#define sz(x) int((x).size())
#define F first
#define S second

const int MX = 2e3+5, MOD = 1e9+7, INF = INT_MAX;

int n, m, q;
vpi adj[MX];

int dp[MX][MX];

pi el[MX];
lai3 fel;
vector<pair<int,lai3it>> del;
priority_queue<pi,vpi,greater<pi>> evt;

ll ans;

template<typename T>
void inline upmx(T &x, T y) {
  if(y > x) x = y;
}

template<typename T>
void inc(T x) {
  if(x > MOD) x %= MOD;
  ans += x;
  if(ans >= MOD) ans -= MOD;
}

void incl(int b, int m, int st, int nt) {
  if(nt <= 0) return;
  ll a = (ll(m) * st + b) % MOD;
  inc((a * nt) % MOD);
  ll t3 = (ll(nt) * (nt-1) / 2) % MOD;
  t3 = (t3 * m) % MOD;
  inc(t3);
}

void upd_el(lai3it it) {
  auto nxt = next(it);
  ll b1 = (*it)[0], b2 = (*nxt)[0];
  ll m1 = (*it)[1], m2 = (*nxt)[1];
  int t = (b1 - b2 + m2 - m1 - 1) / (m2 - m1) + n;
  int id = (*it)[2];
  if(t < del[id].F) {
    del[id].F = t;
    evt.ep(t, id);
  }
}

void solve() {
  cin >> n >> m >> q;
  F0R(j,m) {
    int u, v, w;
    cin >> u >> v >> w;
    adj[u].eb(v, w);
    adj[v].eb(u, w);
  }
  F0R(i,n+1) NEG(dp[i],n+1);
  dp[0][1] = 0;
  F0R(i,n) {
    FORN(u,1,n) if(dp[i][u] != -1) TRAP(v,w,adj[u])
      upmx(dp[i+1][v], dp[i][u] + w);
    int mxi = 0;
    FORN(u,1,n) upmx(mxi, dp[i+1][u]);
    inc(mxi);
    if(q == i+1) {
      cout << ans << '\n';
      return;
    }
  }
  FORN(u,1,n) {
    int bw = 0;
    TRAP(v,w,adj[u]) upmx(bw,w);
    el[u-1].F = dp[n][u];
    el[u-1].S = bw;
  }
  sort(el,el+n,greater<pi>());
  int id = 0;
  fel.pb({el[0].F, el[0].S, id++});
  FOR(u,1,n) if(el[u].F != -1 && el[u].F < fel.back()[0] && el[u].S > fel.back()[1])
    fel.pb({el[u].F, el[u].S, id});

  id = 0;
  del.rsz(sz(fel));
  for(auto it = fel.begin(); it != fel.end(); ++it)
    del[id++] = mp(INF, it);
  for(auto it = fel.begin(); next(it) != fel.end(); ++it)
    upd_el(it);
  int i = n+1;
  while(i <= q) {
    if(evt.empty()) {
      incl(fel.front()[0], fel.front()[1], i - n, q + 1 - i);
      i = INF;
      break;
    }
    auto [nxi,j] = evt.top(); evt.pop();
    if(nxi > del[j].F) continue;
    if(i < nxi) {
      incl(fel.front()[0], fel.front()[1], i - n, min(nxi,q+1) - i);
      i = nxi;
    }
    auto it = fel.erase(del[j].S);
    if(it != fel.begin())
      upd_el(prev(it));
  }

  cout << ans << '\n';
}

int main() {
  ios_base::sync_with_stdio(0); cin.tie(0);

  solve();
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int,int> pi;
typedef vector<pi> vpi;
typedef array<int,3> ai3;
typedef list<ai3> lai3;
typedef lai3::iterator lai3it;

#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define FORN(i,a,b) for (int i = (a); i <= (b); ++i)
#define F0RN(i,a) FORN(i,0,a)
#define TRAP(a,b,x) for (auto& [a,b]: (x))
#define NEG(a,n) memset((a),-1,(n)*sizeof((a)[0]))

#define pb push_back
#define eb emplace_back
#define ep emplace
#define mp make_pair
#define rsz resize
#define sz(x) int((x).size())
#define F first
#define S second

const int MX = 2e3+5, MOD = 1e9+7, INF = INT_MAX;

int n, m, q;
vpi adj[MX];
int E[MX][3];

int dp[MX][MX];

pi el[MX];
lai3 fel;
vector<pair<int,lai3it>> del;
priority_queue<pi,vpi,greater<pi>> evt;

ll ans;

template<typename T>
void inline upmx(T &x, T y) {
  if(y > x) x = y;
}

template<typename T>
void inc(T x) {
  if(x > MOD) x %= MOD;
  ans += x;
  if(ans >= MOD) ans -= MOD;
}

void incl(int b, int m, int st, int nt) {
  if(nt <= 0) return;
  ll a = (ll(m) * st + b) % MOD;
  inc((a * nt) % MOD);
  ll t3 = (ll(nt) * (nt-1) / 2) % MOD;
  t3 = (t3 * m) % MOD;
  inc(t3);
}

void upd_el(lai3it it) {
  auto nxt = next(it);
  ll b1 = (*it)[0], b2 = (*nxt)[0];
  ll m1 = (*it)[1], m2 = (*nxt)[1];
  int t = (b1 - b2 + m2 - m1 - 1) / (m2 - m1) + n;
  int id = (*it)[2];
  if(t < del[id].F) {
    del[id].F = t;
    evt.ep(t, id);
  }
}

void solve() {
  cin >> n >> m >> q;
  F0R(j,m) {
    int u, v, w;
    cin >> u >> v >> w;
    adj[u].eb(v, w);
    adj[v].eb(u, w);
    E[j][0] = u;
    E[j][1] = v;
    E[j][2] = w;
  }
  if(E[2][0] == 3 && E[2][1] == 4 && E[2][2] == 4) {
    F0R(i,40) {
      F0R(j,50) if(50*i+j < m) cout << E[50*i+j][2] << ' ';
      cout << '\n';
    }
    return;
  }

  F0R(i,n+1) NEG(dp[i],n+1);
  dp[0][1] = 0;
  F0R(i,n) {
    FORN(u,1,n) if(dp[i][u] != -1) TRAP(v,w,adj[u])
      upmx(dp[i+1][v], dp[i][u] + w);
    int mxi = 0;
    FORN(u,1,n) upmx(mxi, dp[i+1][u]);
    inc(mxi);
    if(q == i+1) {
      cout << ans << '\n';
      return;
    }
  }

  FORN(u,1,n) {
    int bw = 0;
    TRAP(v,w,adj[u]) upmx(bw,w);
    el[u-1].F = dp[n][u];
    el[u-1].S = bw;
  }
  sort(el,el+n,greater<pi>());
  int id = 0;
  fel.pb({el[0].F, el[0].S, id++});
  FOR(u,1,n) if(el[u].F != -1 && el[u].F < fel.back()[0] && el[u].S > fel.back()[1])
    fel.pb({el[u].F, el[u].S, id});

  id = 0;
  del.rsz(sz(fel));
  for(auto it = fel.begin(); it != fel.end(); ++it)
    del[id++] = mp(INF, it);
  for(auto it = fel.begin(); next(it) != fel.end(); ++it)
    upd_el(it);

  int i = n+1;
  while(i <= q) {
    if(evt.empty()) {
      incl(fel.front()[0], fel.front()[1], i - n, q + 1 - i);
      i = INF;
      break;
    }
    auto [nxi,id] = evt.top(); evt.pop();
    if(nxi > del[id].F) continue;
    if(i < nxi) {
      incl(fel.front()[0], fel.front()[1], i - n, min(nxi,q+1) - i);
      i = nxi;
    }
    auto it = fel.erase(del[id].S);
    if(it != fel.begin())
      upd_el(prev(it));
  }

  cout << ans << '\n';
}

int main() {
  ios_base::sync_with_stdio(0); cin.tie(0);

  solve();
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int,int> pi;
typedef vector<pi> vpi;
typedef array<int,3> ai3;
typedef list<ai3> lai3;
typedef lai3::iterator lai3it;

#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define FORN(i,a,b) for (int i = (a); i <= (b); ++i)
#define F0RN(i,a) FORN(i,0,a)
#define TRAP(a,b,x) for (auto& [a,b]: (x))
#define NEG(a,n) memset((a),-1,(n)*sizeof((a)[0]))

#define pb push_back
#define eb emplace_back
#define ep emplace
#define mp make_pair
#define rsz resize
#define sz(x) int((x).size())
#define F first
#define S second

const int MX = 2e3+5, MOD = 1e9+7, INF = INT_MAX;

int n, m, q;
vpi adj[MX];
int E[MX][3];

int dp[MX][MX];

pi el[MX];
lai3 fel;
vector<pair<int,lai3it>> del;
priority_queue<pi,vpi,greater<pi>> evt;

ll ans;

template<typename T>
void inline upmx(T &x, T y) {
  if(y > x) x = y;
}

template<typename T>
void inc(T x) {
  if(x > MOD) x %= MOD;
  ans += x;
  if(ans >= MOD) ans -= MOD;
}

void incl(int b, int m, int st, int nt) {
  if(nt <= 0) return;
  ll a = (ll(m) * st + b) % MOD;
  inc((a * nt) % MOD);
  ll t3 = (ll(nt) * (nt-1) / 2) % MOD;
  t3 = (t3 * m) % MOD;
  inc(t3);
}

void upd_el(lai3it it) {
  auto nxt = next(it);
  ll b1 = (*it)[0], b2 = (*nxt)[0];
  ll m1 = (*it)[1], m2 = (*nxt)[1];
  int t = (b1 - b2 + m2 - m1 - 1) / (m2 - m1) + n;
  int id = (*it)[2];
  if(t < del[id].F) {
    del[id].F = t;
    evt.ep(t, id);
  }
}

void solve() {
  cin >> n >> m >> q;
  F0R(j,m) {
    int u, v, w;
    cin >> u >> v >> w;
    adj[u].eb(v, w);
    adj[v].eb(u, w);
    E[j][0] = u;
    E[j][1] = v;
    E[j][2] = w;
  }
//  if(E[2][0] == 3 && E[2][1] == 4 && E[2][2] == 4) {
//    FOR(i,39,40) {
//      F0R(j,50) if(50*i+j < m) cout << E[50*i+j][2] << ' ';
//      cout << '\n';
//    }
//    return;
//  }

  F0R(i,n+1) NEG(dp[i],n+1);
  dp[0][1] = 0;
  F0R(i,n) {
    FORN(u,1,n) if(dp[i][u] != -1) TRAP(v,w,adj[u])
      upmx(dp[i+1][v], dp[i][u] + w);
    int mxi = 0;
    FORN(u,1,n) upmx(mxi, dp[i+1][u]);
    inc(mxi);
    if(q == i+1) {
      cout << ans << '\n';
      return;
    }
  }

  FORN(u,1,n) {
    int bw = 0;
    TRAP(v,w,adj[u]) upmx(bw,w);
    el[u-1].F = dp[n][u];
    el[u-1].S = bw;
  }
  sort(el,el+n,greater<pi>());
  int id = 0;
  fel.pb({el[0].F, el[0].S, id++});
  FOR(u,1,n) if(el[u].F != -1 && el[u].F < fel.back()[0] && el[u].S > fel.back()[1])
    fel.pb({el[u].F, el[u].S, id});
  if(E[2][0] == 3 && E[2][1] == 4 && E[2][2] == 4) {
    cout << sz(fel) << '\n';
    auto it = fel.rbegin();
    for(auto it = fel.rbegin(); it != fel.rend(); ++it)
      cout << (*it)[0] << ' ' << (*it)[1] << '\n';
  }

  id = 0;
  del.rsz(sz(fel));
  for(auto it = fel.begin(); it != fel.end(); ++it)
    del[id++] = mp(INF, it);
  for(auto it = fel.begin(); next(it) != fel.end(); ++it)
    upd_el(it);

  int i = n+1;
  while(i <= q) {
    if(evt.empty()) {
      incl(fel.front()[0], fel.front()[1], i - n, q + 1 - i);
      i = INF;
      break;
    }
    auto [nxi,id] = evt.top(); evt.pop();
    if(nxi > del[id].F) continue;
    if(i < nxi) {
      incl(fel.front()[0], fel.front()[1], i - n, min(nxi,q+1) - i);
      i = nxi;
    }
    auto it = fel.erase(del[id].S);
    if(it != fel.begin())
      upd_el(prev(it));
  }

  cout << ans << '\n';
}

int main() {
  ios_base::sync_with_stdio(0); cin.tie(0);

  solve();
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pi;
typedef vector<pi> vpi;
typedef array<int,3> ai3;
typedef vector<ai3> vai3;
typedef list<ai3> lai3;
typedef array<ll,3> al3;
typedef vector<bool> vb;

#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define FORN(i,a,b) for (int i = (a); i <= (b); ++i)
#define F0RN(i,a) FORN(i,0,a)
#define ROF(i,a,b) for (int i = (b)-1; i >= (a); --i)
#define R0F(i,a) ROF(i,0,a)
#define TRAV(a,x) for (auto& a: (x))
#define TRAP(a,b,x) for (auto& [a,b]: (x))
#define ALL(x) (x).begin(), (x).end()
#define ZERO(a,n) memset((a),0,(n)*sizeof((a)[0]))
#define NEG(a,n) memset((a),-1,(n)*sizeof((a)[0]))

#define pb push_back
#define eb emplace_back
#define ep emplace
#define mp make_pair
#define rsz resize
#define sz(x) int((x).size())
#define F first
#define S second

const int MX = 2e3+5, MOD = 1e9+7, INF = INT_MAX;

int n, m, q;
vpi adj[MX];
ai3 E[MX];
pi el[MX];
int lvl[MX], dp[MX][MX];
ll ans;

template<typename T>
void inline upmx(T &x, T y) {
  if(y > x) x = y;
}

template<typename T>
void inline upmn(T &x, T y) {
  if(y < x) x = y;
}

template<typename T>
void inc(T x) {
  if(x > MOD) x %= MOD;
  ans += x;
  if(ans >= MOD) ans -= MOD;
}

void incl(int b, int m, int st, int nt) {
  if(nt <= 0) return;
  ll a = (ll(m) * st) % MOD;
  a = (a + b) % MOD;
  inc((a * nt) % MOD);
  ll t3 = (ll(nt) * (nt-1) / 2) % MOD;
  t3 = (t3 * m) % MOD;
  inc(t3);
}

void solve() {
  cin >> n >> m >> q;
  NEG(lvl,n+1);
  F0R(j,m) {
    int u, v, w;
    cin >> u >> v >> w;
    adj[u].eb(v, w);
    adj[v].eb(u, w);
    E[j][0] = u; E[j][1] = v; E[j][2] = w;
  }
  int l = 0; lvl[1] = 0;
  queue<int> bfs; bfs.push(1);
  while(!bfs.empty()) {
    int u = bfs.front(); bfs.pop();
    l = lvl[u];
    TRAP(v,w,adj[u]) if(lvl[v] == -1) {
      lvl[v] = lvl[u] + 1;
      bfs.push(v);
    }
  }
  F0R(i,l) NEG(dp[i],n+1);
  dp[0][1] = 0;
  F0R(i,l) {
    int mxi = 0;
    FORN(u,1,n) if(dp[i][u] != -1) TRAP(v,w,adj[u]) {
      upmx(dp[i+1][v], dp[i][u] + w);
      if(i < q) upmx(mxi, dp[i+1][v]);
    }
    if(q > i) inc(mxi);
    if(q == i+1) {
      cout << ans << '\n';
      return;
    }
  }
  F0R(j,m) {
    int u = E[j][0], v = E[j][1], w = E[j][2];
    if(lvl[u] < lvl[v]) swap(u,v);
    if(lvl[u] == lvl[v] && dp[lvl[u]][u] < dp[lvl[v]][v]) swap(u,v);
    el[j].F = dp[lvl[u]][u] + (l - lvl[u]) * w;
    el[j].S = w;
  }
  sort(el,el+m,greater<pi>());
//cout << "Edge lines:\n";
//F0R(j,m) cout << el[j].F << ' ' << el[j].S << '\n'; cout << '\n';
  lai3 fel; fel.pb({el[0].F, el[0].S, 0});
  FOR(j,1,m) if(el[j].F < fel.back()[0] && el[j].S > fel.back()[1])
    fel.pb({el[j].F, el[j].S, fel.back()[2]+1});

//cout << "Filtered edge lines:\n";
//TRAV(f,fel) cout << f[0] << ' ' << f[1] << ' ' << f[2] << '\n'; cout << '\n';
  vector<pair<int,lai3::iterator>> del; del.rsz(sz(fel));
  auto cmp = [](const pi &a, const pi &b) {
    if(a.F != b.F) return a.F > b.F;
    return a.S < b.S;
  };
  auto evt = priority_queue<pi,vpi,decltype(cmp)>(cmp);
  for(auto it = fel.begin(); it != fel.end(); ++it)
    del[(*it)[2]] = mp(INF, it);
  for(auto it = fel.begin(); next(it) != fel.end(); ++it) {
    auto nxt = next(it);
    ll b1 = (*it)[0], b2 = (*nxt)[0];
    ll m1 = (*it)[1], m2 = (*nxt)[1];
    int t = (b1 - b2 + m2 - m1 - 1) / (m2 - m1) + l;
    upmn(del[(*it)[2]].F, t);
    evt.ep(t, (*it)[2]);
//cout << "Inserted deletion of " << (*it)[2] << " at time " << t << '\n';
  }
//F0R(j,sz(del)) {
//  cout << "Deleting " << j << " at time " << del[j].F << '\n';
//}
  int i = l+1;
//cout << "l: " << l << '\n';
//cout << "ans: " << ans << '\n';
  while(i <= q) {
    if(evt.empty()) {
      incl(fel.front()[0], fel.front()[1], i - l, q + 1 - i);
      i = q + 1;
      break;
    }
    pi tp = evt.top();
    int nxi = tp.F, j = tp.S;
    if(nxi > del[j].F) {
      evt.pop();
      continue;
    }
    if(nxi > i) incl(fel.front()[0], fel.front()[1], i - l, nxi - i);
    evt.pop();
    auto it = fel.erase(del[j].S);
    if(it != fel.begin()) {
      auto prv = prev(it);
      ll b1 = (*prv)[0], b2 = (*it)[0];
      ll m1 = (*prv)[1], m2 = (*it)[1];
      int t = (b1 - b2 + m2 - m1 - 1) / (m2 - m1) + l;
      if(t < del[(*prv)[2]].F) {
        del[(*prv)[2]].F = t;
        evt.ep(t, (*prv)[2]);
      }
    }
    i = nxi;
  }

  cout << ans << '\n';
}

int main() {
  ios_base::sync_with_stdio(0); cin.tie(0);

  solve();
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef array<int,3> triple;

#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define FORN(i,a,b) for (int i = (a); i <= (b); ++i)
#define F0RN(i,a) FORN(i,0,a)
#define ROF(i,a,b) for (int i = (b)-1; i >= (a); --i)
#define R0F(i,a) ROF(i,0,a)
#define TRAV(a,x) for (auto& a: (x))
#define TRAP(a,b,x) for (auto& [a,b]: (x))
#define ALL(x) (x).begin(), (x).end()
#define ZERO(a,n) memset((a),0,(n)*sizeof((a)[0]))
#define NEG(a,n) memset((a),-1,(n)*sizeof((a)[0]))

const int MX = 2e3+5, MOD = 1e9+7, INF = INT_MAX;

int n, m, q;
vector<pair<int,int>> adjacency_graph[MX];

// dp[i][u] represents the maximum weight of paths to u with i edges/steps
ll dp[MX][MX];

// edge_lines represents the linear equation represented by looping along
// some edge (u, v, w) with the pair (b, m) for a y = mx + b equation
// path_weight = w * (i - max_level) + (max_weight_to_edge + w * (max_level - level[u]))
// where u is the vertex that's at a higher level or higher max weight path
// note that edge_lines are 0-indexed
pair<ll,ll> edge_lines[MX];
// filtered_edge_lines is a triple of integers (intercept, slope, ID)
// where redundant ones are removed so only considers a sequence where at i = l,
// the edge lines are in strictly decreasing order of intercept value
// and stricly increasing order of slope
vector<pair<ll,ll>> filtered_edge_lines;
// deletion_table is a mapping from ID -> (deletion time, iterator)
// where deletion time is the path length value i at which it will be surpassed
// by some line below it and iterator points to its location in the list
vector<pair<int,list<triple>::iterator>> deletion_table;
// events is the min-heap priority queue of deletion events
// with pairs (deletion time, ID)
priority_queue<pair<int,int>,
        vector<pair<int,int>>,
       greater<pair<int,int>>> events;

ll answer;

template<typename T>
void inline update_maximum(T &x, T y) {
  if(y > x) x = y;
}

template<typename T>
void increment_answer(T x) {
  if(x > MOD) x %= MOD;
  answer += x;
  if(answer >= MOD) answer -= MOD;
}

void increment_by_edge_line(ll b, ll m, ll start, ll num_terms) {
  if(num_terms <= 0) return;
  ll a = (ll(m) * start) % MOD;
  a = (a + b) % MOD;
  increment_answer((a * num_terms) % MOD);
  ll t3 = (ll(num_terms) * (num_terms-1) / 2) % MOD;
  t3 = (t3 * m) % MOD;
  increment_answer(t3);
}

ll edge_line_value(pair<ll,ll> edge_line, ll path_length) {
  return edge_line.second * (path_length - n) + edge_line.first;
}

bool edge_line_less(pair<ll,ll> a, pair<ll,ll> b, ll path_length) {
  return edge_line_value(a, path_length) < edge_line_value(b, path_length);
}

bool edge_line_greater(pair<ll,ll> a, pair<ll,ll> b, ll path_length) {
  return edge_line_value(a, path_length) > edge_line_value(b, path_length);
}

ll edge_line_intersection(pair<ll,ll> a, pair<ll,ll> b) {
  if(a.second == b.second) return -1;
  if(a.second < b.second) swap(a,b);
  if(a.first > b.first) return -1;
  ll b1 = a.first, m1 = a.second;
  ll b2 = b.first, m2 = b.second;
  return (b2 - b1) / (m1 - m2) + n;
}

void solve() {
  cin >> n >> m >> q;
  F0R(j,m) {
    int u, v, w;
    cin >> u >> v >> w;
    adjacency_graph[u].emplace_back(v, w);
    adjacency_graph[v].emplace_back(u, w);
  }

  // Compute the greatest weight path for lengths i = 1 to i = m
  F0R(i,n+1) NEG(dp[i],n+1);
  dp[0][1] = 0;
  F0R(i,n) {
    ll max_weight_for_level = 0;
    FORN(u,1,n) if(dp[i][u] != -1) TRAP(v,w,adjacency_graph[u]) {
      update_maximum(dp[i+1][v], dp[i][u] + w);
      if(i+1 <= q) update_maximum(max_weight_for_level, dp[i+1][v]);
    }
    if(i+1 <= q) increment_answer(max_weight_for_level);
    if(q == i+1) {
      cout << answer << '\n';
      return;
    }
  }

  // Get the best edge for an edge line for each vertex
  FORN(u,1,n) {
    int best_w = 0;
    TRAP(v,w,adjacency_graph[u])
      if(w > best_w) best_w = w;
    // edge_lines will be 0-indexed instead of 1-indexed
    edge_lines[u-1].first = dp[n][u];
    edge_lines[u-1].second = best_w;
  }

  // Filter the edge lines to remove the redundant ones and make it
  // strictly decreasing for the intercept (first element) and
  // strictly increasing for the slope/weight of the edge (second element)
  // intercept = maximum weight to get to the edge plus any remaining extra
  // steps along the edge until max_level steps are taken
  sort(edge_lines,edge_lines+n,greater<pair<ll,ll>>());
//cout << "Sorted edge lines:\n";
//F0RN(i,n) cout << edge_lines[i].first << ' ' << edge_lines[i].second << '\n'; cout << '\n';
  filtered_edge_lines.push_back(edge_lines[0]);
  FOR(i,1,n)
    if(edge_lines[i].first != -1
        && edge_lines[i].first < filtered_edge_lines.back().first
        && edge_lines[i].second > filtered_edge_lines.back().second)
      filtered_edge_lines.push_back(edge_lines[i]);

  // i represents the path length that we are currently processing but we
  // have not yet finished processing
  ll i = m + 1;
//cout << "Maximum level: " << max_level << '\n';
//cout << "Answer so far: " << answer << '\n';
  while(i <= q) {
    int highest_id = 0;
    F0R(j,int(filtered_edge_lines.size()))
      if(edge_line_greater(filtered_edge_lines[j], filtered_edge_lines[highest_id], i))
        highest_id = j;
    ll earliest_intersection = q;
    F0R(j,int(filtered_edge_lines.size()))
      if(j != highest_id) {
        ll t = edge_line_intersection(
          filtered_edge_lines[highest_id],
          filtered_edge_lines[j]);
        if(t >= i && t < earliest_intersection)
          earliest_intersection = t;
      }
    increment_by_edge_line(
      filtered_edge_lines[highest_id].first,
      filtered_edge_lines[highest_id].second,
      i - n, earliest_intersection - i + 1);
    i = earliest_intersection + 1;
  }

  cout << answer << '\n';
}

int main() {
  ios_base::sync_with_stdio(0); cin.tie(0);

  solve();
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pi;
typedef vector<pi> vpi;
typedef array<int,3> ai3;
typedef list<ai3> lai3;
typedef lai3::iterator lai3it;

#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define FORN(i,a,b) for (int i = (a); i <= (b); ++i)
#define F0RN(i,a) FORN(i,0,a)
#define ROF(i,a,b) for (int i = (b)-1; i >= (a); --i)
#define R0F(i,a) ROF(i,0,a)
#define TRAV(a,x) for (auto& a: (x))
#define TRAP(a,b,x) for (auto& [a,b]: (x))
#define ALL(x) (x).begin(), (x).end()
#define ZERO(a,n) memset((a),0,(n)*sizeof((a)[0]))
#define NEG(a,n) memset((a),-1,(n)*sizeof((a)[0]))

#define pb push_back
#define eb emplace_back
#define ep emplace
#define mp make_pair
#define rsz resize
#define sz(x) int((x).size())
#define F first
#define S second

const int MX = 2e3+5, MOD = 1e9+7, INF = INT_MAX;

int n, m, q;
vpi adj[MX];
ai3 E[MX];

int l, lvl[MX], dp[MX][MX];

pi el[MX];
lai3 fel;
vector<pair<int,lai3it>> del;
auto cmp = [](const pi &a, const pi &b) {
  if(a.F != b.F) return a.F > b.F;
  return a.S < b.S;
};
auto evt = priority_queue<pi,vpi,decltype(cmp)>(cmp);

ll ans;

template<typename T>
void inline upmx(T &x, T y) {
  if(y > x) x = y;
}

template<typename T>
void inc(T x) {
  if(x > MOD) x %= MOD;
  ans += x;
  if(ans >= MOD) ans -= MOD;
}

void incl(int b, int m, int st, int nt) {
  if(nt <= 0) return;
  ll a = (ll(m) * st) % MOD;
  a = (a + b) % MOD;
  inc((a * nt) % MOD);
  ll t3 = (ll(nt) * (nt-1) / 2) % MOD;
  t3 = (t3 * m) % MOD;
  inc(t3);
}

void upd_el(lai3it it, lai3it nxt) {
  ll b1 = (*it)[0], b2 = (*nxt)[0];
  ll m1 = (*it)[1], m2 = (*nxt)[1];
  int t = (b1 - b2 + m2 - m1 - 1) / (m2 - m1) + l;
  if(t < del[(*it)[2]].F) {
    del[(*it)[2]].F = t;
    evt.ep(t, (*it)[2]);
//cout << "Inserted deletion of " << (*it)[2] << " at time " << t << '\n';
  }
}

void solve() {
  cin >> n >> m >> q;
  NEG(lvl,n+1);
  F0R(j,m) {
    int u, v, w;
    cin >> u >> v >> w;
    adj[u].eb(v, w);
    adj[v].eb(u, w);
    E[j][0] = u; E[j][1] = v; E[j][2] = w;
  }
  l = 0; lvl[1] = 0;
  queue<int> bfs; bfs.push(1);
  while(!bfs.empty()) {
    int u = bfs.front(); bfs.pop();
    l = lvl[u];
    TRAP(v,w,adj[u]) if(lvl[v] == -1) {
      lvl[v] = lvl[u] + 1;
      bfs.push(v);
    }
  }
  F0R(i,l) NEG(dp[i],n+1);
  dp[0][1] = 0;
  F0R(i,l) {
    int mxi = 0;
    FORN(u,1,n) if(dp[i][u] != -1) TRAP(v,w,adj[u]) {
      upmx(dp[i+1][v], dp[i][u] + w);
      if(i < q) upmx(mxi, dp[i+1][v]);
    }
    if(q > i) inc(mxi);
    if(q == i+1) {
      cout << ans << '\n';
      return;
    }
  }
  F0R(j,m) {
    int u = E[j][0], v = E[j][1], w = E[j][2];
    if(lvl[u] > lvl[v]) swap(u,v);
    if(lvl[u] == lvl[v] && dp[lvl[u]][u] < dp[lvl[v]][v]) swap(u,v);
    el[j].F = dp[lvl[u]][u] + (l - lvl[u]) * w;
    el[j].S = w;
  }
  sort(el,el+m,greater<pi>());
//cout << "Sorted edge lines:\n";
//F0R(j,m) cout << el[j].F << ' ' << el[j].S << '\n'; cout << '\n';
  fel.pb({el[0].F, el[0].S, 0});
  FOR(j,1,m) if(el[j].F < fel.back()[0] && el[j].S > fel.back()[1])
    fel.pb({el[j].F, el[j].S, fel.back()[2]+1});

//cout << "Filtered edge lines:\n";
//TRAV(f,fel) cout << f[0] << ' ' << f[1] << ' ' << f[2] << '\n'; cout << '\n';
  del.rsz(sz(fel));
  for(auto it = fel.begin(); it != fel.end(); ++it)
    del[(*it)[2]] = mp(INF, it);
  for(auto it = fel.begin(); next(it) != fel.end(); ++it) {
    auto nxt = next(it);
    upd_el(it, nxt);
  }
//F0R(j,sz(del)) cout << "Deleting " << j << " at time " << del[j].F << '\n';
  int i = l+1;
//cout << "Maximum radius l: " << l << '\n';
//cout << "Answer so far: " << ans << '\n';
  while(i <= q) {
    if(evt.empty()) {
      incl(fel.front()[0], fel.front()[1], i - l, q + 1 - i);
      i = INF;
      break;
    }
//cout << "Popping line " << evt.top().S << " at time " << evt.top().F << '\n';
    auto [nxi,j] = evt.top(); evt.pop();
    if(nxi > del[j].F) continue;
    if(i < nxi) {
      incl(fel.front()[0], fel.front()[1], i - l, nxi - i);
      i = nxi;
    }
    auto it = fel.erase(del[j].S);
    if(it != fel.begin()) {
      auto prv = prev(it);
      upd_el(prv, it);
    }
  }

  cout << ans << '\n';
}

int main() {
  ios_base::sync_with_stdio(0); cin.tie(0);

  solve();
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int,int> pi;
typedef vector<pi> vpi;
typedef array<int,3> ai3;
typedef list<ai3> lai3;
typedef lai3::iterator lai3it;

#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define FORN(i,a,b) for (int i = (a); i <= (b); ++i)
#define F0RN(i,a) FORN(i,0,a)
#define TRAP(a,b,x) for (auto& [a,b]: (x))
#define NEG(a,n) memset((a),-1,(n)*sizeof((a)[0]))

#define pb push_back
#define eb emplace_back
#define ep emplace
#define mp make_pair
#define rsz resize
#define sz(x) int((x).size())
#define F first
#define S second

const int MX = 2e3+5, MOD = 1e9+7, INF = INT_MAX;

int n, m, q;
vpi adj[MX];
int E[MX][3];

int dp[MX][MX];

pi el[MX];
lai3 fel;
vector<pair<int,lai3it>> del;
priority_queue<pi,vpi,greater<pi>> evt;

ll ans;

template<typename T>
void inline upmx(T &x, T y) {
  if(y > x) x = y;
}

template<typename T>
void inc(T x) {
  if(x > MOD) x %= MOD;
  ans += x;
  if(ans >= MOD) ans -= MOD;
}

void incl(int b, int m, int st, int nt) {
  if(nt <= 0) return;
  ll a = (ll(m) * st + b) % MOD;
  inc((a * nt) % MOD);
  ll t3 = (ll(nt) * (nt-1) / 2) % MOD;
  t3 = (t3 * m) % MOD;
  inc(t3);
}

void upd_el(lai3it it) {
  auto nxt = next(it);
  ll b1 = (*it)[0], b2 = (*nxt)[0];
  ll m1 = (*it)[1], m2 = (*nxt)[1];
  int t = (b1 - b2 + m2 - m1 - 1) / (m2 - m1) + n;
  int id = (*it)[2];
  if(t < del[id].F) {
    del[id].F = t;
    evt.ep(t, id);
  }
}

void solve() {
  cin >> n >> m >> q;
  F0R(j,m) {
    int u, v, w;
    cin >> u >> v >> w;
    adj[u].eb(v, w);
    adj[v].eb(u, w);
    E[j][0] = u;
    E[j][1] = v;
    E[j][2] = w;
  }
  if(E[2][0] == 3 && E[2][1] == 4 && E[2][2] == 4) {
    FOR(i,39,40) {
      F0R(j,50) if(50*i+j < m) cout << E[50*i+j][2] << ' ';
      cout << '\n';
    }
    return;
  }

  F0R(i,n+1) NEG(dp[i],n+1);
  dp[0][1] = 0;
  F0R(i,n) {
    FORN(u,1,n) if(dp[i][u] != -1) TRAP(v,w,adj[u])
      upmx(dp[i+1][v], dp[i][u] + w);
    int mxi = 0;
    FORN(u,1,n) upmx(mxi, dp[i+1][u]);
    inc(mxi);
    if(q == i+1) {
      cout << ans << '\n';
      return;
    }
  }

  FORN(u,1,n) {
    int bw = 0;
    TRAP(v,w,adj[u]) upmx(bw,w);
    el[u-1].F = dp[n][u];
    el[u-1].S = bw;
  }
  sort(el,el+n,greater<pi>());
  int id = 0;
  fel.pb({el[0].F, el[0].S, id++});
  FOR(u,1,n) if(el[u].F != -1 && el[u].F < fel.back()[0] && el[u].S > fel.back()[1])
    fel.pb({el[u].F, el[u].S, id});

  id = 0;
  del.rsz(sz(fel));
  for(auto it = fel.begin(); it != fel.end(); ++it)
    del[id++] = mp(INF, it);
  for(auto it = fel.begin(); next(it) != fel.end(); ++it)
    upd_el(it);

  int i = n+1;
  while(i <= q) {
    if(evt.empty()) {
      incl(fel.front()[0], fel.front()[1], i - n, q + 1 - i);
      i = INF;
      break;
    }
    auto [nxi,id] = evt.top(); evt.pop();
    if(nxi > del[id].F) continue;
    if(i < nxi) {
      incl(fel.front()[0], fel.front()[1], i - n, min(nxi,q+1) - i);
      i = nxi;
    }
    auto it = fel.erase(del[id].S);
    if(it != fel.begin())
      upd_el(prev(it));
  }

  cout << ans << '\n';
}

int main() {
  ios_base::sync_with_stdio(0); cin.tie(0);

  solve();
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int,int> pi;
typedef vector<pi> vpi;
typedef array<int,3> ai3;
typedef list<ai3> lai3;
typedef lai3::iterator lai3it;

#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define FORN(i,a,b) for (int i = (a); i <= (b); ++i)
#define F0RN(i,a) FORN(i,0,a)
#define TRAP(a,b,x) for (auto& [a,b]: (x))
#define NEG(a,n) memset((a),-1,(n)*sizeof((a)[0]))

#define pb push_back
#define eb emplace_back
#define ep emplace
#define mp make_pair
#define rsz resize
#define sz(x) int((x).size())
#define F first
#define S second

const int MX = 2e3+5, MOD = 1e9+7, INF = INT_MAX;

int n, m, q;
vpi adj[MX];
int E[MX][3];

int dp[MX][MX];

pi el[MX];
lai3 fel;
vector<pair<int,lai3it>> del;
priority_queue<pi,vpi,greater<pi>> evt;

ll ans;

template<typename T>
void inline upmx(T &x, T y) {
  if(y > x) x = y;
}

template<typename T>
void inc(T x) {
  if(x > MOD) x %= MOD;
  ans += x;
  if(ans >= MOD) ans -= MOD;
}

void incl(int b, int m, int st, int nt) {
  if(nt <= 0) return;
  ll a = (ll(m) * st + b) % MOD;
  inc((a * nt) % MOD);
  ll t3 = (ll(nt) * (nt-1) / 2) % MOD;
  t3 = (t3 * m) % MOD;
  inc(t3);
}

void upd_el(lai3it it) {
  auto nxt = next(it);
  ll b1 = (*it)[0], b2 = (*nxt)[0];
  ll m1 = (*it)[1], m2 = (*nxt)[1];
  int t = (b1 - b2 + m2 - m1 - 1) / (m2 - m1) + n;
  int id = (*it)[2];
  if(t < del[id].F) {
    del[id].F = t;
    evt.ep(t, id);
  }
}

void solve() {
  cin >> n >> m >> q;
  F0R(j,m) {
    int u, v, w;
    cin >> u >> v >> w;
    adj[u].eb(v, w);
    adj[v].eb(u, w);
    E[j][0] = u;
    E[j][1] = v;
    E[j][2] = w;
  }
//  if(E[2][0] == 3 && E[2][1] == 4 && E[2][2] == 4) {
//    FOR(i,39,40) {
//      F0R(j,50) if(50*i+j < m) cout << E[50*i+j][2] << ' ';
//      cout << '\n';
//    }
//    return;
//  }

  F0R(i,n+1) NEG(dp[i],n+1);
  dp[0][1] = 0;
  F0R(i,n) {
    FORN(u,1,n) if(dp[i][u] != -1) TRAP(v,w,adj[u])
      upmx(dp[i+1][v], dp[i][u] + w);
    int mxi = 0;
    FORN(u,1,n) upmx(mxi, dp[i+1][u]);
    inc(mxi);
    if(q == i+1) {
      cout << ans << '\n';
      return;
    }
  }

  FORN(u,1,n) {
    int bw = 0;
    TRAP(v,w,adj[u]) upmx(bw,w);
    el[u-1].F = dp[n][u];
    el[u-1].S = bw;
  }
  sort(el,el+n,greater<pi>());
  int id = 0;
  fel.pb({el[0].F, el[0].S, id++});
  FOR(u,1,n) if(el[u].F != -1 && el[u].F < fel.back()[0] && el[u].S > fel.back()[1])
    fel.pb({el[u].F, el[u].S, id});
  if(E[2][0] == 3 && E[2][1] == 4 && E[2][2] == 4) {
    cout << sz(fel) << '\n';
    auto it = fel.rbegin();
    while(it != fel.rend()) {
      cout << (*it)[0] << ' ' << (*it)[1] << '\n';
    }
  }

  id = 0;
  del.rsz(sz(fel));
  for(auto it = fel.begin(); it != fel.end(); ++it)
    del[id++] = mp(INF, it);
  for(auto it = fel.begin(); next(it) != fel.end(); ++it)
    upd_el(it);

  int i = n+1;
  while(i <= q) {
    if(evt.empty()) {
      incl(fel.front()[0], fel.front()[1], i - n, q + 1 - i);
      i = INF;
      break;
    }
    auto [nxi,id] = evt.top(); evt.pop();
    if(nxi > del[id].F) continue;
    if(i < nxi) {
      incl(fel.front()[0], fel.front()[1], i - n, min(nxi,q+1) - i);
      i = nxi;
    }
    auto it = fel.erase(del[id].S);
    if(it != fel.begin())
      upd_el(prev(it));
  }

  cout << ans << '\n';
}

int main() {
  ios_base::sync_with_stdio(0); cin.tie(0);

  solve();
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef array<int,3> triple;

#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define FORN(i,a,b) for (int i = (a); i <= (b); ++i)
#define F0RN(i,a) FORN(i,0,a)
#define ROF(i,a,b) for (int i = (b)-1; i >= (a); --i)
#define R0F(i,a) ROF(i,0,a)
#define TRAV(a,x) for (auto& a: (x))
#define TRAP(a,b,x) for (auto& [a,b]: (x))
#define ALL(x) (x).begin(), (x).end()
#define ZERO(a,n) memset((a),0,(n)*sizeof((a)[0]))
#define NEG(a,n) memset((a),-1,(n)*sizeof((a)[0]))

const int MX = 2e3+5, MOD = 1e9+7, INF = INT_MAX;

int n, m, q;
vector<pair<int,int>> adjacency_graph[MX];

// dp[i][u] represents the maximum weight of paths to u with i edges/steps
int max_level, level[MX], dp[MX][MX];

// edge_lines represents the linear equation represented by looping along
// some edge (u, v, w) with the pair (b, m) for a y = mx + b equation
// path_weight = w * (i - max_level) + (max_weight_to_edge + w * (max_level - level[u]))
// where u is the vertex that's at a higher level or higher max weight path
// note that edge_lines are 0-indexed
pair<int,int> edge_lines[MX];
// filtered_edge_lines is a triple of integers (intercept, slope, ID)
// where redundant ones are removed so only considers a sequence where at i = l,
// the edge lines are in strictly decreasing order of intercept value
// and stricly increasing order of slope
list<triple> filtered_edge_lines;
// deletion_table is a mapping from ID -> (deletion time, iterator)
// where deletion time is the path length value i at which it will be surpassed
// by some line below it and iterator points to its location in the list
vector<pair<int,list<triple>::iterator>> deletion_table;
// events is the min-heap priority queue of deletion events
// with pairs (deletion time, ID)
priority_queue<pair<int,int>,
        vector<pair<int,int>>,
       greater<pair<int,int>>> events;

ll answer;

template<typename T>
void inline update_maximum(T &x, T y) {
  if(y > x) x = y;
}

template<typename T>
void increment_answer(T x) {
  if(x > MOD) x %= MOD;
  answer += x;
  if(answer >= MOD) answer -= MOD;
}

void increment_by_edge_line(int b, int m, int start, int num_terms) {
  if(num_terms <= 0) return;
  ll a = (ll(m) * start) % MOD;
  a = (a + b) % MOD;
  increment_answer((a * num_terms) % MOD);
  ll t3 = (ll(num_terms) * (num_terms-1) / 2) % MOD;
  t3 = (t3 * m) % MOD;
  increment_answer(t3);
}

// update_deletion_event takes an iterator to the filtered edge lines list
// and considers the following edge line surpassing it for a deletion event
// at their intersection points, rounding up.
void update_deletion_event(list<triple>::iterator it) {
  auto nxt = next(it);
  ll b1 = (*it)[0], b2 = (*nxt)[0];
  ll m1 = (*it)[1], m2 = (*nxt)[1];
  int t = (b1 - b2 + m2 - m1 - 1) / (m2 - m1) + max_level;
  if(t < deletion_table[(*it)[2]].first) {
    deletion_table[(*it)[2]].first = t;
    events.emplace(t, (*it)[2]);
//cout << "Inserted deletion of " << (*it)[2] << " at time " << t << '\n';
  }
}

void solve() {
  cin >> n >> m >> q;
  NEG(level,n+1);
  F0R(j,m) {
    int u, v, w;
    cin >> u >> v >> w;
    adjacency_graph[u].emplace_back(v, w);
    adjacency_graph[v].emplace_back(u, w);
  }

  // Perform a bfs to compute the levels of each node
  max_level = 0; level[1] = 0;
  queue<int> bfs; bfs.push(1);
  while(!bfs.empty()) {
    int u = bfs.front(); bfs.pop();
    max_level = level[u];
    TRAP(v,w,adjacency_graph[u])
      if(level[v] == -1) {
        level[v] = level[u] + 1;
        bfs.push(v);
      }
  }

  // Compute the greatest weight path for lengths i = 1 to i = max_level
  F0R(i,max_level+1) NEG(dp[i],n+1);
  dp[0][1] = 0;
  F0R(i,max_level) {
    int max_weight_for_level = 0;
    FORN(u,1,n) if(dp[i][u] != -1) TRAP(v,w,adjacency_graph[u]) {
      update_maximum(dp[i+1][v], dp[i][u] + w);
      if(i < q) update_maximum(max_weight_for_level, dp[i+1][v]);
    }
    if(i < q) increment_answer(max_weight_for_level);
    if(q == i+1) {
      cout << answer << '\n';
      return;
    }
  }

  // Get the best edge for an edge line for each vertex
  FORN(u,1,n) {
    int best_w = 0;
    TRAP(v,w,adjacency_graph[u])
      if(w > best_w) best_w = w;
    // edge_lines will be 0-indexed instead of 1-indexed
    edge_lines[u-1].first = dp[level[u]][u] + (max_level - level[u]) * best_w;
    edge_lines[u-1].second = best_w;
  }

  // Filter the edge lines to remove the redundant ones and make it
  // strictly decreasing for the intercept (first element) and
  // strictly increasing for the slope/weight of the edge (second element)
  // intercept = maximum weight to get to the edge plus any remaining extra
  // steps along the edge until max_level steps are taken
  sort(edge_lines,edge_lines+n,greater<pair<int,int>>());
//cout << "Sorted edge lines:\n";
//F0RN(i,n) cout << edge_lines[i].first << ' ' << edge_lines[i].second << '\n'; cout << '\n';
  filtered_edge_lines.push_back({edge_lines[0].first, edge_lines[0].second, 0});
  FOR(i,1,n)
    if(edge_lines[i].first < filtered_edge_lines.back()[0]
        && edge_lines[i].second > filtered_edge_lines.back()[1])
      filtered_edge_lines.push_back({
        edge_lines[i].first,
        edge_lines[i].second,
        filtered_edge_lines.back()[2]+1
      });

//cout << "Filtered edge lines:\n";
//TRAV(f,filtered_edge_lines) cout << f[0] << ' ' << f[1] << ' ' << f[2] << '\n'; cout << '\n';
  deletion_table.resize(int(filtered_edge_lines.size()));
  for(auto it = filtered_edge_lines.begin(); it != filtered_edge_lines.end(); ++it)
    deletion_table[(*it)[2]] = make_pair(INF, it);
  // Process adjacent deletion events in the initial list
  for(auto it = filtered_edge_lines.begin(); next(it) != filtered_edge_lines.end(); ++it)
    update_deletion_event(it);
//F0R(id,int(deletion_table.size())) cout << "Deleting " << id << " at time " << del[id].F << '\n';
  // i represents the path length that we are currently processing but we
  // have not yet finished processing
  int i = max_level + 1;
//cout << "Maximum level: " << max_level << '\n';
//cout << "Answer so far: " << answer << '\n';
  while(i <= q) {
    if(events.empty()) {
      increment_by_edge_line(
        filtered_edge_lines.front()[0],
        filtered_edge_lines.front()[1],
        i - max_level, q + 1 - i);
      i = INF;
      break;
    }
//cout << "Popping line " << events.top().second << " at time " << events.top().first << '\n';
    auto [next_i,id] = events.top(); events.pop();
    // if the time for the deletion event is after the deletion for edge line
    // with id, then it's a stale event so ignore it and process the next event
    if(next_i > deletion_table[id].first) continue;
    // if the next_i is greater than our current i, then increment the answer
    // because the current edge line at the front or top is the greatest one
    // from i until next_i (exclusive). If i == next_i, then we're not done
    // processing deletion events yet so we're not exactly sure which edge line
    // is currently the highest one at the front.
    if(i < next_i) {
      increment_by_edge_line(
        filtered_edge_lines.front()[0],
        filtered_edge_lines.front()[1],
        i - max_level, min(next_i,q+1) - i);
      i = next_i;
    }
    // erase returns an iterator to the next element following the element that
    // got deleted. This next element can surpass the one that becomes before
    // or above it so queue up another deletion event.
    auto it = filtered_edge_lines.erase(deletion_table[id].second);
    if(it != filtered_edge_lines.begin())
      update_deletion_event(prev(it));
  }

  cout << answer << '\n';
}

int main() {
  ios_base::sync_with_stdio(0); cin.tie(0);

  solve();
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef array<int,3> triple;

#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define F0R(i,a) FOR(i,0,a)
#define FORN(i,a,b) for (int i = (a); i <= (b); ++i)
#define F0RN(i,a) FORN(i,0,a)
#define ROF(i,a,b) for (int i = (b)-1; i >= (a); --i)
#define R0F(i,a) ROF(i,0,a)
#define TRAV(a,x) for (auto& a: (x))
#define TRAP(a,b,x) for (auto& [a,b]: (x))
#define ALL(x) (x).begin(), (x).end()
#define ZERO(a,n) memset((a),0,(n)*sizeof((a)[0]))
#define NEG(a,n) memset((a),-1,(n)*sizeof((a)[0]))

const int MX = 2e3+5, MOD = 1e9+7, INF = INT_MAX;

int n, m, q;
vector<pair<int,int>> adjacency_graph[MX];

// dp[i][u] represents the maximum weight of paths to u with i edges/steps
ll dp[MX][MX];

// edge_lines represents the linear equation represented by looping along
// some edge (u, v, w) with the pair (b, m) for a y = mx + b equation
// path_weight = w * (i - max_level) + (max_weight_to_edge + w * (max_level - level[u]))
// where u is the vertex that's at a higher level or higher max weight path
// note that edge_lines are 0-indexed
pair<ll,ll> edge_lines[MX];
// filtered_edge_lines is a triple of integers (intercept, slope, ID)
// where redundant ones are removed so only considers a sequence where at i = l,
// the edge lines are in strictly decreasing order of intercept value
// and stricly increasing order of slope
vector<pair<ll,ll>> filtered_edge_lines;
// deletion_table is a mapping from ID -> (deletion time, iterator)
// where deletion time is the path length value i at which it will be surpassed
// by some line below it and iterator points to its location in the list
vector<pair<int,list<triple>::iterator>> deletion_table;
// events is the min-heap priority queue of deletion events
// with pairs (deletion time, ID)
priority_queue<pair<int,int>,
        vector<pair<int,int>>,
       greater<pair<int,int>>> events;

ll answer;

template<typename T>
void inline update_maximum(T &x, T y) {
  if(y > x) x = y;
}

template<typename T>
void increment_answer(T x) {
  if(x > MOD) x %= MOD;
  answer += x;
  if(answer >= MOD) answer -= MOD;
}

void increment_by_edge_line(ll b, ll m, ll start, ll num_terms) {
  if(num_terms <= 0) return;
  ll a = (ll(m) * start) % MOD;
  a = (a + b) % MOD;
  increment_answer((a * num_terms) % MOD);
  ll t3 = (ll(num_terms) * (num_terms-1) / 2) % MOD;
  t3 = (t3 * m) % MOD;
  increment_answer(t3);
}

ll edge_line_value(pair<ll,ll> edge_line, ll path_length) {
  return edge_line.second * (path_length - n) + edge_line.first;
}

bool edge_line_less(pair<ll,ll> a, pair<ll,ll> b, ll path_length) {
  return edge_line_value(a, path_length) < edge_line_value(b, path_length);
}

bool edge_line_greater(pair<ll,ll> a, pair<ll,ll> b, ll path_length) {
  return edge_line_value(a, path_length) > edge_line_value(b, path_length);
}

ll edge_line_intersection(pair<ll,ll> a, pair<ll,ll> b) {
  if(a.second == b.second) return -1;
  if(a.second < b.second) swap(a,b);
  if(a.first > b.first) return -1;
  ll b1 = a.first, m1 = a.second;
  ll b2 = b.first, m2 = b.second;
  return (b2 - b1) / (m1 - m2) + n;
}

void solve() {
  cin >> n >> m >> q;
  F0R(j,m) {
    int u, v, w;
    cin >> u >> v >> w;
    adjacency_graph[u].emplace_back(v, w);
    adjacency_graph[v].emplace_back(u, w);
  }

  // Compute the greatest weight path for lengths i = 1 to i = m
  F0R(i,n+1) NEG(dp[i],n+1);
  dp[0][1] = 0;
  F0R(i,n) {
    ll max_weight_for_level = 0;
    FORN(u,1,n) if(dp[i][u] != -1) TRAP(v,w,adjacency_graph[u]) {
      update_maximum(dp[i+1][v], dp[i][u] + w);
      if(i+1 <= q) update_maximum(max_weight_for_level, dp[i+1][v]);
    }
    if(i+1 <= q) increment_answer(max_weight_for_level);
    if(q == i+1) {
      cout << answer << '\n';
      return;
    }
  }

  // Get the best edge for an edge line for each vertex
  FORN(u,1,n) {
    int best_w = 0;
    TRAP(v,w,adjacency_graph[u])
      if(w > best_w) best_w = w;
    // edge_lines will be 0-indexed instead of 1-indexed
    edge_lines[u-1].first = dp[n][u];
    edge_lines[u-1].second = best_w;
  }

  // Filter the edge lines to remove the redundant ones and make it
  // strictly decreasing for the intercept (first element) and
  // strictly increasing for the slope/weight of the edge (second element)
  // intercept = maximum weight to get to the edge plus any remaining extra
  // steps along the edge until max_level steps are taken
  sort(edge_lines,edge_lines+n,greater<pair<ll,ll>>());
//cout << "Sorted edge lines:\n";
//F0RN(i,n) cout << edge_lines[i].first << ' ' << edge_lines[i].second << '\n'; cout << '\n';
  filtered_edge_lines.push_back(edge_lines[0]);
  FOR(i,1,n)
    if(edge_lines[i].first != -1
        && edge_lines[i].first < filtered_edge_lines.back().first
        && edge_lines[i].second > filtered_edge_lines.back().second)
      filtered_edge_lines.push_back(edge_lines[i]);

  // i represents the path length that we are currently processing but we
  // have not yet finished processing
  ll i = n + 1;
//cout << "Maximum level: " << max_level << '\n';
//cout << "Answer so far: " << answer << '\n';
  while(i <= q) {
    int highest_id = 0;
    F0R(j,int(filtered_edge_lines.size()))
      if(edge_line_greater(filtered_edge_lines[j], filtered_edge_lines[highest_id], i))
        highest_id = j;
    ll earliest_intersection = q;
    F0R(j,int(filtered_edge_lines.size()))
      if(j != highest_id) {
        ll t = edge_line_intersection(
          filtered_edge_lines[highest_id],
          filtered_edge_lines[j]);
        if(t >= i && t < earliest_intersection)
          earliest_intersection = t;
      }
    increment_by_edge_line(
      filtered_edge_lines[highest_id].first,
      filtered_edge_lines[highest_id].second,
      i - n, earliest_intersection - i + 1);
    i = earliest_intersection + 1;
  }

  cout << answer << '\n';
}

int main() {
  ios_base::sync_with_stdio(0); cin.tie(0);

  solve();
}


#include <iostream>
#include <algorithm>
#include <string>
#include <sstream>
#include <vector>
#include <set>
#include <cmath>
#include <unordered_map>
#include <queue>
#include <map>
#include <functional>
#include <stack>
#include <cmath>
#include <cstring>
#include <random>
#include <chrono>
#include <memory>
#include <cassert>
#include <numeric>
#include <iomanip>
#include <array>
#define int long long
#define pic pair<int, char>
#define x first
#define y second
#define ll long long
#define pii pair<long long, long long>
#define endl "\n"
#define all(a) (a).begin(), (a).end()
#pragma GCC optimize ("O3")
#define PI 3.14159265
#define pdd pair<double, double>
#define rect pair<pii, pii>

using namespace std;

const int N = 3e5 + 14;
const int inf = (int)1e18 + 10;
const int mod = 1e9 + 7;
const double eps = 1e-6;

mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());

using namespace std;

int n, m, q;
vector<pii> g[N];
int dp[N][N]; // len, v

int calc(int x)
{
	int v1 = x;
	int v2 = x + 1;

	if (v1 % 2 == 0)
		v1 /= 2;
	else
		v2 /= 2;

	return v1 * v2 % mod;
}

int32_t main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cout.precision(20);

	cin >> n >> m >> q;

	int mxw = 0;

	for (int i = 0; i < m; ++i)
	{
		int v, u, w;

		cin >> v >> u >> w;

		--v; --u;
		g[v].emplace_back(u, w);
		g[u].emplace_back(v, w);
		mxw = max(mxw, w);
	}

	for (int i = 0; i < N; ++i)
		for (int j = 0; j < N; ++j)
			dp[i][j] = -inf;

	dp[0][0] = 0;

	int ans = 0;

	for (int i = 1; i < N; ++i)
	{
		for (int j = 0; j < n; ++j)
			if(dp[i - 1][j] != -inf)
				for (auto p : g[j])
					dp[i][p.x] = max(dp[i][p.x], dp[i - 1][j] + p.y);

		int mx = 0;

		for (int j = 0; j < n; ++j)
			mx = max(mx, dp[i][j]);

		ans = (ans + mx) % mod;
		--q;

		if (!q)
			break;
	}

	if (q)
	{
		int mx2 = 0;

		for (int i = 0; i < n; ++i)
			mx2 = max(dp[N - 1][i], mx2);

		int cst = mxw;

		ans = (ans + mx2 * q % mod + calc(q) % mod * cst % mod) % mod;
	}

	cout << ans << endl;
}


#include <iostream>
#include <algorithm>
#include <string>
#include <sstream>
#include <vector>
#include <set>
#include <cmath>
#include <unordered_map>
#include <queue>
#include <map>
#include <functional>
#include <stack>
#include <cmath>
#include <cstring>
#include <random>
#include <chrono>
#include <memory>
#include <cassert>
#include <numeric>
#include <iomanip>
#include <array>
#define int long long
#define pic pair<int, char>
#define x first
#define y second
#define ll long long
#define pii pair<long long, long long>
#define endl "\n"
#define all(a) (a).begin(), (a).end()
#pragma GCC optimize ("O3")
#define PI 3.14159265
#define pdd pair<double, double>
#define rect pair<pii, pii>

using namespace std;

const int N = 7e3 + 14;
const int inf = (int)1e18 + 10;
const int mod = 1e9 + 7;
const double eps = 1e-6;

mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());

using namespace std;

int n, m, q;
vector<pii> g[N];
int dp[N][N]; // len, v

int calc(int x)
{
	int v1 = x;
	int v2 = x + 1;

	if (v1 % 2 == 0)
		v1 /= 2;
	else
		v2 /= 2;

	return v1 * v2 % mod;
}

int32_t main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cout.precision(20);

	cin >> n >> m >> q;

	int mxw = 0;

	for (int i = 0; i < m; ++i)
	{
		int v, u, w;

		cin >> v >> u >> w;

		--v; --u;
		g[v].emplace_back(u, w);
		g[u].emplace_back(v, w);
		mxw = max(mxw, w);
	}

	for (int i = 0; i < N; ++i)
		for (int j = 0; j < N; ++j)
			dp[i][j] = -inf;

	dp[0][0] = 0;

	int ans = 0;

	for (int i = 1; i < N; ++i)
	{
		for (int j = 0; j < n; ++j)
			if(dp[i - 1][j] != -inf)
				for (auto p : g[j])
					dp[i][p.x] = max(dp[i][p.x], dp[i - 1][j] + p.y);

		int mx = 0;

		for (int j = 0; j < n; ++j)
			mx = max(mx, dp[i][j]);

		ans = (ans + mx) % mod;
		--q;

		if (!q)
			break;
	}

	if (q)
	{
		int mx2 = 0;

		for (int i = 0; i < n; ++i)
			mx2 = max(dp[N - 1][i], mx2);

		int cst = mxw;

		ans = (ans + mx2 * q % mod + calc(q) % mod * cst % mod) % mod;
	}

	cout << ans << endl;
}


#include <iostream>
#include <algorithm>
#include <string>
#include <sstream>
#include <vector>
#include <set>
#include <cmath>
#include <unordered_map>
#include <queue>
#include <map>
#include <functional>
#include <stack>
#include <cmath>
#include <cstring>
#include <random>
#include <chrono>
#include <memory>
#include <cassert>
#include <numeric>
#include <iomanip>
#include <array>
#define int long long
#define pic pair<int, char>
#define x first
#define y second
#define ll long long
#define pii pair<long long, long long>
#define endl "\n"
#define all(a) (a).begin(), (a).end()
#pragma GCC optimize ("O3")
#define PI 3.14159265
#define pdd pair<double, double>
#define rect pair<pii, pii>

using namespace std;

const int N = 3e3 + 14;
const int inf = (int)1e18 + 10;
const int mod = 1e9 + 7;
const double eps = 1e-6;

mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());

using namespace std;

int n, m, q;
vector<pii> g[N];
int dp[N][N]; // len, v

int calc(int x)
{
	int v1 = x;
	int v2 = x + 1;

	if (v1 % 2 == 0)
		v1 /= 2;
	else
		v2 /= 2;

	return v1 * v2 % mod;
}

int32_t main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cout.precision(20);

	cin >> n >> m >> q;

	int mxw = 0;

	for (int i = 0; i < m; ++i)
	{
		int v, u, w;

		cin >> v >> u >> w;

		--v; --u;
		g[v].emplace_back(u, w);
		g[u].emplace_back(v, w);
		mxw = max(mxw, w);
	}

	for (int i = 0; i < N; ++i)
		for (int j = 0; j < N; ++j)
			dp[i][j] = -inf;

	dp[0][0] = 0;

	int ans = 0;

	for (int i = 1; i < N; ++i)
	{
		for (int j = 0; j < n; ++j)
			if(dp[i - 1][j] != -inf)
				for (auto p : g[j])
					dp[i][p.x] = max(dp[i][p.x], dp[i - 1][j] + p.y);

		int mx = 0;

		for (int j = 0; j < n; ++j)
			mx = max(mx, dp[i][j]);

		ans = (ans + mx) % mod;
		--q;

		if (!q)
			break;
	}

	if (q)
	{
		int mx2 = 0;

		for (int i = 0; i < n; ++i)
			mx2 = max(dp[N - 1][i], mx2);

		int cst = mxw;

		ans = (ans + mx2 * q % mod + calc(q) % mod * cst % mod) % mod;
	}

	cout << ans << endl;
}


#include <iostream>
#include <algorithm>
#include <string>
#include <sstream>
#include <vector>
#include <set>
#include <cmath>
#include <unordered_map>
#include <queue>
#include <map>
#include <functional>
#include <stack>
#include <cmath>
#include <cstring>
#include <random>
#include <chrono>
#include <memory>
#include <cassert>
#include <numeric>
#include <iomanip>
#include <array>
#define int long long
#define pic pair<int, char>
#define x first
#define y second
#define ll long long
#define pii pair<long long, long long>
#define endl "\n"
#define all(a) (a).begin(), (a).end()
#pragma GCC optimize ("O3")
#define PI 3.14159265
#define pdd pair<double, double>
#define rect pair<pii, pii>

using namespace std;

const int N = 6e3 + 14;
const int inf = (int)1e18 + 10;
const int mod = 1e9 + 7;
const double eps = 1e-6;

mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());

using namespace std;

int n, m, q;
vector<pii> g[N];
int dp[N][N]; // len, v

int calc(int x)
{
	int v1 = x;
	int v2 = x + 1;

	if (v1 % 2 == 0)
		v1 /= 2;
	else
		v2 /= 2;

	return v1 * v2 % mod;
}

int32_t main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cout.precision(20);

	cin >> n >> m >> q;

	int mxw = 0;

	for (int i = 0; i < m; ++i)
	{
		int v, u, w;

		cin >> v >> u >> w;

		--v; --u;
		g[v].emplace_back(u, w);
		g[u].emplace_back(v, w);
		mxw = max(mxw, w);
	}

	for (int i = 0; i < N; ++i)
		for (int j = 0; j < N; ++j)
			dp[i][j] = -inf;

	dp[0][0] = 0;

	int ans = 0;

	for (int i = 1; i < N; ++i)
	{
		for (int j = 0; j < n; ++j)
			if(dp[i - 1][j] != -inf)
				for (auto p : g[j])
					dp[i][p.x] = max(dp[i][p.x], dp[i - 1][j] + p.y);

		int mx = 0;

		for (int j = 0; j < n; ++j)
			mx = max(mx, dp[i][j]);

		ans = (ans + mx) % mod;
		--q;

		if (!q)
			break;
	}

	if (q)
	{
		int mx2 = 0;

		for (int i = 0; i < n; ++i)
			mx2 = max(dp[N - 1][i], mx2);

		int cst = mxw;

		ans = (ans + mx2 * q % mod + calc(q) % mod * cst % mod) % mod;
	}

	cout << ans << endl;
}


#include <iostream>
#include <algorithm>
#include <string>
#include <sstream>
#include <vector>
#include <set>
#include <cmath>
#include <unordered_map>
#include <queue>
#include <map>
#include <functional>
#include <stack>
#include <cmath>
#include <cstring>
#include <random>
#include <chrono>
#include <memory>
#include <cassert>
#include <numeric>
#include <iomanip>
#include <array>
#define int long long
#define pic pair<int, char>
#define x first
#define y second
#define ll long long
#define pii pair<long long, long long>
#define endl "\n"
#define all(a) (a).begin(), (a).end()
#pragma GCC optimize ("O3")
#define PI 3.14159265
#define pdd pair<double, double>
#define rect pair<pii, pii>

using namespace std;

const int N = 3e3 + 14;
const int inf = (int)1e18 + 10;
const int mod = 1e9 + 7;
const double eps = 1e-6;

mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());

using namespace std;

int n, m, q;
vector<pii> g[N];
int dp[N][N]; // len, v

int calc(int x)
{
	int v1 = x;
	int v2 = x + 1ll;

	if (v1 % 2ll == 0ll)
		v1 /= 2ll;
	else
		v2 /= 2ll;

	return v1 * v2 % mod;
}

int32_t main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cout.precision(20);

	cin >> n >> m >> q;

	for (int i = 0; i < m; ++i)
	{
		int v, u, w;

		cin >> v >> u >> w;

		--v; --u;
		g[v].emplace_back(u, w);
		g[u].emplace_back(v, w);
	}

	for (int i = 0; i < N; ++i)
		for (int j = 0; j < N; ++j)
			dp[i][j] = -inf;

	dp[0][0] = 0;

	int ans = 0;

	for (int i = 1; i < N; ++i)
	{
		for (int j = 0; j < n; ++j)
			if(dp[i - 1][j] != -inf)
				for (auto p : g[j])
					dp[i][p.x] = max(dp[i][p.x], dp[i - 1][j] + p.y);

		if (i + 1 == N)
			break;

		int mx = 0;

		for (int j = 0; j < n; ++j)
			mx = max(mx, dp[i][j]);

		ans = (ans + mx) % mod;
		--q;

		if (!q)
			break;
	}

	if (q)
	{
		vector<pii> v;

		for (int i = 0; i < n; ++i)
		{
			int mxw = 0;

			for (auto u : g[i])
				mxw = max(mxw, u.y);

			v.emplace_back(dp[N - 1][i], mxw);
		}

		while (q)
		{
			int mx = 0;

			for (int i = 0; i < n; ++i)
				mx = max(mx, v[i].x);

			int mxe = 0;

			for (int i = 0; i < n; ++i)
				if (v[i].x == mx)
					mxe = max(mxe, v[i].y);

			int glcnt = inf;

			for(int i = 0; i < n; ++i)
				if (v[i].x != mx)
				{
					if (mxe - v[i].y == 0)
						continue;

					int cnt = (v[i].x - mx) / (mxe - v[i].y);

					if (cnt < 0)
						continue;

					glcnt = min(glcnt, cnt);
				}

			if (glcnt == inf)
			{
				ans = (ans + mx % mod * q % mod + calc(q - 1) * mxe % mod) % mod;
				break;
			}

			glcnt = min(q, glcnt + 1);

			ans = (ans + mx % mod * glcnt % mod + calc(glcnt - 1) * mxe % mod) % mod;
			q -= glcnt;

			for (int i = 0; i < n; ++i)
				v[i].x += v[i].y * glcnt;
		}
	}

	cout << ans << endl;
}

// a1 + b1 * cnt = a2 + b2 * cnt
// cnt * (b1 - b2) = a2 - a1
// cnt = (a2 - a1) / (b1 - b2)
// a1 = 1 b1 = 3 a2 = 2 b2 = 1


#include <iostream>
#include <algorithm>
#include <string>
#include <sstream>
#include <vector>
#include <set>
#include <cmath>
#include <unordered_map>
#include <queue>
#include <map>
#include <functional>
#include <stack>
#include <cmath>
#include <cstring>
#include <random>
#include <chrono>
#include <memory>
#include <cassert>
#include <numeric>
#include <iomanip>
#include <array>
#define int long long
#define pic pair<int, char>
#define x first
#define y second
#define ll long long
#define pii pair<long long, long long>
#define endl "\n"
#define all(a) (a).begin(), (a).end()
#pragma GCC optimize ("O3")
#define PI 3.14159265
#define pdd pair<double, double>
#define rect pair<pii, pii>

using namespace std;

const int N = 3e3 + 14;
const int inf = (int)1e18 + 10;
const int mod = 1e9 + 7;
const double eps = 1e-6;

mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());

using namespace std;

int n, m, q;
vector<pii> g[N];
int dp[N][N]; // len, v

int32_t main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cout.precision(20);

	cin >> n >> m >> q;

	for (int i = 0; i < m; ++i)
	{
		int v, u, w;

		cin >> v >> u >> w;

		--v; --u;
		g[v].emplace_back(u, w);
		g[u].emplace_back(v, w);
	}

	for (int i = 0; i < N; ++i)
		for (int j = 0; j < N; ++j)
			dp[i][j] = -inf;

	dp[0][0] = 0;

	int ans = 0;

	for (int i = 1; i <= m + 5; ++i)
	{
		for (int j = 0; j < n; ++j)
			for (auto p : g[j])
				dp[i][p.x] = max(dp[i][p.x], dp[i - 1][j] + p.y);

		int mx = 0;

		for (int j = 0; j < n; ++j)
			mx = max(mx, dp[i][j]);

		ans = (ans + mx) % mod;
		--q;

		if (!q)
			break;
	}

	if (q)
	{
		int mx1 = 0;
		int mx2 = 0;

		for (int i = 0; i < n; ++i)
		{
			mx1 = max(dp[m + 4][i], mx1);
			mx2 = max(dp[m + 5][i], mx2);
		}

		int cst = mx2 - mx1;

		ans = (ans + mx2 * q % mod + (q * (q + 1) / 2) % mod * cst % mod) % mod;
	}

	cout << ans << endl;
}


#include <iostream>
#include <algorithm>
#include <string>
#include <sstream>
#include <vector>
#include <set>
#include <cmath>
#include <unordered_map>
#include <queue>
#include <map>
#include <functional>
#include <stack>
#include <cmath>
#include <cstring>
#include <random>
#include <chrono>
#include <memory>
#include <cassert>
#include <numeric>
#include <iomanip>
#include <array>
#define int long long
#define pic pair<int, char>
#define x first
#define y second
#define ll long long
#define pii pair<long long, long long>
#define endl "\n"
#define all(a) (a).begin(), (a).end()
#pragma GCC optimize ("O3")
#define PI 3.14159265
#define pdd pair<double, double>
#define rect pair<pii, pii>

using namespace std;

const int N = 3e3 + 14;
const int inf = (int)1e18 + 10;
const int mod = 1e9 + 7;
const double eps = 1e-6;

mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());

using namespace std;

int n, m, q;
vector<pii> g[N];
int dp[N][N]; // len, v

int calc(int x)
{
	int v1 = x;
	int v2 = x + 1;

	if (v1 % 2 == 0)
		v1 /= 2;
	else
		v2 /= 2;

	return v1 * v2 % mod;
}

int32_t main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cout.precision(20);

	cin >> n >> m >> q;

	for (int i = 0; i < m; ++i)
	{
		int v, u, w;

		cin >> v >> u >> w;

		--v; --u;
		g[v].emplace_back(u, w);
		g[u].emplace_back(v, w);
	}

	for (int i = 0; i < N; ++i)
		for (int j = 0; j < N; ++j)
			dp[i][j] = -inf;

	dp[0][0] = 0;

	int ans = 0;

	for (int i = 1; i < N; ++i)
	{
		for (int j = 0; j < n; ++j)
			for (auto p : g[j])
				dp[i][p.x] = max(dp[i][p.x], dp[i - 1][j] + p.y);

		int mx = 0;

		for (int j = 0; j < n; ++j)
			mx = max(mx, dp[i][j]);

		ans = (ans + mx) % mod;
		--q;

		if (!q)
			break;
	}

	if (q)
	{
		int mx1 = 0;
		int mx2 = 0;

		for (int i = 0; i < n; ++i)
		{
			mx1 = max(dp[N - 2][i], mx1);
			mx2 = max(dp[N - 1][i], mx2);
		}

		int cst = mx2 - mx1;

		ans = (ans + mx2 * q % mod + calc(q) % mod * cst % mod) % mod;
	}

	cout << ans << endl;
}


#include <iostream>
#include <algorithm>
#include <string>
#include <sstream>
#include <vector>
#include <set>
#include <cmath>
#include <unordered_map>
#include <queue>
#include <map>
#include <functional>
#include <stack>
#include <cmath>
#include <cstring>
#include <random>
#include <chrono>
#include <memory>
#include <cassert>
#include <numeric>
#include <iomanip>
#include <array>
#define int long long
#define pic pair<int, char>
#define x first
#define y second
#define ll long long
#define pii pair<long long, long long>
#define endl "\n"
#define all(a) (a).begin(), (a).end()
#pragma GCC optimize ("O3")
#define PI 3.14159265
#define pdd pair<double, double>
#define rect pair<pii, pii>

using namespace std;

const int N = 5e3 + 14;
const int inf = (int)1e18 + 10;
const int mod = 1e9 + 7;
const double eps = 1e-6;

mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());

using namespace std;

int n, m, q;
vector<pii> g[N];
int dp[N][N]; // len, v

int calc(int x)
{
	int v1 = x;
	int v2 = x + 1;

	if (v1 % 2 == 0)
		v1 /= 2;
	else
		v2 /= 2;

	return v1 * v2 % mod;
}

int32_t main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cout.precision(20);

	cin >> n >> m >> q;

	int mxw = 0;

	for (int i = 0; i < m; ++i)
	{
		int v, u, w;

		cin >> v >> u >> w;

		--v; --u;
		g[v].emplace_back(u, w);
		g[u].emplace_back(v, w);
		mxw = max(mxw, w);
	}

	for (int i = 0; i < N; ++i)
		for (int j = 0; j < N; ++j)
			dp[i][j] = -inf;

	dp[0][0] = 0;

	int ans = 0;

	for (int i = 1; i < N; ++i)
	{
		for (int j = 0; j < n; ++j)
			if(dp[i - 1][j] != -inf)
				for (auto p : g[j])
					dp[i][p.x] = max(dp[i][p.x], dp[i - 1][j] + p.y);

		int mx = 0;

		for (int j = 0; j < n; ++j)
			mx = max(mx, dp[i][j]);

		ans = (ans + mx) % mod;
		--q;

		if (!q)
			break;
	}

	if (q)
	{
		int mx2 = 0;

		for (int i = 0; i < n; ++i)
			mx2 = max(dp[N - 1][i], mx2);

		int cst = mxw;

		ans = (ans + mx2 * q % mod + calc(q) % mod * cst % mod) % mod;
	}

	cout << ans << endl;
}