#pragma GCC optimize("Ofast")
//#pragma GCC target("avx2")
#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
using namespace std;
//#include<boost/multiprecision/cpp_int.hpp>
//#include<boost/multiprecision/cpp_dec_float.hpp>
//namespace mp=boost::multiprecision;
//#define mulint mp::cpp_int
//#define mulfloat mp::cpp_dec_float_100
struct __INIT{__INIT(){cin.tie(0);ios::sync_with_stdio(false);cout<<fixed<<setprecision(15);}} __init;
#define INF (1<<30)
#define LINF (lint)(1LL<<56)
#define endl "\n"
#define rep(i,n) for(lint (i)=0;(i)<(n);(i)++)
#define reprev(i,n) for(lint (i)=(n-1);(i)>=0;(i)--)
#define flc(x) __builtin_popcountll(x)
#define pint pair<int,int>
#define pdouble pair<double,double>
#define plint pair<lint,lint>
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define vec vector<lint>
#define nep(x) next_permutation(all(x))
typedef long long lint;
int dx[8]={1,1,0,-1,-1,-1,0,1};
int dy[8]={0,1,1,1,0,-1,-1,-1};
const int MAX_N=3e5+5;
template<class T>bool chmax(T &a,const T &b){if(a<b){a=b;return 1;}return 0;}
template<class T>bool chmin(T &a,const T &b){if(b<a){a=b;return 1;}return 0;}
//vector<int> bucket[MAX_N/1000];
constexpr int MOD=1000000007;
//constexpr int MOD=998244353;
/*#include<atcoder/all>
using namespace atcoder;
typedef __int128_t llint;*/

lint N,M,X,Y;

struct edge{lint to,cost,k;};
lint V;
vector<edge> G[200000]; // MAX_V
lint d[200000]; // MAX_V
void dijkstra(lint S){
    priority_queue<plint,vector<plint>,greater<plint>> que;
    fill(d,d+V,LINF);
    d[S]=0;
    que.push(plint(0,S));
    while(!que.empty()){
        plint p=que.top();
        que.pop();
        lint v=p.second;
        if(d[v]<p.first) continue;
        rep(i,G[v].size()){
            edge e=G[v][i];
            lint apr=((d[v]+e.k-1)/e.k)*e.k+e.cost;
            if(d[e.to]>apr){
                d[e.to]=apr;
                que.push(plint(d[e.to],e.to));
            }
        }
    }
}

int main(void){
    cin >> N >> M >> X >> Y;
    V=N;
    X--,Y--;
    rep(i,M){
        lint a,b,t,k;
        cin >> a >> b >> t >> k;
        a--,b--;
        G[a].push_back({b,t,k});
        G[b].push_back({a,t,k});
    }
    dijkstra(X);
    if(d[Y]==LINF) cout << -1 << endl;
    else cout << d[Y] << endl;
}
#include<bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
template <typename T>  using ordered_set =
tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
#define ll           long long
#define rep(i,j,n)   for(int i=j;i<n;i++)
#define scn(a)       scanf("%d",&a)
#define scns(a,b)    scanf("%d %d",&a,&b)
#define print(a)     printf("%d\n",a)
#define vec          vector<int>
#define pb           emplace_back    
#define pairs        pair<int,int>
#define f            first
#define s            second
#define all(v)       v.begin(),v.end()
#define mem(a,b)     memset(a,b,sizeof(a))
#define inf          1e18
const int mod = 1e9+7;
const int N = 5e5+5;

int n;
ll dis[N];
vector<tuple<int,int,int>> v1[N];

int main()
{
    int test; test = 1;

    while(test--)
    {
        int m,x,y; scns(n,m); scns(x,y);

        rep(i,0,m)
        {
            int u,v,wt,k; scns(u,v); scns(wt,k);

            v1[u].pb(v,wt,k), v1[v].pb(u,wt,k);
        }

        auto dijkstra = [&](int src)
        {
            rep(i,0,n+1)
            dis[i] = inf;
        
            dis[src] = 0;
        
            set<pair<ll,int>>ms; ms.emplace(0, src);
            
            int cnt = -1;

            while((int)ms.size()>0)
            {
                auto [_, u] = *ms.begin(); ms.erase(ms.begin());

                ++cnt;
                
                for(auto [v, wt, k]:v1[u])
                {
                    ll folds = ((dis[u]-1)/k + 1)*1LL*k;

                    ll cost = folds + wt; 

                    if(cnt == 0)
                    folds = 0;

                    // cout<<folds<<" "<<u<<" "<<v<<endl;
                    
                    if(dis[v] > folds + wt)
                    {
                        if(dis[v] != inf)
                        ms.erase({dis[v],v});

                        dis[v] = folds + wt; ms.emplace(dis[v],v);
                    }
                }
            }
        };
        
        dijkstra(x);

        ll ans = dis[y];

        if(dis[y] >= inf)
        ans = -1;

        printf("%lld\n",ans);
    }

    return 0;
}