#include<stdio.h>
#include <iostream>
#include <math.h>
#include <numeric>
#include <vector>
#include <map>
#include <functional>
#include <stdio.h>
#include <array>
#include <algorithm>
#include <string>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <queue>
#include<iomanip>
#include<bitset>
#include<stack>
#include<set>
#include<limits>
#include <complex>
using namespace std;


const int mod = 1000000007;
struct Mod {
public:
	int num;
	Mod() : num(0) { ; }
	Mod(long long int n) : num((n % mod + mod) % mod) { ; }
	Mod(int n) : num((n % mod + mod) % mod) { ; }
	operator int() { return num; }
};

Mod operator+(const Mod a, const Mod b) { return Mod((a.num + b.num) % mod); }
Mod operator+(const long long int a, const Mod b) { return Mod(a) + b; }
Mod operator++(Mod &a) { return a + Mod(1); }
Mod operator-(const Mod a, const Mod b) { return Mod((mod + a.num - b.num) % mod); }
Mod operator-(const long long int a, const Mod b) { return Mod(a) - b; }
Mod operator--(Mod &a) { return a - Mod(1); }
Mod operator*(const Mod a, const Mod b) { return Mod(((long long)a.num * b.num) % mod); }
Mod operator*(const long long int a, const Mod b) { return Mod(a)*b; }
Mod operator+=(Mod &a, const Mod b) { return a = a + b; }
Mod operator+=(long long int &a, const Mod b) { return a = a + b; }
Mod operator-=(Mod &a, const Mod b) { return a = a - b; }
Mod operator-=(long long int &a, const Mod b) { return a = a - b; }
Mod operator*=(Mod &a, const Mod b) { return a = a * b; }
Mod operator*=(long long int &a, const Mod b) { return a = a * b; }
Mod operator^(const Mod a, const int n) {
	if (n == 0) return Mod(1);
	Mod res = (a * a) ^ (n / 2);
	if (n % 2) res = res * a;
	return res;
}
Mod inv(const Mod a) { return a ^ (mod - 2); }
Mod operator/(const Mod a, const Mod b) {
	assert(b.num != 0);
	return a * inv(b);
}
Mod operator/(const long long int a, const Mod b) {
	assert(b.num != 0);
	return Mod(a) * inv(b);
}
Mod operator/=(Mod &a, const Mod b) {
	assert(b.num != 0);
	return a = a * inv(b);
}

#define MAX_N 1024000

Mod fact[MAX_N], factinv[MAX_N];
void init() {
	fact[0] = Mod(1); factinv[0] = 1;
	for (int i = 0; i < MAX_N - 1; ++i) {
		fact[i + 1] = fact[i] * Mod(i + 1);
		factinv[i + 1] = factinv[i] / Mod(i + 1);
	}
}
Mod comb(const int a, const int b) {
	return fact[a] * factinv[b] * factinv[a - b];
}


template<typename T>
vector<vector<T>> keisann(const vector<vector<T>>l, const vector<vector<T>>r) {
	vector<vector<T>>ans(l.size(), vector<T>(r[0].size()));
	assert(l[0].size() == r.size());
	for (unsigned int h = 0; h < l.size(); ++h) {
		for (unsigned int i = 0; i < r.size(); ++i) {
			for (unsigned int w = 0; w < r[0].size(); ++w) {

				ans[h][w] += l[h][i] * r[i][w];
			}
		}
	}
	return ans;
}
template<typename T>
vector<vector<T>>powgyou(vector<vector<T>>a, const long long int n) {
	assert(a.size() == a[0].size());
	if (!n) {
		vector<vector<T>>e(a.size(), vector<T>(a[0].size()));
		for (unsigned int i = 0; i < a.size(); ++i) {
			e[i][i] = 1;
		}
		return e;
	}
	if (n == 1)return a;
	else {
		vector<vector<T>>ans(a.size(), vector<T>(a[0].size(), 0));
		ans = powgyou(a, n / 2);
		ans = keisann(ans, ans);
		if (n % 2) {
			ans = keisann(ans, a);
		}
		return ans;
	}
}

#define REP(i,n) for(int i=0;i<(int)n;++i)
#define FOR(i,c) for(auto i=(c).begin();i!=(c).end();++i)
#define ALL(c) (c).begin(), (c).end()

const int INF = 2147483647;
const long long int L_INF = 9223372036854775807;

typedef int Weight;
struct Edge {
	int src, dst;
	Weight weight;
	Edge(int src, int dst, Weight weight) :
		src(src), dst(dst), weight(weight) { }
};
bool operator < (const Edge &e, const Edge &f) {
	return e.weight != f.weight ? e.weight > f.weight : // !!INVERSE!!
	e.src != f.src ? e.src < f.src : e.dst < f.dst;
}
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;

typedef vector<Weight> Array;
typedef vector<Array> Matrix;
#define RESIDUE(s,t) (capacity[s][t]-flow[s][t])

vector<pair<int, int>>uses;

//流量0の逆辺も張らないと正しく求まらないので注意
Weight maximumFlow(const Graph &ag, int s, int t) {

	Graph g(ag);
	for (int i = 0; i < ag.size(); ++i) {
		for (int j = 0; j < ag[i].size(); ++j) {
			int d = ag[i][j].dst;
			int s = ag[i][j].src;
			
			bool ok = false;
			for (int k = 0; k < ag[d].size(); ++k) {
				if (ag[d][k].src == s) {
					ok = true; 
					break;
				}
			}
			if (!ok) {
				g[d].push_back(Edge(d, s, 0));
			}
		}
	}

	int n = g.size();
	Matrix flow(n, Array(n)), capacity(n, Array(n));
	REP(u, n) FOR(e, g[u]) capacity[e->src][e->dst] += e->weight;

	Weight total = 0;
	while (1) {
		queue<int> Q; Q.push(s);
		vector<int> prev(n, -1); prev[s] = s;
		while (!Q.empty() && prev[t] < 0) {
			int u = Q.front(); Q.pop();
			FOR(e, g[u]) if (prev[e->dst] < 0 && RESIDUE(u, e->dst) > 0) {
				prev[e->dst] = u;
				Q.push(e->dst);
			}
		}
		if (prev[t] < 0) return total; // prev[x] == -1 <=> t-side
		Weight inc = INF;
		for (int j = t; prev[j] != j; j = prev[j])
			inc = min(inc, RESIDUE(prev[j], j));
		for (int j = t; prev[j] != j; j = prev[j])
			flow[prev[j]][j] += inc, flow[j][prev[j]] -= inc;
		total += inc;
	}
}

map<long long int, int>soinnsuu(long long int a) {
	map<long long int, int>ans;
	for (long long i = 2; i*i <= a; ++i) {
		while (a%i == 0) {
			ans[i]++;
			a /= i;
		}
	}
	if (a != 1)ans[a]++;


	return ans;
}

bool isso(long long int a) {
	if (a == 1)return false;
	for (long long int i = 2; i*i <= a; ++i) {
		if (!(a%i)) {
			return false;
		}
		else {
		}
	}
	return true;
}


struct vert {
	int deg;
	int s;
	int id;
	vert(int a, int b, int c) {
		deg = a;
		s = b;
		id = c;
	}
};


#include<stdio.h>
#include <iostream>
#include <math.h>
#include <numeric>
#include <vector>
#include <map>
#include <functional>
#include <stdio.h>
#include <array>
#include <algorithm>
#include <string>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <queue>
#include<iomanip>
#include<bitset>
#include<stack>
#include<set>
#include<limits>
#include <complex>
using namespace std;


long long int powint(long long int a, int b) {
	if (b == 0)return 1;
	if (b == 1)return a;
	else {
		long long int ans = 1;
		long long int c = powint(a, b / 2);
		ans *= c*c;
		ans *= (b % 2) ? a : 1;
		return ans;
	}

}


#define Seg_Max_N (1<<18) 
// update(l,r,v) := [l,r]の区間に対してvを一様に足す. k,a,bは飾り

struct NODE {
	int sum;//更新された値. この値を参照する時は評価が完全に完了しているようにする.
	int lazy;	//遅延されている値を保存している
	NODE() {
		sum = lazy = 0;
	}
};

NODE seg[2 * Seg_Max_N];

// inlineつけないと大変なことになるよ!(遅い)
inline void lazy_evaluate_node(int k, int a, int b) {
	seg[k].sum += seg[k].lazy * (b - a + 1);
	if (k < Seg_Max_N) { // 2*k(左の子番号) < 2*N (節点の数) のイメージで. 末端ノードじゃなきゃ伝搬するのと等価.
		seg[2 * k].lazy += seg[k].lazy;	//次は君が伝搬してね☆って感じ.
		seg[2 * k + 1].lazy += seg[k].lazy;
	}
	seg[k].lazy = 0;
}

inline void update_node(int k) { // kの子が既に評価されていることが前提. 末端以外のときしか呼び出さないような位置に書くのでif文要らない.
	seg[k].sum = seg[2 * k].sum + seg[2 * k + 1].sum;
}

// update(l,r,v) := [l,r]を更新する. 区間は1-indexed.
void update(int l, int r, int v, int k = 1, int a = 1, int b = Seg_Max_N) {

	assert(r < Seg_Max_N);
	assert(l<=0&&r<=0);
	lazy_evaluate_node(k, a, b); 	// とりあえず辿ったノードは都合がいいので伝搬しとけ精神.

	if (b < l || r < a) //[a,b]と[l,r]が交差している場合
		return;
	if (l <= a && b <= r) { // [l,r]が[a,b]を完全に含んでいる場合
		seg[k].lazy += v;
		lazy_evaluate_node(k, a, b); //一回遅延評価しとかないと都合悪いので.
		return;
	}

	int m = (a + b) / 2;
	update(l, r, v, 2 * k, a, m);
	update(l, r, v, 2 * k + 1, m + 1, b);
	update_node(k);
}

// get(l,r) := [l,r]に対するクエリの答えを得る. 区間は1-indexed.
int get(int l, int r, int k = 1, int a = 1, int b = Seg_Max_N) {
	assert(r < Seg_Max_N);
	if (l < 0||r<0)assert(false);
	lazy_evaluate_node(k, a, b); // とりあえず辿ったノードは都合がいいので伝搬しとけ精神.

	if (b < l || r < a) //[a,b]と[l,r]が交差している場合
		return 0;

	if (l <= a && b <= r) { // [l,r]が[a,b]を完全に含んでいる場合
		return seg[k].sum;
	}

	int m = (a + b) / 2;
	int vl = get(l, r, 2 * k, a, m);
	int vr = get(l, r, 2 * k + 1, m + 1, b);
	update_node(k);
	return vl + vr;
}

//2:54

long long unsigned  int K, N;
vector<long long unsigned  int>as, ds;



bool check(long long unsigned  int cost, bool needmoney = false) {
	
	long long unsigned  int renotime = 0;
	for (int i = 0; i < N; ++i) {
		if (cost >= as[i]) {

			renotime += 1 + (cost-as[i] ) / ds[i];
		}
		if (renotime >= K)return true;
	}
	if (renotime >= K)return true;
	else return false;
}
struct edge {
	long long int from;
	long long int to;
	long long int leng;
	long long int cost;
};

struct a {
	long long int now;
	long long int leng;
	long long int cost;
};

class Compare {
public:
	bool operator()(const pair<int, int>&l, const pair<int, int>&r) {
		return l.second> r.second;
	}
	bool operator()(const a&l, const a&r) {
		return l.leng== r.leng?l.cost>r.cost:l.leng>r.leng;
	}
};

int main() {
	while (1) {
		long long int N, M; cin >> N >> M;
		if (!N)break;
		vector<vector<edge>>edges(N);
		for (int i = 0; i < M; ++i) {
			long long int u, v, d, c; cin >> u >> v >> d >> c;
			u--; v--;
			edges[u].push_back(edge{ u,v,d,c });
			edges[v].push_back(edge{ v,u,d,c });
		}
		vector<long long int>times(N,9999999999999);

		priority_queue<a, vector<a>, Compare>que;
		que.push({ 0,0,0 });
		int ans = 0;
		while (!que.empty()) {
			a atop(que.top());
			que.pop();
			if (times[atop.now] > atop.leng) {
				ans += atop.cost;
				times[atop.now] = atop.leng;
				for (auto it : edges[atop.now]) {
					if (times[it.to] > atop.leng + it.leng) {
						que.push({ it.to,atop.leng + it.leng,it.cost });
					}
				}
			}
		}
		cout << ans << endl;
	}
	return 0;
}

Measured memory_bytes: 17832