#include <iostream>
#include <queue>
#include <vector>
using namespace std;
const int maxn=1001;
struct edge{
int to;
int dis;
int waste;
edge(int a,int c,int d):to(a),
dis(c),waste(d){};
bool operator<(edge y) const{
return dis>y.dis;
}
};
struct point{
int number;
int dis;
int waste;
point(int a,int b,int c):number(a),dis(b),waste(c){};
bool operator< (point y) const{
if(dis==y.dis) return waste>y.waste;
else return dis>y.dis;
}
};
int dist[maxn];
bool visit[maxn];
int w[maxn];
vector<edge> G[maxn];
priority_queue<point> q;
void init(){
for(int i=0;i<maxn;i++) {
G[i].clear();
dist[i]=1000;
visit[i]=false;
w[i]=0;
}
while(!q.empty()) q.pop();
}
int main() {
int n,m;
while(cin>>n>>m){
if(n==0 && m==0) break;
init();
for(int i=0;i<m;i++){
int a,b,d,p;
cin>>a>>b>>d>>p;
G[a].push_back(edge(b, d, p));
G[b].push_back(edge(a,d,p));
}
int start,end;
cin>>start>>end;
dist[start]=0;
q.push(point(start,0,0));
while(!q.empty()){
point tem=q.top();
q.pop();
for(int i=0;i<G[tem.number].size();i++){
edge tp=G[tem.number][i];
if((dist[tp.to]>(dist[tem.number]+tp.dis)) ||
( dist[tp.to]==(dist[tem.number]+tp.dis)&& (w[tp.to]
>w[tem.number]+tp.waste))){
dist[tp.to]=dist[tem.number]+tp.dis;
q.push(point(tp.to,dist[tp.to],
tem.waste+tp.waste));
w[tp.to]=w[tem.number]+tp.waste;
}
}
}
cout<<dist[end]<<' '<<w[end]<<endl;
}
}