#include <bits/stdc++.h>
using namespace std;
const int MAXV = 1010;
const int INF = 1e9;
struct Node{
int v, dis, co;
Node(int _v, int _dis, int _co) : v(_v) , dis(_dis), co(_co) {}
bool friend operator < (Node n1, Node n2){//设置优先级,即距离短的优先级高
return n1.dis > n2.dis;
}
};
vector<Node> Adj[MAXV];
priority_queue<Node> q;//优先队列大法
int n, m, s;//顶点数、边数、起点下标
int dis[MAXV];
int cost[MAXV];
bool vis[MAXV] = {false};
void init(int n){
fill(dis, dis + n + 1, INF);
fill(cost, cost + n + 1, INF);
fill(vis, vis + n + 1, false);
for(int i = 1; i <= n; ++i){
Adj[i].clear();
}
}
void Dij(int s){
dis[s] = 0, cost[s] = 0;
q.push(Node(s, 0, 0));//放入起点
//求出使d[u]最小的还未被访问的顶点的编号
while(!q.empty()){
Node t = q.top();
q.pop();
int u = t.v;
if(vis[u]) continue;
vis[u] = true;
for(int j = 0; j < Adj[u].size(); ++j){
int v = Adj[u][j].v;
if(!vis[v] && Adj[u][j].dis + dis[u] < dis[v] ||
Adj[u][j].dis + dis[u] == dis[v] && Adj[u][j].co + cost[u] < cost[v]){
dis[v] = Adj[u][j].dis + dis[u];
cost[v] = Adj[u][j].co + cost[u];
q.push(Node(v, dis[v], cost[v]));
}
}
}
}
int main(){
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
int a, b, d, p, s, t;
while(~scanf("%d %d", &n, &m) && n){
init(n);
//顶点个数、边数、起点编号
while(m--){
scanf("%d %d %d %d", &a, &b, &d, &p);
Adj[a].push_back(Node(b, d, p));
Adj[b].push_back(Node(a, d, p));
}
scanf("%d %d", &s, &t);
Dij(s);//Dijkstra算法入口
printf("%d %d\n", dis[t], cost[t]);
}
return 0;
}