/*
 * author : rits1272
 */

#include<bits/stdc++.h>
using namespace std;

#define int long long
#define print(x) cerr << "[" << #x << ": " << x << "]";
#define println(x) cerr << "[" << #x << ": " << x << "]\n";
#define show(v) for(int i = 0; i < (int)v.size(); i++) cout << v[i] << (i == (int)v.size()-1 ? "\n" : " ");
#define deb(v) for(int i = 0; i < (int)v.size(); i++) {print(i) println(v[i])}
#define pb push_back
#define INF 1e18 + 5
const int MOD = 1e9 + 7;

const int N = 1e5 + 5;
vector<vector<int>> adj[N];
vector<bool> vis(N);
int n, m, x, y;

int wait(int t, int k){
	if(t == 0 || t%k == 0) return 0;
	return k - t%k;
}

int32_t main(){
	ios_base::sync_with_stdio(false);cin.tie(NULL); 
	cin >> n >> m >> x >> y;
	--x, --y;
	vis.resize(n);
	for(int i = 0; i < m; i++){
		int a, b, t, k; cin >> a >> b >> t >> k;
		--a, --b;
		adj[a].pb({b, t, k}); // city, time, departure
		adj[b].pb({a, t, k});
	}
	priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
	pq.push({0ll, x}); // time city
	vector<int> mn(n, INF);
	mn[x] = 0;
	while(pq.size()){
		int cur_city = pq.top().second, t = pq.top().first;
		//print(cur_city) println(t)
		pq.pop();
		for(auto x: adj[cur_city]){
			int nxt_city = x[0], T = x[1], k = x[2];
			if(t + T + wait(t, k) < mn[nxt_city]){
				mn[nxt_city] = t + T + wait(t, k);
				pq.push({mn[nxt_city], nxt_city});
			}
		}
	} 
	cout << (mn[y] == INF ? -1 : mn[y]) << "\n";
	return 0; 
}

/*
 * Only write code when you are sure of the approach.
 * Do optimized thinking (Think which technique/observation can be used).
 * Do post analysis after the contest.
 * Upsolve the problems.
 * Learn a technique and solve some problems if its new to you.
 * DON'T GET STUCK ON ONE APPROACH
 */ 


#include <bits/stdc++.h>

template <class T>
T read() {
  T num = 0;
  T f = 1;
  char ch = getchar();
  while (!isdigit(ch)) {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (isdigit(ch)) {
    num = num * 10 + ch - '0';
    ch = getchar();
  }
  return num * f;
}

constexpr int N = 1e5 + 7;
std::vector<std::tuple<int, int, int>> edge[N];
int n, m;
using ll = long long;
ll dist[N];
bool done[N];

void dijkstra(int s, int t) {
  memset(dist, 0x3f, sizeof(dist));
  std::priority_queue<std::pair<ll, int>, std::vector<std::pair<ll, int>>,
                      std::greater<std::pair<ll, int>>>
      que;
  que.push(std::make_pair(dist[s] = 0, s));
  while (!que.empty()) {
    auto p = que.top();
    que.pop();
    int u = p.second;
    if (done[u]) continue;
    done[u] = 1;
    for (auto [v, cost, k] : edge[u]) {
      ll new_dist = (dist[u] + k - 1) / k * k + cost;
      if (new_dist < dist[v]) {
        que.push(std::make_pair(dist[v] = new_dist, v));
      }
    }
  }
  printf("%lld\n", dist[t] == 0x3f3f3f3f3f3f3f3f ? -1 : dist[t]);
}

int main() {
  n = read<int>(), m = read<int>();
  int x = read<int>(), y = read<int>();
  for (int i = 0; i < m; i++) {
    int A = read<int>(), B = read<int>(), T = read<int>(), K = read<int>();
    edge[A].emplace_back(std::make_tuple(B, T, K));
    edge[B].emplace_back(std::make_tuple(A, T, K));
  }
  dijkstra(x, y);
  return 0;
}