#include <bits/stdc++.h>
#define rep(i, n) for (ll i = 0; i < (ll)n; i++)
#define PI 3.14159265358979323846
#define vll vector<long long>
using namespace std;
using ll = long long;
using ld = long double;

class UnionFind {
private:
  ll n;
  vll P;
  ll root(ll x);
  void setN(ll N);
  void init();

public:
  UnionFind(ll N);
  void unite(ll x, ll y);
  bool same(ll x, ll y);
};

// コンストラクタ
UnionFind::UnionFind(ll N) {
  setN(N);
  init();
}

// nを変更
void UnionFind::setN(ll N) { n = N; }

// Union-Find Treeを初期化する
void UnionFind::init() {
  P.clear();
  rep(i, n) { P.push_back(i); }
}

// 根の値を返す
ll UnionFind::root(ll x) {
  if (P[x] == x) { return x; }
  return (P[x] = root(P[x])); // パス圧縮しつつ返す
}

// 木を結合する（rankはとりあえず無視）
void UnionFind::unite(ll x, ll y) { P[root(x)] = root(y); }

// xとyが同じ集合にあるか判別
bool UnionFind::same(ll x, ll y) {
  if (root(x) == root(y)) {
    return true;
  } else {
    return false;
  }
}

// ----本問について----
// 問題：橋の取り壊し
// 問題文URL：https://onlinejudge.u-aizu.ac.jp/problems/0180
// 所要時間：
// 学んだこと：
// ------------------

// ----ここから本問のソースコード----

struct edge {
  ll w, s, e; // weight, start, end

  // コンストラクタ
  edge(ll W, ll S, ll E) {
    w = W;
    s = S;
    e = E;
  }
};

// edge用の比較関数
bool cmpI(const edge &a, const edge &b) { return a.w < b.w; }

// グローバル変数（入力）
ll n, m;
vector<edge> edges;

// 入力
void input() {
  edges.clear();
  rep(i, m) {
    ll a, b, cost;
    cin >> a >> b >> cost;
    edges.push_back(edge(cost, a, b));
  }
}

// 最小全域木の重みの合計を求める（クラスカル法）．
void solve() {
  sort(edges.begin(), edges.end(), cmpI); // 辺を重みをキーに昇順ソート
  UnionFind u(n);                         // UnionFind木を初期化
  ll ans = 0;
  rep(i, edges.size()) {
    if (!u.same(edges[i].s, edges[i].e)) { // 閉路ができない
      u.unite(edges[i].s, edges[i].e);     // 辺を張る
      ans += edges[i].w;
    }
  }
  cout << ans << endl;
}

int main() {
  while (cin >> n >> m && n > 0) {
    input();
    solve();
  }
  return 0;
}

