#include <bits/stdc++.h>
using namespace std;
template <class T>
inline void init(T &x) {
  x = 0;
  char ch = getchar();
  bool t = 0;
  for (; ch > '9' || ch < '0'; ch = getchar())
    if (ch == '-') t = 1;
  for (; ch >= '0' && ch <= '9'; ch = getchar())
    x = (x << 1) + (x << 3) + (ch - 48);
  if (t) x = -x;
  return;
}
int n, m;
const int N = 1e5 + 10;
const int mod = 1e9 + 7;
struct edge {
  int to, next, w, col;
} a[N << 1];
int head[N], cnt = 0;
inline void add(int x, int y, int z, int col) {
  a[++cnt] = (edge){y, head[x], z, col};
  head[x] = cnt;
}
inline int fpow(int x, int k) {
  int ret = 1;
  for (; k; k >>= 1, x = (long long)x * x % mod)
    if (k & 1) ret = (long long)ret * x % mod;
  return ret;
}
int size[N], RT, SZ, vis[N], f[N];
void Find_rt(int u, int fa) {
  size[u] = 1;
  f[u] = 0;
  for (int v, i = head[u]; i; i = a[i].next) {
    v = a[i].to;
    if (v == fa || vis[v]) continue;
    Find_rt(v, u);
    size[u] += size[v];
    f[u] = max(f[u], size[v]);
  }
  f[u] = max(f[u], SZ - size[u]);
  if ((!RT) || f[u] < f[RT]) RT = u;
  return;
}
int ans = 1;
struct pack {
  int Mul, v1, v2;
  pack() {}
  pack(int a, int b, int c) { Mul = a, v1 = b, v2 = c; }
};
pack stk[N];
int top = 0;
void Dfs(int u, int fa, int Mul, int bla, int whi) {
  stk[++top] = pack(Mul, bla, whi);
  for (int v, i = head[u]; i; i = a[i].next) {
    v = a[i].to;
    if (v == fa || vis[v]) continue;
    Dfs(v, u, (long long)Mul * a[i].w % mod, bla + a[i].col,
        whi + (a[i].col ^ 1));
  }
  return;
}
int F;
const int MAXN = N << 1;
int Cnt[MAXN], tr[MAXN], H = 0, que[MAXN];
struct Dat {
  int Mul, v1, v2, tp;
  inline bool operator<(const Dat B) const {
    if (v1 != B.v1) return v1 < B.v1;
    if (v2 != B.v2) return v2 < B.v2;
    return tp < B.tp;
  }
} P[MAXN];
int pnum = 0;
inline void Clear(int p) {
  while (p <= H) Cnt[p] = 0, tr[p] = 1, p += ((p) & (-p));
  return;
}
inline void Update(int p, int mu, int c) {
  for (; p <= H; p += ((p) & (-p)))
    tr[p] = (long long)tr[p] * mu % mod, Cnt[p] += c;
  return;
}
inline void Query(int p, int &cnt, int &Mul) {
  for (; p; p -= ((p) & (-p)))
    cnt += Cnt[p], Mul = (long long)Mul * tr[p] % mod;
  return;
}
Dat tmp[MAXN];
int t = 0;
void CDQ(int l, int r) {
  if (l >= r) return;
  int mid = l + r >> 1;
  CDQ(l, mid);
  CDQ(mid + 1, r);
  int p = l, q = mid + 1;
  t = p - 1;
  while (p <= mid && q <= r) {
    if (P[p] < P[q]) {
      tmp[++t] = P[p];
      if (P[p].tp == 0) Update(P[p].v2, P[p].Mul, 1);
      ++p;
    } else {
      tmp[++t] = P[q];
      if (P[q].tp == 1) {
        int Cnt = 0, Mul = 1;
        Query(P[q].v2, Cnt, Mul);
        if (F == 1)
          ans = (long long)ans * Mul % mod * fpow(P[q].Mul, Cnt) % mod;
        else
          ans = (long long)ans *
                fpow((long long)Mul * fpow(P[q].Mul, Cnt) % mod, mod - 2) % mod;
      }
      ++q;
    }
  }
  int np = p;
  while (p <= mid) tmp[++t] = P[p++];
  while (q <= r) {
    tmp[++t] = P[q];
    if (P[q].tp == 1) {
      int Cnt = 0, Mul = 1;
      Query(P[q].v2, Cnt, Mul);
      if (F == 1)
        ans = (long long)ans * Mul % mod * fpow(P[q].Mul, Cnt) % mod;
      else
        ans = (long long)ans *
              fpow((long long)Mul * fpow(P[q].Mul, Cnt) % mod, mod - 2) % mod;
    }
    ++q;
  }
  for (int i = l; i < np; ++i)
    if (P[i].tp == 0) Clear(P[i].v2);
  for (int i = l; i <= r; ++i) P[i] = tmp[i];
  return;
}
void Calc(int L, int R) {
  pnum = 0;
  H = 0;
  for (int i = L; i <= R; ++i) {
    int bla = stk[i].v1, whi = stk[i].v2;
    int v1 = 2 * bla - whi;
    int v2 = 2 * whi - bla;
    P[++pnum] = (Dat){stk[i].Mul, v1, v2, 1};
    P[++pnum] = (Dat){stk[i].Mul, -v1, -v2, 0};
    que[++H] = v2, que[++H] = -v2;
  }
  sort(que + 1, que + 1 + H);
  H = unique(que + 1, que + 1 + H) - que - 1;
  for (int i = 1; i <= pnum; ++i)
    P[i].v2 = lower_bound(que + 1, que + 1 + H, P[i].v2) - que;
  CDQ(1, pnum);
}
void Divide(int u) {
  vis[u] = 1;
  F = -1;
  top = 0;
  for (int v, i = head[u]; i; i = a[i].next) {
    v = a[i].to;
    if (vis[v]) continue;
    int Pre = top;
    Dfs(v, u, a[i].w, a[i].col, a[i].col ^ 1);
    Calc(Pre + 1, top);
  }
  F = 1;
  Calc(1, top);
  for (int i = 1; i <= top; ++i)
    if (stk[i].v1 <= (stk[i].v2 << 1) && stk[i].v2 <= (stk[i].v1 << 1))
      ans = (long long)ans * stk[i].Mul % mod;
  for (int v, i = head[u]; i; i = a[i].next) {
    v = a[i].to;
    if (vis[v]) continue;
    RT = 0;
    SZ = size[v];
    Find_rt(v, u);
    Divide(RT);
  }
  return;
}
int main() {
  init(n);
  int u, v, w, col;
  for (int i = 1; i < MAXN; ++i) tr[i] = 1, Cnt[i] = 0;
  for (int i = 2; i <= n; ++i) {
    init(u), init(v), init(w);
    init(col);
    add(u, v, w, col), add(v, u, w, col);
  }
  SZ = n;
  Find_rt(1, 0);
  Divide(RT);
  printf("%d\n", ans);
}
