#include <bits/stdc++.h>
#define rep(i,n) for (int i = 0; i < (int)(n); i++)
#define REP(i,n) for (int i = 1; i < (int)(n); i++)
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define debug(var) do{cout << #var << " : "; view(var);}while(0)
template<class T> bool chmin(T &a, T b) {if(a>b) {a=b;return 1;}return 0;}
template<class T> bool chmax(T &a, T b) {if(a<b) {a=b;return 1;}return 0;}
using namespace std;
template<class T> void view(T e) {cout << e << endl;}
template<class T> void view(const vector<T> &v) {for(const auto &e : v){cout << e << " ";} cout << endl;}
template<class T> void view(const vector<vector<T>> &vv) {for(const auto &v : vv){view(v);}}
using vint = vector<int>;
using vvint = vector<vector<int>>;
using ll = long long;
using vll = vector<ll>;
using vvll = vector<vector<ll>>;
using P = pair<ll,int>;
const int inf = 1<<30;
const ll inf_l = 1LL<<61;
const int MAX = 1e5;

// dijkstra(O((E+V)log(V)))
template<class T>
struct dijkstra {
    struct edge{
        int to;
        T cost;
        int K;
    };
    vector<T> d;
    vector<vector<edge>> G;
    T init_v;
    int N;

    dijkstra(int n, T init_v) : N(n), init_v(init_v) {init(n);} 

    void init(int n) {
        G.resize(n);
        d.resize(n);
    }

    void add_edge(int s, int t, T cost, int k) {
        edge e;
        e.to = t; e.cost = cost; e.K = k;
        G[s].push_back(e);
    }

    void run(int s) {
        rep(i,N) d[i] = init_v;
        priority_queue<pair<T,int>, vector<pair<T,int>>, greater<pair<T,int>>> q;
        d[s] = 0;
        q.push(pair<T,int>(0,s));
        while (!q.empty()) {
            pair<T,int> e = q.top(); q.pop();
            int v = e.second;
            if (d[v] < e.first) continue;
            for (auto e: G[v]) {
                if (chmin(d[e.to], (d[v] + e.K - 1) / e.K * e.K + e.cost)) {
                    q.push(pair<T,int>(d[e.to],e.to));
                }
            }
        }
    }
};

int main() {
    int n, m, x, y;
    cin >> n >> m >> x >> y;
    x--; y--;
    dijkstra<ll> dj(n, inf_l);
    rep(i,m) {
        int a, b, t, k; 
        cin >> a >> b >> t >> k;
        a--; b--;
        dj.add_edge(a, b, t, k);
        dj.add_edge(b, a, t, k);
    }
    dj.run(x);
    if (dj.d[y] == inf_l) cout << -1 << endl;
    else cout << dj.d[y] << endl;
}
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+5;
int head[maxn],tot;
struct Edge{
	int next,to,tim,val;
}e[maxn];
void add_edge(int x,int y,int z,int w){
	e[++tot] = (Edge){head[x],y,z,w},head[x] = tot;

}
int n,m,x,y;
struct Sta{
	long long tim;
	int u;
	bool operator <(Sta b)const{return tim>b.tim;}
};
int vis[maxn];
long long dis[maxn];
std :: priority_queue <Sta> q;
void Dijkstra(){
	memset(dis,0x3f,sizeof(dis));
	q.push((Sta){0,x}),dis[x] = 0;
	while(!q.empty()){
		Sta u = q.top();
		q.pop();
		if(vis[u.u])continue;
		vis[u.u] = 1;
//		cout << u.u << ' ' << head[1] << endl;
		for(int i=head[u.u],v;v=e[i].to,i;i=e[i].next){
			long long to = dis[u.u]?((dis[u.u]-1)/e[i].tim+1)*e[i].tim+e[i].val:e[i].val;
//			cout << u.u << ' ' << v<< ' ' << to  << endl;
			if(to < dis[v] && !vis[v])dis[v] = to,q.push((Sta){to,v});
		}
	}
	if(vis[y])printf("%lld",dis[y]);
	else puts("-1");
}
int main(){
	scanf("%d %d %d %d",&n,&m,&x,&y);
	for(int i=1,a,b,c,d;i<=m;++i){
		scanf("%d %d %d %d",&a,&b,&c,&d);
		add_edge(a,b,d,c),add_edge(b,a,d,c);
	}
//	for(int i=1;i<=n;++i)cout << head[i] << ' ';
//	cout<< '\n';
	Dijkstra();
	return 0;
}
