#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;
}