#include <iostream>
#include <vector>
#include <utility>
#include <queue>
#include <cmath>
#include <algorithm>
#include <random>
#include <string.h>

using namespace std;
typedef long long ll;
const double pi = acos(-1);
#define FOR(i,a,b) for (ll i=(a);i<(b);i++)
#define RFOR(i,a,b) for (ll i=(b)-1;i>=(a);i--)
#define REP(i,n) FOR(i,0,n)
#define RREP(i,n) RFOR(i,0,n)
template<typename T> ostream& operator<<(ostream& os, const vector<T>& v) {
	REP(i, v.size()) { if (i)os << " "; os << v[i]; }return os;
}
template<typename T> ostream& operator<<(ostream& os, const vector<vector<T>>& v) {
	REP(i, v.size()) { if (i)os << endl; os << v[i]; }return os;
}

class union_find {
public:
    union_find(int n)
        : par_(n, -1)
    {}
    void init(int n) {
        par_.assign(n, -1);
    }

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

    bool unite(int x, int y) {
        x = root(x); y = root(y);
        if(x == y) {
            return false;
        } else {
            if(par_[x] < par_[y]) {
                par_[x] += par_[y];
                par_[y] = x;
            } else {
                par_[y] += par_[x];
                par_[x] = y;
            }
            return true;
        }
    }

    bool same(int x, int y) {
        return root(x) == root(y);
    }

    int size(int x) {
        return -par_[root(x)];
    }

private:
    std::vector<int> par_;
};

//s
using weight = int;

struct edge {
    int from, to;
    weight cost;
    bool operator<(edge const& rhs) const {
        return cost > rhs.cost;
    }
};

using edges = std::vector<edge>;
using graph = std::vector<edges>;

edges kruskal (int V, edges& es) {
    std::sort(es.rbegin(), es.rend());
    union_find uf(V);
    edges res;
    for(int i=0; i<es.size(); ++i) {
        edge e = es[i];
        if(!uf.same(e.from, e.to)) {
            uf.unite(e.from, e.to);
            res.push_back(e);
        }
    }
    return res;
}

edges prim(graph& g) {
    edges res;
    std::vector<bool> used(g.size(), 0);
    priority_queue<edge> que;
    que.push((edge{-1, 0, 0}));
    while(!que.empty()) {
        edge e = que.top(); que.pop();
        if(used[e.to]) continue;
        if(e.from >= 0) {
            res.push_back(e);
        }
        used[e.to] = true;
        for(auto ee : g[e.to]) {
            if(!used[ee.to]) {
                que.push(ee);
            }
        }
    }
    sort(res.rbegin(), res.rend());
    return res;
}


int main() {
	int n,m;
    cin >> n >> m;
    edges es,answer;
    while(n!=0 && m!=0){
        int sum = 0;
        edge e;
        es.erase(es.begin(),es.begin()+es.size());
        for(int i=0;i<m;++i){
            int v1,v2,c;
            cin >> v1 >> v2 >> c;
            e = edge{v1,v2,c};
            es.push_back(e);
        }
        answer = kruskal(n,es);
        for(auto a: answer){
            sum += a.cost;
        }
        cout << sum << endl;
        cin >> n >> m;
    }
}