#include "bits/stdc++.h"
#include<unordered_map>
#include<unordered_set>
#pragma warning(disable:4996)
using namespace std;
using ld = long double;
template<class T>
using Table = vector<vector<T>>;
const ld eps=1e-9;

//// < "D:\D_Download\Visual Studio 2015\Projects\programing_contest_c++\Debug\a.txt" > "D:\D_Download\Visual Studio 2015\Projects\programing_contest_c++\Debug\b.answer"

struct aa {
	int now;
	long long int time;
	int x;
};
class Compare {
public:
	//aa?????????????????¶
	bool operator()(const aa&l, const aa&r) {
		return l.time> r.time;
	}
};
template<class T>
class cht {
public:
	vector<pair<T, T>>ls;
	bool check(const pair<T, T>&l1, const pair<T, T>&l2, const pair<T, T>&l3)const {
		return 1.l*(l2.first - l1.first)*(l3.second - l2.second) >= 1.l*(l2.second - l1.second)*(l3.first - l2.first);
	}
	cht() :ls() {
	}
	cht(vector<pair<T, T>>&vs) :ls() {
		sort(vs.begin(), vs.end());
		for (auto v : vs) {
			add(v);
		}
	}
	void add(const pair<T, T>&p) {
		while (ls.size() >= 2) {
			if (!check(ls[ls.size() - 2], ls[ls.size() - 1], p)) {
				break;
			}
			else {
				ls.pop_back();
			}
		}
		if (ls.size() == 1 && ls.back().second == p.second) {
			ls.back().first = max(ls.back().first, p.first);
		}
		else {
			ls.emplace_back(p);
		}
	}
	T f(int k, const T&x)const {
		return ls[k].first*x + ls[k].second;
	}
	T query(const T&x)const {
		int amin = 0;
		int amax = ls.size();
		while (amin + 1 != amax) {
			int amid = (amin + amax) / 2;
			if (f(amid - 1, x) <= f(amid, x)) {
				amin = amid;
			}
			else {
				amax = amid;
			}
		}
		return f(amin, x);
	}
};
int main() {
	while (1) {
		int N, M, S1, S2, T; cin >> N >> M >> S1 >> S2 >> T;
		if (!N)break;
		S1--; S2--; T--;
		vector<vector<pair<int,long long int>>>edges(N);
		for (int i = 0; i < M; ++i) {
			int a, b;string w; cin >> a >> b >> w; a--; b--;
			long long int value;
			if (w == "x") {
				value = -1;
			}
			else {
				value = stoll(w);

			}
			edges[a].push_back(make_pair(b, value));
			edges[b].push_back(make_pair(a, value));

		}
		//if (N != 1000)continue;
		vector<vector<long long int>>memo(N, vector<long long int>(102,1e18));
		memo[T][0] = 0;
		priority_queue<aa, vector<aa>, Compare>que;
		que.push(aa{ T,0,0 });
		while (!que.empty()) {
			aa atop(que.top());
			const int now = atop.now;
			const long long int now_time = atop.time;
			const int now_x = atop.x;
			que.pop();
			for (auto e : edges[atop.now]) {
				if (e.second == -1) {
					const long long int next_time = now_time;
					if (now_x >= 100)continue;
					if (memo[e.first][now_x + 1] > next_time) {
						bool ok = true;
						for (int ax = 0; ax < now_x + 1; ++ax) {
							if (memo[e.first][ax] <= next_time) {
								ok = false;
								break;
							}
						}
						if (!ok)continue;
						memo[e.first][now_x + 1] = next_time;
						
						que.push(aa{ e.first,next_time ,now_x + 1 });
					}
				}
				else {
					const long long int next_time = now_time + e.second;
					if (memo[e.first][now_x]>next_time) {
						bool ok = true;
						for (int ax = 0; ax < now_x; ++ax) {
							if (memo[e.first][ax] <= next_time) {
								ok = false;
								break;
							}
						}
						if (!ok)continue;

						memo[e.first][now_x] = next_time;
						que.push(aa{ e.first,next_time,now_x });
					}
				}
			}
		}

		cht<long long int> cht1,cht2;
		for (int i = 100; i>=0; --i) {
			if (memo[S1][i] < 1e17) {
				cht1.add(make_pair(-i, -memo[S1][i]));
			}
			if (memo[S2][i] < 1e17) {
				cht2.add(make_pair(-i, -memo[S2][i]));
			}
		}
		vector<long long int >nums;
		nums.emplace_back(0);
		nums.emplace_back(static_cast<long long int>(1e15));
		assert(!cht1.ls.empty() && !cht2.ls.empty());
		for (int i = 0; i < int(cht1.ls.size())-1; ++i) {
			auto pa = cht1.ls[i];
			auto pb = cht1.ls[i+1];
			assert(pb.first != pa.first);
			nums.emplace_back((pa.second - pb.second) / (pb.first - pa.first));
			nums.emplace_back((pa.second - pb.second) / (pb.first - pa.first)+1);
		}
		for (int i = 0; i < int(cht2.ls.size()) - 1; ++i) {
			auto pa = cht2.ls[i];
			auto pb = cht2.ls[i + 1];
			assert(pb.first != pa.first);
			nums.emplace_back((pa.second - pb.second) / (pb.first - pa.first));
			nums.emplace_back((pa.second - pb.second) / (pb.first - pa.first)+1);
		}
		sort(nums.begin(), nums.end());
		nums.erase(unique(nums.begin(), nums.end()), nums.end());
		long long int ans = 1e18;
		for (int i = 0; i < nums.size() - 1; ++i) {
			long long int al = nums[i];
			long long int ar = nums[i+1];
			if (ar < 0)continue;
			else if (al < 0)al = 0;
			if (al == ar)continue;
			long long int lvalue1 = cht1.query(al);
			long long int lvalue2 = cht2.query(al);
			long long int rvalue1 = cht1.query(ar); 
			long long int rvalue2 = cht2.query(ar);
				
			if ((lvalue1 > lvalue2&&rvalue1 > rvalue2)||(lvalue1<lvalue2&&rvalue1<rvalue2)) {
				ans = min(ans, min(abs(lvalue1 - lvalue2), abs(rvalue1 - rvalue2)));
			}
			else {
				long long int dis1 = (rvalue1 - lvalue1) / (ar - al);
				long long int dis2 = (rvalue2 - lvalue2) / (ar - al);
				if (dis1 == dis2) {
					ans = min(ans, abs(lvalue1 - lvalue2));
				}
				else {
					long long int cx = abs((lvalue2 - lvalue1) / (dis1 - dis2));
					if (dis1>dis2) {
						ans = min(ans, abs((lvalue2 - lvalue1) - (cx - 1)*(dis1 - dis2)));
						ans = min(ans, abs((lvalue2 - lvalue1) - (cx)*(dis1 - dis2)));
						ans = min(ans, abs((lvalue2 - lvalue1) - (cx + 1)*(dis1 - dis2)));
					}
					else {
						ans = min(ans, abs((lvalue2 - lvalue1) - (cx - 1)*(dis1 - dis2)));
						ans = min(ans, abs((lvalue2 - lvalue1) - (cx)*(dis1 - dis2)));
						ans = min(ans, abs((lvalue2 - lvalue1) - (cx + 1)*(dis1 - dis2)));
					}
				}
					
			}
			

		}
	
		cout << ans << endl;
	}
	return 0;
}

Measured memory_bytes: 3948