#include <cstdio>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
#include <set>
#include <queue>

using namespace std;

#define reep(i,f,t) for(int i=f ; i<int(t) ; ++i)
#define rep(i,n) reep(i, 0, n) 

typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int,int> pii;

struct Edge
{
	int src, dst;
	int weight;
	Edge(int src, int dst, int weight) : src(src), dst(dst), weight(weight) {}

	bool operator< (const Edge& e)const
	{
		return weight != e.weight ? weight > e.weight :
			src != e.src ? src < e.src : dst < e.dst;
	}
};

typedef vector<Edge> Edges;
typedef vector<Edges> Graph;

struct UnionFind
{
	vi data;

	UnionFind(int size) : data(size, -1) {}

	// xツづツづ個集ツ債づーツ閉ケツ債つキツづゥ
	bool unionSet(int x, int y)
	{
		x = root(x);
		y = root(y);
		if(x != y){
			if(data[y] < data[x])
				swap(x, y);
			data[x] += data[y];
			data[y] = x;
		}
		return x != y;
	}

	// xツづツづ個集ツ債つェツ督卍つオツつ「ツつゥツ偲ヲツ督セツつキツづゥ
	bool findSet(int x, int y)
	{
		return root(x) == root(y);
	}

	int root(int x)
	{
		return data[x] < 0 ? x : data[x] = root(data[x]);
	}
	int size(int x)
	{
		return -data[root(x)];
	}
};

pair<int, Edges> Kruskal(const Graph& g)
{
	int n = g.size();
	UnionFind uf(n);
	priority_queue<Edge> Q;

	rep(i, n) rep(j, g[i].size())
		if(i < g[i][j].dst)
			Q.push(g[i][j]);

	int total = 0;
	Edges F;
	while(F.size() < n-1 && !Q.empty()){
		Edge e = Q.top();
		Q.pop();
		if(uf.unionSet(e.src, e.dst)){
			F.push_back(e);
			total += e.weight;
		}
	}
	return pair<int, Edges>(total, F);
}

int main()
{
	int n, m;
	while(scanf("%d%d", &n, &m), n){
		Graph g(n);
		rep(i, m){
			int a, b, cost;
			scanf("%d%d%d", &a, &b, &cost);
			g[a].push_back(Edge(a, b, cost));
			g[b].push_back(Edge(b, a, cost));
		}

		pair<int, Edges> result = Kruskal(g);
		printf("%d\n", result.first);
	}
	return 0;
}