#include <bits/stdc++.h>
using namespace std ;
typedef long long ll ;
typedef pair<ll,int> P ;
#define MAX_M (ll)100
#define MAX_N 100000

int n , m , X , Y ;

struct edge
{
  ll cost ;
  ll limit ;
  int to ;
};


vector<edge> G[100000] ;
ll d[100000] ;

ll djikstra(int s , int t){
  fill(d,d+n,LLONG_MAX) ;
  d[s] = 0 ;
  priority_queue<P,vector<P>,greater<P>> que ;
  que.push(P(0,s)) ;
  while(!que.empty()){
    P p = que.top() ; que.pop() ;
    int v = p.second ;
    if(p.first > d[v]) continue ;
    for(int i = 0 ; i < G[v].size() ; i++){
      edge e = G[v][i] ;
      if(d[v] % e.limit == 0){
        if(d[e.to] > d[v] + e.cost){
          d[e.to] = d[v] + e.cost ;
          que.push(P(d[e.to],e.to)) ;
        }
      }
      else{
        ll mod = d[v] / e.limit + 1 ;
        if(d[e.to] > mod * e.limit + e.cost){
          d[e.to] = mod * e.limit + e.cost ;
          que.push(P(d[e.to],e.to)) ;
        }
      }
    }
  }
  return d[t] ;
}

int main(){
  cin >> n >> m >> X >> Y ;
  for(int i = 0 ; i < m ; i++){
    int A , B ;
    ll tim , k ;
    cin >> A >> B >> tim >> k ;
    edge E , F ;
    E.to = B - 1 ;
    E.cost = tim ;
    E.limit = k ;
    F.to = A - 1 ;
    F.cost = tim ;
    F.limit = k ;
    G[A-1].push_back(E) ;
    G[B-1].push_back(F) ;
  }
  ll ans = djikstra(X-1,Y-1) ;
  if(ans == LLONG_MAX) cout << -1 << endl ;
  else cout << ans << endl ;
}
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <utility>
#include <cmath>
#include <vector>
#include <stack>
#include <queue>
#include <deque>
#include <set>
#include <map>
#include <tuple>
#include <numeric>
#include <functional>
using namespace std;
typedef long long ll;
typedef vector<ll> vl;
typedef vector<vector<ll>> vvl;
typedef pair<ll, ll> P;
#define rep(i, n) for(ll i = 0; i < n; i++)
#define exrep(i, a, b) for(ll i = a; i <= b; i++)
#define out(x) cout << x << endl
#define exout(x) printf("%.10f\n", x)
#define chmax(x, y) x = max(x, y)
#define chmin(x, y) x = min(x, y)
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()
#define pb push_back
#define re0 return 0
const ll mod = 1000000007;
const ll INF = 1e16;

struct Edge {
    ll to, cost, D;
    Edge(ll to, ll cost, ll D): to(to), cost(cost), D(D) {}
};

struct Data {
    ll v, x;  // いまいる頂点v, 進んだ距離x
    Data(ll v, ll x): v(v), x(x) {}
    bool operator<(const Data& hoge) const {
        return x > hoge.x;
    }
};

ll ceil(ll a, ll b) {  // a÷b以上の最小の整数
    if(b == 0) {
        return 0;
    }
    return (a+b-1)/b;
}

int main() {
    ll n, m, sv, gv;
    cin >> n >> m >> sv >> gv;
    sv--;  gv--;
    
    vector<vector<Edge>> G(n);
    rep(i, m) {
        ll a, b, c, d;
        cin >> a >> b >> c >> d;
        a--;  b--;
        G[a].emplace_back(b, c, d);
        G[b].emplace_back(a, c, d);
    }

    vl dp(n, INF);  // dp[v] : 頂点vまでの距離の最小値
    priority_queue<Data> Q;
    auto push = [&](ll v, ll x) {
        if(dp[v] <= x) {
            return;
        }
        dp[v] = x;
        Q.emplace(v, x);
    };

    // ダイクストラ法。計算量はO((V+E)*log(V))
    push(sv, 0);
    while(!Q.empty()) {
        Data hoge = Q.top();  Q.pop();
        ll v = hoge.v, x = hoge.x;
        if(dp[v] != x) {
            continue;
        }
        for(Edge e : G[v]) {
            ll u = e.to;
            ll c = e.cost;
            ll d = e.D;
            push(u, d*ceil(x, d) + c);
        }
    }

    if(dp[gv] == INF) {
        out(-1);
    }
    else {
        out(dp[gv]);
    }

    re0;
}