// ダイクストラ法 非負距離のみ
// O((N+M)log M)
// https://www.youtube.com/watch?v=iEfDi7wagfE&feature=youtu.be
#include <bits/stdc++.h>
using namespace std;

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

typedef long long ll;

#define REP(i,n) for(ll i=0;i<(ll)(n);i++)
#define REPD(i,n) for(ll i=n-1;i>=0;i--)
#define FOR(i,a,b) for(ll i=a;i<=(ll)(b);i++)
#define FORD(i,a,b) for(ll i=a;i>=(ll)(b);i--)
//定数
#define INF (1LL << 60)/2 //10^9:極めて大きい値,∞
//略記
#define PB push_back //vectorヘの挿入
#define MP make_pair //pairのコンストラクタ
#define F first //pairの一つ目の要素
#define S second //pairの二つ目の要素

////////////////////////////////////////////////
struct Edge {
    long long to; // 繋がる所
    long long cost; // 区間距離（コスト）
    Edge(long long to=0, long long cost=0): to(to), cost(cost) {}
};
using Graph = vector<vector<Edge>>;
using P = pair<long, int>;

/* dijkstra(G,s,dis)
    入力：グラフ G, 開始点 s, 距離を格納する（結果） dis
    計算量：O(|E|log|V|)
    副作用：dis が書き換えられる (disがINFなら到達不可)
*/
void dijkstra(const Graph &G, int s, vector<long long> &dis) {
    int N = G.size();
    dis.resize(N, INF);
    priority_queue<P, vector<P>, greater<P>> pq;  // 「仮の最短距離, 頂点」が小さい順に並ぶ
    dis[s] = 0;
    pq.emplace(dis[s], s);
    while (!pq.empty()) {
        P p = pq.top();
        pq.pop();
        int v = p.second;
        if (dis[v] < p.first) {  // 最短距離で無ければ無視
            continue;
        }
        for (auto &e : G[v]) {
            if (dis[e.to] > dis[v] + e.cost) {  // 最短距離候補なら priority_queue に追加
                dis[e.to] = dis[v] + e.cost;
                pq.emplace(dis[e.to], e.to);
            }
        }
    }
}

int main(){
    int N, M;
    cin >> N >> M;
    Graph g0(N),g1(N);
    vector<long long> dis0, dis1, same(N, INF);
    rep(i, M){
        int a, b, c;
        cin >> a >> b >> c;
        a--;b--;
        g0[a].emplace_back(b, c);
        g1[b].emplace_back(a, c);
        if(a==b) same[a]=min(same[a], (ll)c);
    }
    rep(i, N){
        dis0.clear();
        dis1.clear();
        dijkstra(g0, i, dis0);
        dijkstra(g1, i, dis1);
        ll dist=same[i];
        rep(j,N){
            if(j==i) continue;
            dist=min(dist, dis0[j]+dis1[j]);
        }
        if(dist>=INF) cout << "-1" << endl;
        else cout << dist << endl;
    }
    return 0;
}

#include <bits/stdc++.h>

using namespace std;

#define dbg(...) dbs(#__VA_ARGS__, __VA_ARGS__)
template <class T>
void dbs(string str, T t) {
    cerr << str << " : " << t << "\n";
}
template <class T, class... S>
void dbs(string str, T t, S... s) {
    int idx = str.find(',');
    cerr << str.substr(0, idx) << " : " << t << ",";
    dbs(str.substr(idx + 1), s...);
}
template <class S, class T>
ostream &operator<<(ostream &os, const pair<S, T> &p) {
    return os << "(" << p.first << ", " << p.second << ")";
}
template <class T>
void debug(T a, T b) {
    cerr << "[";
    for (T i = a; i != b; ++i) {
        if (i != a)
            cerr << ", ";
        cerr << *i;
    }
    cerr << "]\n";
}

const int N = 100100;

int root[N];

int getRoot(int n) {
    if (root[n] != n) {
        root[n] = getRoot(root[n]);
    }
    return root[n];
}

vector<pair<int, int>> adj[N];
int val[N];
bool visited[N];
int n, m;

void dfs(int u, int edgeVal) {
    val[u] = edgeVal;
    visited[u] = true;

    set<int> childVals;
    for (const auto& e : adj[u]) {
        if (visited[e.first]) {
            continue;
        }

        if (e.second == edgeVal) {
            dfs(e.first, edgeVal % n + 1);
        } else {
            dfs(e.first, e.second);
        }

        childVals.insert(val[e.first]);
    }

    if (val[u] == -1) {
        val[u] = 1;
        while (childVals.count(val[u])) {
            ++val[u];
        }
    }
}

int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n >> m;

    for (int i = 0; i < m; ++i) {
        int u, v, w;
        cin >> u >> v >> w;
        --u, --v;
        adj[u].emplace_back(v, w);
        adj[v].emplace_back(u, w);
    }

    dfs(0, -1);

    for (int i = 0; i < n; ++i) {
        cout << val[i] << "\n";
    }

    return 0;
}
