#include <bits/stdc++.h>

using namespace std;
typedef long double ld;
typedef long long ll;
using P = pair<ll,int>;
const char EOLN = '\n';
#define rep(i,n) for (int i = 0; i < (n); ++i)
// DP
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return true; } return false; }
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return true; } return false; }

// 定数
#define INF32 2147483647 //2.147483647×10^{9}:32bit整数のinf
#define INF64 9223372036854775807 //9.223372036854775807×10^{18}:64bit整数のinf
#define MOD 1000000007 //問題による
const double pi = 3.14159265359;

// メモ
// vector二次元配列
// vector<vector<ll>> cnt(h,vector<ll> (w));
// bit演算
// for (int bit = 0; bit < (1<<k); ++bit)
// bit & (1 << i)
// 複数変数をいっきに代入
// tie(a,b,c) = make_tuple(10, 7.7, "hello");
// index が条件を満たすかどうか
struct Edge{
    int to,t,k;
    Edge(int to,int t,int k): to(to),t(t),k(k){}
};

int main()
{
    int N,M,XX,YY;
    cin>>N>>M>>XX>>YY;
    XX--;YY--;
    vector<vector<Edge>> G(N);
    for(int i=0;i<M;i++){
        int a,b,t,k;
        cin>>a>>b>>t>>k;
        a--;b--;
        G[a].emplace_back(b,t,k);
        G[b].emplace_back(a,t,k);
    }
    
    vector<ll> dist(N,INF64); //dp
    priority_queue<P,vector<P>,greater<P>> X;
    X.push({0,XX});
    //queueが空になるまでroop
    while(!X.empty()){
        ll curcost=X.top().first;
        int from=X.top().second;
        X.pop();    //queueから1つ取り出す
        if(dist[from]<curcost) continue;
        for(auto x:G[from]){    //Gの行ける場所を調査
            ll nx = (curcost+x.k-1)/x.k*x.k + x.t;
            if(chmin(dist[x.to],nx)){  //Update
                //X.push({nx,x.to});    //調査対象の取り出し
                X.push({dist[x.to],x.to});
            }
        }
    }
    ll ans = dist[YY];
    if(ans==INF64) ans=-1;
    cout <<ans;
    return 0;
}
#if _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <bits/stdc++.h>
#include <unordered_map>
#include <unordered_set>
using namespace std;

#ifndef ONLINE_JUDGE 
const bool DEBUG = true;
#else
const bool DEBUG = false;
#endif

// Reads a 1D vector
template <class T>
void read1d(vector<T> & arg) {
	const int l = arg.size();
	for (int i = 0; i < l; ++i) cin >> arg[i];
}

void read() {}
// Reads arbitrary values
template <class T1, class... T2>
void read(T1& var1, T2&... var2) { cin >> var1; read(var2...); }



void pln() { cout << (DEBUG ? "]\n" : "\n"); }
template <class T1, class... T2>
void pln(const T1& var1, const T2& ... var2) { cout << var1 << " "; pln(var2...); }

// Prints arbitrary values and goes to next line
template <class T1, class... T2>
constexpr void print(const T1& var1, const T2& ... var2) { cout << (DEBUG ? " [ " : ""); pln(var1, var2...); }

// Prints arbitrary values and goes to next line ONLY IF IN DEBUG MODE
template <class T1, class... T2>
constexpr void debug(const T1& var1, const T2& ... var2) { if (!DEBUG) return;  cout << " debug : [ "; pln(var1, var2...); }





using ll = long long;
using ull = unsigned long long;
using ld = long double;


#define all(x) begin(x), end(x)

const bool MULTIPLE_TEST_CASES = 0;

struct Edge {
	ll wt;
	ll mul;

	Edge() {}
	Edge(ll wt, ll mul) : mul(mul), wt(wt) { }
};

void exec() 
{
	int n, m;
	read(n, m);
	int x, y;
	read(x, y);
	--x; --y;

	vector<unordered_map<int, vector<Edge>>> graph(n, unordered_map<int, vector<Edge>>());
	for (int i = 0; i < m; ++i) {
		int from, to, time, mul;
		read(from, to, time, mul);
		--from; --to;

		graph[from][to].push_back(Edge(time, mul));
		graph[to][from].push_back(Edge(time, mul));
	}

	auto cmp = [&](pair<ll, int>& a, pair<ll, int>& b) { return a < b; };

	vector<bool> vis(n, false);
	vector<ll> T(n, LLONG_MAX);
	priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<pair<ll, int>>> djk;

	//vis[x] = true;
	T[x] = 0;
	djk.push({ 0, x });

	for (int i = 0; i < n; ++i) {
		while (!djk.empty() && vis[djk.top().second]) djk.pop();
		if (djk.empty()) break;
		int root = djk.top().second;
		ll _T = djk.top().first;
		djk.pop();

		vis[root] = true;
		//if (root == y) break;

		for (auto& [node, edges] : graph[root]) {
			if (vis[node]) continue;

			ll reachingAt = LLONG_MAX;

			for (auto& edge : edges) {
				// when is the next train coming?
				ll nextTrain = (_T % edge.mul == 0 ? _T : ((_T / edge.mul) + 1) * edge.mul);
				// when we reaching?
				reachingAt = min(reachingAt, nextTrain + edge.wt);
			}

			if (reachingAt < T[node]) {
				T[node] = reachingAt;
				djk.push({ reachingAt, node });
			}
		}
	}

	if (T[y] == LLONG_MAX) print(-1);
	else print(T[y]);
}

















int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);

	if (!MULTIPLE_TEST_CASES)
		exec();
	else {
		int n;
		cin >> n;

		while (n--) exec();
	}

    return 0;
}