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

struct edge {
    int to, color;
};

vector<vector<edge>> graph;

int main() {
    ll N, M;
    cin >> N >> M;
    graph.resize(N);
    set<P> uset;
    rep(i, M) {
        int u, v, c;
        cin >> u >> v >> c;
        --u;
        --v;
        --c;
        if (uset.find(P(u, v)) == uset.end()) {
            graph[u].push_back(edge{v, c});
            graph[v].push_back(edge{u, c});
            uset.insert(P(u, v));
            uset.insert(P(v, u));
        }
    }
    vector<ll> ans(N);
    set<int> s;
    rep(i, N) {
        s.insert(i);
    }

    for (edge e : graph[0]) {
        s.erase(e.color);
    }
    ans[0] = *s.lower_bound(0);

    queue<int> q;
    vector<bool> already(N, false);
    q.push(0);
    already[0] = true;
    while (!q.empty()) {
        int parent = q.front();
        q.pop();

        for (edge e : graph[parent]) {
            if (already[e.to]) {
                continue;
            }
            if (e.color == ans[parent]) {
                ans[e.to] = (ans[parent] + 1) % N;
            } else {
                ans[e.to] = e.color;
            }
            q.push(e.to);
            already[e.to] = true;
        }
    }

    rep(i, N) {
        cout << ans[i] + 1 << "\n";
    }

    return 0;
}
#include <bits/stdc++.h>
//#include <atcoder/all>

using namespace std;
//using namespace atcoder;

using ll = long long;
using vll = vector<ll>;
using vvll = vector<vll>;
using pll = pair<ll, ll>;
using vpll = vector<pll>;
using ld = long double;
using vld = vector<ld>;
using vb = vector<bool>;

#define rep(i, n) for (ll i = 0; i < (n); i++)
#ifdef LOCAL
#define dbg(x) cerr << __LINE__ << " : " << #x << " = " << (x) << endl
#else
#define dbg(x) true
#endif

template <class T> bool chmin(T& a, T b) {
    if(a > b) { a = b; return true; }
    else return false;
}

template <class T> bool chmax(T& a, T b) {
    if(a < b) { a = b; return true; }
    else return false;
}

template <class T> ostream& operator<<(ostream& s, const vector<T>& a) {
    for(auto i : a) s << i << ' ';
    return s;
}

constexpr int INF = 1 << 30;
constexpr ll INFL = 1LL << 62;
constexpr ld EPS = 1e-12;
ld PI = acos(-1.0);

struct mint {
    static const long long mod = 1000000007;
    long long x;
    mint(long long x = 0) : x((x % mod + mod) % mod) {}
    mint operator-() const { return mint(-x);}
    mint& operator+=(const mint& a) {if ((x += a.x) >= mod) x -= mod; return *this;}
    mint& operator-=(const mint& a) {if ((x += mod - a.x) >= mod) x -= mod; return *this;}
    mint& operator*=(const mint& a) {(x *= a.x) %= mod; return *this;}

    friend const mint operator+(const mint& a, const mint& b) { mint ret = a; return ret += b; }
    friend const mint operator-(const mint& a, const mint& b) { mint ret = a; return ret -= b; }
    friend const mint operator*(const mint& a, const mint& b) { mint ret = a; return ret *= b; }
    friend ostream& operator<<(ostream& s, const mint& a) { return s << a.x; }

    mint pow(long long t) const {
        if (!t) return 1;
        mint a = pow(t >> 1);
        a *= a;
        if (t & 1) a *= *this;
        return a;
    }

    // for prime mod
    mint inv() const { return pow(mod - 2);}
    mint& operator/=(const mint a) { return (*this) *= a.inv();}
    friend const mint operator/(const mint& a, const mint& b) { mint ret = a; return ret /= b; }
};

void solve() {
    ll n;
    cin >> n;
    vector<vpll> g(n);
    rep(_, n-1) {
        ll u, v, w;
        cin >> u >> v >> w;
        --u, --v;
        g[u].emplace_back(v, w);
        g[v].emplace_back(u, w);
    }

    using vi = vector<int>;
    using vvi = vector<vi>;
    vector<vvi> dp(n, vvi(60, vi(2)));   // 頂点、ビット、0か1

    // subtreeから計算するためのdfs
    function<void(ll, ll)> dfs = [&](ll v, ll p) -> void {
        for(auto [nv, w] : g[v]) {
            if(nv == p) continue;
            dfs(nv, v);
            rep(i, 60) {
                ll wb = (w >> i) & 1;
                ++dp[v][i][wb]; // nvとの辺の寄与
                rep(j, 2) {
                    ll nj = (j+wb)%2;
                    dp[v][i][nj] += dp[nv][i][j];
                }
            }
        }
    };
    dfs(0, -1);

    // 親から渡すためのdfs
    function<void(ll, ll)> dfs2 = [&](ll v, ll p) -> void {
        for(auto [nv, w] : g[v]) {
            if(nv == p) continue;
            rep(i, 60) {
                ll wb = (w >> i) & 1;
                rep(j, 2) {
                    ll dp_add = dp[v][i][j];
                    if(j == wb) --dp_add;
                    ll nj = (j+wb)%2;
                    dp_add -= dp[nv][i][nj];
                    dp[nv][i][nj] += dp_add;
                    if(nj == wb) ++dp[nv][i][nj];
                }
            }
            dfs2(nv, v);
        }
    };
    dfs2(0, -1);

    mint ans = 0;
    rep(bit, 60) {
        mint bitm = mint(1ll << bit);
        mint sum_dp = 0;
        rep(i, n) sum_dp += dp[i][bit][1];
        ans += bitm * sum_dp;
    }
    ans /= 2;
    cout << ans << endl;
    return;
}

int main() {
    std::cin.tie(nullptr);
    std::ios_base::sync_with_stdio(false);
    cout << fixed << setprecision(15);
    solve();
}