#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
typedef long long ll;
typedef pair<int, int> P;
typedef vector<int> vi;
typedef vector<ll> vl;

// input
int N, M;
vi U, V, C;


void input() {
    cin >> N >> M;
    U = V = C = vi(M);
    rep(i, M) cin >> U[i] >> V[i] >> C[i];
}


struct edge {
    int num;
    int from;
    int to;
    ll cost;
};


struct node {
    int num;
    int depth;
    edge rev;
    vi parent;
    vi children;
    vector<edge> edges;
    node(int n) : num(n), depth(-1), parent(30, -1) {}
};


struct tree {
    int m;
    vector<edge> edges;
    vector<node> nodes;
    
    tree(int n) {
        rep(i, n) nodes.push_back(node(i));
        m = 0;
    }

    void add_edge(int u, int v, ll cost) {
        edge e1{m, u, v, cost};
        edge e2{m, v, u, cost};
        m++;
        nodes[u].edges.push_back(e1);
        nodes[v].edges.push_back(e2);
    }

    void make_tree(int v) {
        make_tree(v, -1, 0, edge{-1, -1, v, -1});
    }

    void make_tree(int u, int p, int d, edge rev) {
        node &w1 = nodes[u];
        w1.parent[0] = p;
        w1.depth = d;
        w1.rev = rev;
        edges.push_back(rev);
        for (int k = 1; k <= int(log2(d)); k++) {
            node &par = nodes[w1.parent[k - 1]];
            w1.parent[k] = par.parent[k - 1];
        }
        for (edge &e : w1.edges) {
            int v = e.to;
            if (v == p) continue;
            node &w2 = nodes[v];
            if (w2.depth != -1) continue;
            w1.children.push_back(w2.num);
            make_tree(v, u, d + 1, e);
        }
    }

    int lca(int u, int v) {
        if (u == v) return u;
        if (nodes[u].depth != nodes[v].depth) {
            if (nodes[u].depth > nodes[v].depth) swap(u, v);
            while (nodes[u].depth != nodes[v].depth) {
                int k = log2(nodes[v].depth - nodes[u].depth);
                v = nodes[v].parent[k];
            }
            if (nodes[u].num == nodes[v].num) return nodes[u].num;
        }
        node &w1 = nodes[u];
        node &w2 = nodes[v];
        int k = log2(w1.depth) + 1;
        while (k > 0 && w1.parent[k] == w2.parent[k]) k--;
        return lca(w1.parent[k], w2.parent[k]);
    }

    int dist(int u, int v) {
        int x = lca(u, v);
        node &w = nodes[lca(u, v)];
        int ret = (nodes[u].depth - w.depth) + (nodes[v].depth - w.depth);
        return ret;
    }

    bool is_on_path(int u, int v, int x) {
        if (dist(u, v) == dist(u, x) + dist(x, v)) return true;
        else return false;
    }
};


void solve(int u, tree &tr, vi &ans) {
    node &w1 = tr.nodes[u];
    if (u > 0) {
        if (ans[w1.parent[0]] == w1.rev.cost) {
            ans[u] = w1.rev.cost + 1;
            if (ans[u] == N + 1) ans[u] = 1;
        } else {
            ans[u] = w1.rev.cost;
        }
    }
    for (int v : w1.children) {
        solve(v, tr, ans);
    }
}


int main() {
    input();
    tree tr(N);
    rep(i, M) {
        int u = U[i] - 1, v = V[i] - 1, c = C[i];
        tr.add_edge(u, v, c);
    }
    tr.make_tree(0);
    vi ans(N, 1);
    solve(0, tr, ans);
    rep(i, N) cout << ans[i] << endl;
}

#include <bits/stdc++.h>
#define st first
#define nd second
#define PQ priority_queue

using ll = long long ;
using namespace std;
using pii = pair<int,int>;
const int N = 2e5 + 10;
const int MOD = 0;
vector<pii> gr[N];
bool vis[N];
int  a[N];
void dfs(int node, int val){
	vis[node] = true;
	a[node] = val > 0 ? val : (val == -1 ? 2 : 1);
	for(auto it: gr[node]){
		if(!vis[it.st]){
			dfs(it.st, a[node] == it.nd ? -a[node] : it.nd);
		}
	}
	return;
}
int main(){
	int n, m, x, y, z;
	scanf("%d %d" ,&n, &m);
	for(int i = 1; i <= m; i++){
		scanf("%d %d %d", &x, &y, &z);
		gr[x].push_back({y, z});
		gr[y].push_back({x, z});
	}
	dfs(1, 1);
	for(int i = 1; i <= n; i++){
		printf("%d\n", a[i]);
	}


}