#include <bits/stdc++.h>

using namespace std;

#define LOG(...) fprintf(stderr, __VA_ARGS__)
// #define LOG(...)
#define FOR(i, a, b) for(int i = (int)(a); i < (int)(b); ++i)
#define REP(i, n) for(int i = 0; i < (int)(n); ++i)
#define RREP(i, n) for(int i = (int)(n - 1); i >= 0; --i)
#define RFOR(i, a, b) for(int i = (int)(b - 1); i >= (int)(a); --i)
#define ALL(a) (a).begin(), (a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define EXIST(s, e) ((s).find(e) != (s).end())
#define SORT(c) sort(ALL(c))
#define RSORT(c) sort(RALL(c))
#define SQ(n) (n) * (n)
#define BIT(x, i) (((x) >> (i)) & 1)

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<char> vc;
typedef vector<pii> vpi;
typedef vector<pll> vpl;
typedef vector<ll> vll;
typedef vector<vb> vvb;
typedef vector<vi> vvi;
typedef vector<vc> vvc;
typedef vector<vll> vvll;

struct Edge {
  int from, to;
  string w;
  bool reach;

  bool operator <(const Edge& p) const {
    if (reach == p.reach) {
      return w < p.w;
    }
    return reach;
  }
};

bool contain(const string &a, const string &b) {
  REP(i, a.length()) {
    if (a[i] != b[i]) return false;
  }
  return true;
}

int main() {
  int n, a, s, g;
  while(cin >> n >> a >> s >> g, n) {
    vector<vector<Edge>> edges(n);
    vector<vector<Edge*>> revedges(n);

    // input
    REP(i, a) {
      int from, to;
      string w;
      cin >> from >> to >> w;
      Edge e = {from, to, w, false};
      if (from != g) {
        edges[from].push_back(e);
      }
    }
    REP(i, n) {
      for(auto &e : edges[i]) {
        revedges[e.to].push_back(&e);
      }
    }

    // reach check
    {
      vb G(n, false);
      queue<int> que;
      que.push(g);
      while(!que.empty()) {
        int p = que.front(); que.pop();
        G[p] = true;
        for(auto &e : revedges[p]) {
          int sp = e->from;
          e->reach = true;
          if (G[sp]) continue;
          que.push(sp);
        }
      }
    }
    // REP(i, n) {
    //   LOG("%d\n", i);
    //   for(auto e : revedges[i]) {
    //     LOG("(%d -> %d '%s' %c) ", e->from, e->to, e->w.c_str(), e->reach ? 'o' : 'x');
    //   }
    //   LOG("\n");
    // }
    // copy and sort
    REP(i, n) {
      SORT(edges[i]);
    }

    priority_queue<pair<string, int>, vector<pair<string, int>>, greater<pair<string, int>>> que;
    set<pair<string, int>> G;
    que.push({"", s});
    G.insert({"", s});

    while(!que.empty()) {
      auto p = que.top(); que.pop();
      G.erase(p);
      // LOG(":::: %d %s\n", p.second, p.first.c_str());

      if (p.second == g) {
        cout << p.first << endl;
        goto END;
      }
      if (p.first.length() >= n * 10) break;

      for(Edge e : edges[p.second]) {
        if (!e.reach) continue;
        int sp = e.to;
        string sw = p.first + e.w;
        pair<string, int> s = {sw, sp};
        if (!EXIST(G, s)) {
          que.push(s);
          G.insert(s);
        }
      }
    }
    cout << "NO" << endl;

END:;

    // log
    // REP(i, n) {
    //   LOG("%d\n", i);
    //   for(auto e : edges[i]) {
    //     LOG("(%d %s %c) ", e.to, e.w.c_str(), e.reach ? 'o' : 'x');
    //   }
    //   LOG("\n");
    // }
  }
}

Measured memory_bytes: 4160