#include<bits/stdc++.h>
#define ll long long int
#define pll pair<ll,ll>
#define vpll vector< pll >
#define mpll map<ll,ll>
#define MOD 1000000007
#define all(v) v.begin(),v.end()
#define s(v) v.size()
#define test ll t;cin>>t;while(t--)
#define vec vector<ll>
#define read0(v,n) for(int i=0;i<n;i++)cin>>v[i];
#define read1(v,n) for(int i=1;i<=n;i++)cin>>v[i];
#define trav(a,x) for (auto& a: x)
#define fast ios_base::sync_with_stdio(false);cin.tie(NULL);
#define cut(x) {cout<<x;return 0;}
#define print(x) {cout<<x<<nl;continue;}
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define FORB(i,a,b) for(int i=a;i>=b;i--)
#define err1(a) {cout<<#a<<' '<<a<<nl;}
#define err2(a,b) {cout<<#a<<' '<<a<<' '<<#b<<' '<<b<<nl;}

#define mp make_pair
#define pb push_back
#define eb emplace_back
#define f first
#define sc second
#define lb lower_bound
#define ub upper_bound
#define nl '\n'
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace __gnu_pbds;
using namespace std;
#define oset tree<int, null_type,less_equal<int>, rb_tree_tag,tree_order_statistics_node_update>
ll gcd(ll a, ll b)
{
	if (b==0)return a;
	return gcd(b, a % b);
}
ll lcm(ll a,ll b)
{
    return (a*b)/gcd(a,b);
}
ll pow(ll a, ll b)
{
	ll ans=1;
	while(b)
	{
		if(b&1)
			ans=(ans*a)%MOD;
		b/=2;
		a=(a*a)%MOD;
	}
	return ans;
}
struct node{
    ll x,t,k;
};
const int N=1e5+5;
vec d(N,(ll)1e18);
vec v[N];
vector<node> g[N];
ll dis(ll x,ll y)
{
    ll p=x/y;
    if(x%y!=0)p++;
    p*=y;
    return p;
}
void solve(ll n,ll u)
{
    multiset<pll> q;
    d[u]=0;
    q.insert({0,u});
    while(!q.empty())
    {
        pll p=*q.begin();
        q.erase(q.begin());
        trav(it,g[p.sc])
        {
            ll c=dis(p.f,it.k);

            if(d[it.x]>c+it.t)
            {
                d[it.x]=c+it.t;
                q.insert({d[it.x],it.x});
            }
        }
    }

}
int main()
{
	fast
	int n,m,x,y;
	cin>>n>>m>>x>>y;
	FOR(i,1,m)
	{
	    ll a,b,c,d;
	    cin>>a>>b>>c>>d;
	    node temp;
	    temp.x=b;temp.t=c;temp.k=d;
	    g[a].pb(temp);
	    node kemp;
	    kemp.x=a;kemp.t=c;kemp.k=d;
	    g[b].pb(kemp);
	}
    solve(n,x);
    if(d[y]==(ll)1e18)cut(-1)
	//FOR(i,1,n)cout<<d[i]<<' ';
    cut(d[y])

}

// Problem: E - Train
// Contest: AtCoder - AtCoder Beginner Contest 192
// URL: https://atcoder.jp/contests/abc192/tasks/abc192_e
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <algorithm>
#include <bitset>
#include <cassert>
#include <chrono>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#define ll long long
#define mod 1000000007

// templates
#define all(v) v.begin(), v.end()
#define F first
#define S second
#define sz(x) (int)x.size()
#define po(x, y) fixed << setprecision(y) << x
#define ss(s) scanf(" %[^\n]%*c", s)
#define sc(n) scanf("%d", &n)
#define sl(n) scanf("%lld", &n)
#define ps(s) printf("%s\n", s)
#define pr(n) printf("%d\n", n)
#define pl(n) printf("%lld\n", n)
#define prs(n) printf("%d ", n)
#define pls(n) printf("%lld ", n)
using namespace std;

const ll inf = (ll)1e16 + 10;
const int N = (int)1e5 + 10;
int a[N], b[N];
vector<array<ll, 3>> adj[N];  // u->v,t,k
vector<ll> dist(N);
ll n, m, x, y;
void bfs() {
  set<array<ll, 2>> s;  // time,node
  s.insert({0, x});
  for (int i = 0; i <= n; i++) {
    dist[i] = inf;
  }
  dist[x] = 0;
  while (sz(s)) {
    auto temp = *s.begin();
    s.erase(s.begin());
    ll node = temp[1], kete = temp[0];
    for (auto c : adj[node]) {
      ll add = 0;
      if (kete < c[2] && kete != 0) {
        add = (c[2] - kete);
      } else if (kete != 0) {
        if (kete % c[2]) {
          add = c[2] - (kete % c[2]);
        }
      }
      ll curr = c[1] + add + kete;
      // printf("node-> %lld curr-> %lld\n", node, curr);
      if (dist[c[0]] > curr) {
        s.erase({dist[c[0]], c[0]});
        dist[c[0]] = curr;
        s.insert({curr, c[0]});
      }
    }
  }
  if (dist[y] == inf) {
    dist[y] = -1;
  }
  pl(dist[y]);
}
void solve() {
  sl(n), sl(m), sl(x), sl(y);
  for (int i = 1; i <= m; i++) {
    ll u, v, t, k;
    sl(u), sl(v), sl(t), sl(k);
    adj[u].push_back({v, t, k});
    adj[v].push_back({u, t, k});
  }
  bfs();
}

int main() {
  // #ifndef ONLINE_JUDGE
  // freopen("input.txt", "r", stdin);
  // freopen("output.txt", "w", stdout);
  // #endif
  int t = 1;
  // sc(t);
  while (t--) {
    solve();
  }
  // cerr << (float)clock() / CLOCKS_PER_SEC * 1000 << " ms" << endl;
  return 0;
}