7 9 999999999 0 3
0 1 0
1 2 0
2 3 0
0 4 1
4 1 1
1 5 499999999
5 2 499999999
2 6 1
6 3 1
 7 9 320 0 3
0 1 0
1 2 0
2 3 0
0 4 1
4 1 1
1 5 100
5 2 100
2 6 59
6 3 61
 4 5 7 0 3
0 1 0
1 2 3
2 3 0
0 2 5
1 3 5
 8 9 10 1 0
1 2 1
2 4 1
1 3 0
3 4 0
4 5 0
5 6 1
6 0 1
5 7 0
7 0 0
 4 4 14 1 3
1 3 13
2 3 0
2 0 0
1 0 12
 5 6 1000000000 0 4
0 1 1
2 0 2
3 0 3
4 1 0
4 2 0
3 4 0
 4 5 10 1 2
0 1 3
1 2 0
1 3 4
2 3 4
2 0 6
 4 4 2 1 3
1 3 13
2 3 0
2 0 0
1 0 0
 5 5 2 0 2
0 1 1
1 2 1
0 4 0
4 3 0
3 2 0
 5 5 3 0 2
0 1 1
1 2 1
0 4 0
4 3 0
3 2 0
 4 4 8 1 3
1 3 13
2 3 0
2 0 0
1 0 6
 1000 1 1000000000 998 0
0 999 0
 5 5 1 0 2
0 1 1
1 2 1
0 4 0
4 3 0
3 2 0
 100 1 123456 99 0
0 99 123456
 4 4 13 1 3
1 3 13
2 3 0
2 0 0
1 0 12
 7 9 319 0 3
0 1 0
1 2 0
2 3 0
0 4 1
4 1 1
1 5 100
5 2 100
2 6 59
6 3 61
 1000 1 5 999 0
0 999 0

YES
0 1 1
1 2 999999996
2 3 999999997
0 4 1
4 1 1
1 5 499999999
5 2 499999999
2 6 1
6 3 1
 YES
0 1 1
1 2 199
2 3 318
0 4 1
4 1 1
1 5 100
5 2 100
2 6 59
6 3 61
 YES
0 1 3
1 2 3
2 3 2
0 2 5
1 3 5
 YES
1 2 1
2 4 1
1 3 1
3 4 1
4 5 6
5 6 1
6 0 1
5 7 1
7 0 1
 NO YES
0 1 1
2 0 2
3 0 3
4 1 999999999
4 2 999999998
3 4 999999997
 NO NO YES
0 1 1
1 2 1
0 4 1
4 3 1
3 2 1
 NO YES
1 3 13
2 3 1
2 0 1
1 0 6
 NO NO YES
0 99 123456
 YES
1 3 13
2 3 1
2 0 1
1 0 12
 YES
0 1 1
1 2 198
2 3 317
0 4 1
4 1 1
1 5 100
5 2 100
2 6 59
6 3 61
 YES
0 999 5

#include <bits/stdc++.h>
using namespace std;
struct _hash {
  static unsigned long long splitmix64(unsigned long long x) {
    x += 0x9e3779b97f4a7c15;
    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
    x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
    return x ^ (x >> 31);
  }
  size_t operator()(string x) const {
    static const unsigned long long FIXED_RANDOM =
        chrono::steady_clock::now().time_since_epoch().count();
    unsigned long long h = hash<string>()(x);
    return splitmix64(h + FIXED_RANDOM);
  }
  template <typename T>
  size_t operator()(T x) const {
    static const unsigned long long FIXED_RANDOM =
        chrono::steady_clock::now().time_since_epoch().count();
    return splitmix64(x + FIXED_RANDOM);
  }
  template <typename T1, typename T2>
  size_t operator()(pair<T1, T2> x) const {
    static const uint64_t FIXED_RANDOM =
        chrono::steady_clock::now().time_since_epoch().count();
    return splitmix64(1ll * _hash()(x.first) * 37 + _hash()(x.second) +
                      FIXED_RANDOM);
  }
  template <typename T>
  size_t operator()(vector<T> v) const {
    uint64_t h = 0;
    static const uint64_t FIXED_RANDOM =
        chrono::steady_clock::now().time_since_epoch().count();
    for (auto x : v) {
      h <<= 32;
      h ^= _hash()(x);
      h = _hash()(h);
    }
    return splitmix64(h + FIXED_RANDOM);
  }
  template <typename T>
  size_t operator()(set<T> v) const {
    uint64_t h = 0;
    static const uint64_t FIXED_RANDOM =
        chrono::steady_clock::now().time_since_epoch().count();
    for (auto x : v) {
      h <<= 32;
      h ^= _hash()(x);
      h = _hash()(h);
    }
    return splitmix64(h + FIXED_RANDOM);
  }
};
const int MAX = 1005;
const long long INF = 1e9 + 10;
unordered_set<pair<int, long long>, _hash> g[MAX];
unordered_set<pair<int, int>, _hash> edges;
int par[MAX];
long long dijkstra(int src, int trg) {
  vector<long long> d(MAX, INF);
  d[src] = 0, par[src] = -1;
  set<pair<long long, int>> s;
  s.insert({0LL, src});
  while (s.size()) {
    int u = s.begin()->second;
    s.erase(s.begin());
    for (auto e : g[u]) {
      int v = e.first;
      long long w = e.second;
      if (d[v] > d[u] + w) {
        s.erase({d[v], v});
        d[v] = d[u] + w, par[v] = u;
        s.insert({d[v], v});
      }
    }
  }
  return d[trg];
}
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n, m, L, s, t;
  cin >> n >> m >> L >> s >> t;
  vector<vector<int>> all;
  for (int i = 0; i < m; i++) {
    int u, v, w;
    cin >> u >> v >> w;
    all.push_back({u, v, w});
    if (w == 0)
      edges.insert({u, v});
    else {
      g[u].insert({v, w});
      g[v].insert({u, w});
    }
  }
  long long dist = dijkstra(s, t);
  if (dist < L) return cout << "NO", 0;
  for (auto &e : edges) {
    int u = e.first, v = e.second;
    g[u].insert({v, 1});
    g[v].insert({u, 1});
  }
  dist = dijkstra(s, t);
  if (dist > L) return cout << "NO", 0;
  if (dist == L) {
    cout << "YES\n";
    for (auto &e : all) {
      int u = e[0], v = e[1], w = e[2];
      cout << u << " " << v << " " << max(1, w) << "\n";
    }
  } else {
    unordered_set<pair<int, int>, _hash> temp;
    int x = -1, y = -1, w = -1;
    int p = t, pp = par[t];
    while (pp != -1) {
      temp.insert({p, pp});
      if (edges.find({p, pp}) != edges.end() ||
          edges.find({pp, p}) != edges.end())
        x = p, y = pp;
      p = pp;
      pp = par[p];
    }
    cout << "YES\n";
    for (auto &e : all) {
      int u = e[0], v = e[1], w = e[2];
      if ((u == x && v == y) || (u == y && v == x)) {
        w = L - dist + 1;
        cout << u << " " << v << " " << w << "\n";
      } else if (temp.find({u, v}) == temp.end() &&
                 temp.find({v, u}) == temp.end()) {
        if (w == 0) w = INF;
        cout << u << " " << v << " " << w << "\n";
      } else
        cout << u << " " << v << " " << max(w, 1) << "\n";
    }
  }
  return 0;
}
