
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define reg register
#define x1 x11
#define x2 x22
#define y1 y11
#define y2 y22
#define z1 z11
#define z2 z22
const int mod=1e9+7;
const int INF=2e16;
const int maxn=5e5+5;
const double Pi=acos(-1.0);
double Exp=1e-6;
inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9')
	{
	    if(ch=='-')
	        f=-1;
	    ch=getchar();
	}
	while(ch>='0' && ch<='9')
	{
	    x=x*10+ch-'0';
	    ch=getchar();
	}
	return x*f;
}
int n,m,s,t;
struct node
{
	int to;
	int nxt;
	int dis;
	int v;
}edge[maxn];
int wugui=0;
int head1[maxn];
void add(int x,int y,int d,int v)
{
	wugui++;
	edge[wugui].to=y;
	edge[wugui].nxt=head1[x];
	edge[wugui].dis=d;
	edge[wugui].v=v;
	head1[x]=wugui;
}
struct node1
{
	int x,y,t,k;
}a[maxn];
struct vode
{
	int id;
	int dist;
}love;
priority_queue<vode> q;
bool operator<(vode a,vode b)
{
	return a.dist>b.dist;
}
int vis[maxn];
int dist[maxn];
void dij()
{
	memset(dist,0x3f,sizeof(dist));
	//cout<<dist[2]<<endl;
	dist[s]=0;
	vode p;
	p.dist=0,p.id=s;
	q.push(p);
	while(!q.empty())
	{
		vode point=q.top();
		q.pop();
		if(vis[point.id])
		continue;
		vis[point.id]=1;
		for(int i=head1[point.id];i;i=edge[i].nxt)
		{
			int t=edge[i].to;
			int wns=dist[point.id]+edge[i].dis;
			if(point.dist%edge[i].v)
			{
				int tot=point.dist/edge[i].v;
				wns=wns+(tot+1)*edge[i].v-point.dist;
			}
			if(dist[t]>wns)
			{
				dist[t]=wns;
				vode p;
				p.dist=dist[t];
				p.id=t;
				q.push(p);
			}
		}
	}
}
signed main()
{
	n=read(),m=read(),s=read(),t=read();
	for(int i=1;i<=m;i++)
	{
		a[i].x=read(),a[i].y=read(),a[i].t=read(),a[i].k=read();
		add(a[i].x,a[i].y,a[i].t,a[i].k);
		add(a[i].y,a[i].x,a[i].t,a[i].k);
	}
	dij();
	if(dist[t]>=INF)
	{
		printf("-1\n");
	}
	else
	printf("%lld\n",dist[t]);
	return 0;
}	

/*
40
1 4
2 3
5 8
6 7
*/

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <utility>
#include <algorithm>
#include <cmath>
#include <climits>
#include <iomanip>
#include <queue>
#include <stack>
#include <ctype.h>

using namespace std;

typedef long long ll;

const int INF = (1<<30)-1;
const ll LINF = (1LL<<60)-1;

#define rep(i, n) for (int i = 0; i < n; i++)

template<class T> 
bool chmax(T &a, T b) {if (a < b) {a = b;return true;}else return false;}

template<class T> 
bool chmin(T &a, T b) {if (a > b) {a = b;return true;}else return false;}

typedef pair<ll,ll> P;


struct edge {
    int to;
    ll cost;
    ll k;
    edge(int to, ll cost, ll k): to(to), cost(cost), k(k) {};
};
 
void dijkstra(vector<vector<edge> >&G, int s, vector<ll> &dist) {
    dist.resize(G.size());
    dist.assign(dist.size(), LINF);
    dist[s] = 0;
    priority_queue<P, vector<P>, greater<P> > que;
    que.push(P(0, s));
    while (que.size()) {
        P p = que.top();    que.pop();
        int u = p.second;   ll d = p.first;
        if (dist[u] < d)    continue;
        for (auto e: G[u]) {
            int v = e.to;   ll c = e.cost, k = e.k;;
            if (chmin(dist[v], (d+k-1)/k*k+c))
                que.push(P(dist[v], v));
        }
    }
}

int main() {
    int n, m, x, y; cin >> n >> m >> x >> y;
    x--;    y--;
    vector<vector<edge> > G(n);
    rep(i, m) {
        int a, b;   ll t, k;    cin >> a >> b >> t >> k;
        a--;    b--;
        G[a].push_back(edge(b, t, k));
        G[b].push_back(edge(a, t, k));
    }
    vector<ll> dist;
    dijkstra(G, x, dist);
    if (dist[y] < LINF)
        cout << dist[y] << endl;
    else 
        cout << -1 << endl;
    return 0;
}

//小数点精度
//cout << fixed << std::setprecision(15) << y << endl;