#include <stdio.h>
#include <queue>
#include <vector>
#include <iostream>
using namespace std;
typedef pair<int,int> P;//P.first:最小コスト P.second:頂点番号

//cost[x][i][j]:iからjへの種類xのコスト
//xが1なら時間,0なら金額をあらわす
int cost[2][301][301];

//smore[x][i][j]:iからjへの最短距離
int smore[2][301][301];

//somerode[x][i]:iから移動できる頂点の番号を保持
queue <int> somerode[2][301];

//m:駅の数
int m;

//seeked[i]:頂点iについてダイクストラしたかのフラグ
bool seeked[2][301];

//dijkstra(int):ダイクストラ法をstartを始点に行う
void dijkstra(int start,int type);

int main()
{
	int n,a,b,C,T,p,q,r,ans[300],k;

	scanf("%d%d",&n,&m);

	while(n != 0 && m != 0){

		//フラグ、コスト、最小値の初期化
		for(int i = 0;i <= 300; i++){
			seeked[0][i] = false;
			seeked[1][i] = false;
			for(int j = 0;j <= 300; j++){
				smore[0][i][j] = INT_MAX;
				smore[1][i][j] = INT_MAX;
				cost[0][i][j] = 10000;
				cost[1][i][j] = 10000;
			}
		}
		
		//路線情報入力
		for(int i = 0;i < n; i++){
			scanf("%d%d%d%d",&a,&b,&C,&T);
			if(cost[0][a][b] > C){
				cost[0][a][b] = C;
				somerode[0][a].push(b);
				//printf("出発:%d 目的:%d コスト:%d 記録コスト:%d\n",a,b,C,cost[0][a][b]);
			}
			if(cost[0][b][a] > C){
				cost[0][b][a] = C;
				somerode[0][b].push(a);
				//printf("出発:%d 目的:%d コスト:%d 記録コスト:%d\n",a,b,C,cost[0][b][a]);
			}
			if(cost[1][a][b] > T){
				cost[1][a][b] = T;
				somerode[1][a].push(b);
				//printf("出発:%d 目的:%d 時間:%d 記録時間:%d\n",a,b,T,cost[1][a][b]);
			}
			if(cost[1][b][a] > T){
				cost[1][b][a] = T;
				somerode[1][b].push(a);
				//printf("出発:%d 目的:%d 時間:%d 記録時間:%d\n",a,b,T,cost[1][b][a]);
			}
		}

		//問い合わせ
		scanf("%d",&k);
		//printf("問い合わせ個数:%d\n",k);
		for(int i = 0;i < k; i++){
			scanf("%d%d%d",&p,&q,&r);
			//printf("p:%d q:%d r:%d",p,q,r);
			if(seeked[r][q])	ans[i] = smore[r][q][p];
			else if (seeked[r][p])	ans[i] = smore[r][p][q];
			else{
				dijkstra(p,r);
				ans[i] = smore[r][p][q];
				seeked[r][p] = true;
			}
		}
		for(int i = 0; i < k; i++){
			printf("%d\n",ans[i]);
		}
		scanf("%d%d",&n,&m);
	}

	return 0;
}

void dijkstra(int start,int type){
	//printf("キュー宣言前\n");
	priority_queue< P,vector<P>,greater<P> > que;
	//printf("キュー宣言後 %d %d\n",type,start);
	smore[type][start][start] = 0;
	//printf("キュー代入前\n");
	que.push(P(0,start));
	//printf("while前\n");

	while(!que.empty()){
		P p = que.top(); que.pop();	//キューから最小コストの頂点の番号とコストを取り出す
		int v = p.second;			//vにコストが最小の頂点の番号
		int size = somerode[type][v].size();
		//printf("最小頂点:%d\n",v);
		if(smore[type][start][v] < p.first)continue; //もし最小コストが取り出したコストより小さければ更新の必要がないので次のループへ
		for(int i = 0; i < size; i++){	//somerode[x][i]:iからいける頂点の番号をもつキュー
			//もし現在の(start-i間最小コスト)より(移動コスト+現在までかかったコスト)が小さければ更新
			//printf("更新する点:%d 更新候補前:%d 更新候補後:%d\n",somerode[type][v].front(),smore[type][start][ somerode[type][v].front() ],smore[type][start][v] + cost[type][v][ somerode[type][v].front() ]);
			if(smore[type][start][ somerode[type][v].front() ] > smore[type][start][v] + cost[type][v][ somerode[type][v].front() ]){
				smore[type][start][ somerode[type][v].front() ] = smore[type][start][v] + cost[type][v][ somerode[type][v].front() ];
				//printf("更新したsmore:%d 更新した頂点:%d\n",smore[type][start][ somerode[type][v].front() ],somerode[type][v].front());
				que.push(P(smore[type][start][ somerode[type][v].front() ],somerode[type][v].front()));	//キュー更新
			}
			somerode[type][v].push( somerode[type][v].front() );
			somerode[type][v].pop();
		}
	}
}