#include <algorithm>
#include <iostream>
#include <list>
#include <vector>
#include <set>
#include <string>

const std::string empty;
const std::string no("NO");

typedef int node_t;

struct arrow_t {
    node_t source;
    node_t sink;
    std::string label;
};

struct substring_t {
    std::string::const_iterator begin;
    std::string::const_iterator end;
    substring_t(const std::string& s) : begin(s.begin()), end(s.end()) {}
    int size() const { return end - begin; }
};

struct entry_t {
    substring_t label;
    node_t node;
    entry_t(const substring_t& label, node_t node) : label(label), node(node) {}
};

typedef std::list<entry_t> queue_t;

int compare(const substring_t& s1, const substring_t& s2) {
    for (std::string::const_iterator i1 = s1.begin, i2 = s2.begin; ; ++i1, ++i2) {
        if (i1 == s1.end) {
            return i2 == s2.end? 0 : -1;
        } else if (i2 == s2.end) {
            return 1;
        }
        int c = ((int) *i1) - ((int) *i2);
        if (c != 0) {
            return c < 0 ? -2 : 2;
        }
    }
    return 0;
}

queue_t::iterator insert(queue_t& queue, substring_t label, node_t node) {
    for (queue_t::iterator it = queue.begin(); it != queue.end(); ++it) {
        switch (compare(it->label, label)) {
        case -2:
            return queue.end();
        case -1:
            label.begin += it->label.size();
            continue;
        case 0:
            if (it->node < node) {
                label.begin += it->label.size();
                continue;
            } else if (it->node == node) {
                return it;
            } else {
                it->label.begin += label.size();
                return queue.insert(it, entry_t(label, node));
            }
        case 1:
            it->label.begin += label.size();
            return queue.insert(it, entry_t(label, node));
        case 2:
            return queue.insert(queue.erase(it, queue.end()), entry_t(label, node));
        }
    }
    return queue.insert(queue.end(), entry_t(label, node));
}

std::set<node_t> collect(int n, const std::vector<arrow_t>& arrows, node_t goal) {
    std::vector<std::vector<node_t> > ins(n);
    for (const arrow_t& arrow : arrows) {
        ins[arrow.sink].push_back(arrow.source);
    }

    std::set<node_t> result;
    std::vector<node_t> stack;
    stack.push_back(goal);
    while (!stack.empty()) {
        node_t node = stack.back();
        stack.pop_back();

        result.insert(node);

        for (int source : ins[node]) {
            if (result.find(source) == result.end()) {
                stack.push_back(source);
            }
        }
    }
    return result;
}

std::string calc(int n, const std::vector<arrow_t>& arrows, node_t start, node_t goal) {
    const std::set<node_t>& reachable_set = collect(n, arrows, goal);
    if (reachable_set.find(start) == reachable_set.end()) {
        return no;
    }

    size_t max = 0;
    std::vector<std::vector<const arrow_t*> > outs(n);
    for (const arrow_t& arrow : arrows) {
        if (reachable_set.find(arrow.sink) != reachable_set.end()) {
            max = std::max(max, arrow.label.size());
            outs[arrow.source].push_back(&arrow);
        }
    }

    size_t limit = n * max;

    std::string result;
    queue_t queue;
    queue.push_back(entry_t(empty, start));
    while (true) {
        substring_t label = queue.front().label;
        int node = queue.front().node;
        queue.pop_front();

        result.append(label.begin, label.end);
        if (node == goal) {
            return result;
        }
        if (result.size() > limit) {
            return no;
        }

        //for (node_t node : nodes) {
            for (const arrow_t* arrow : outs[node]) {
                queue_t::iterator it = insert(queue, arrow->label, arrow->sink);
                //if (it != queue.end()) {
                //    it->nodes.insert(arrow->sink);
                //}
            }
        //}
    }
}

int main() {
    while (true) {
        int n, a, s, g;
        std::cin >> n >> a >> s >> g;
        if (n == 0) {
            break;
        }
        std::vector<arrow_t> arrows(a);
        for (arrow_t& arrow : arrows) {
            std::cin >> arrow.source >> arrow.sink >> arrow.label;
        }
        std::cout << calc(n, arrows, s, g) << std::endl;
    }
    return 0;
}

Measured memory_bytes: 3168