#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
void add(int& x, int y) { ((x += y) >= MOD) && (x -= MOD); }
int mul(int x, int y) { return x * 1ll * y % MOD; }
int mpow(int a, int p) {
  int res = 1;
  for (; p > 0; p >>= 1, a = mul(a, a)) {
    if (p & 1) {
      res = mul(res, a);
    }
  }
  return res;
}
int inv(int x) {
  int y = mpow(x, MOD - 2);
  assert(mul(x, y) == 1);
  return y;
}
struct Edge {
  int to;
  int val;
  int col;
};
int n;
vector<vector<Edge>> g;
bool read() {
  if (scanf("%d", &n) < 1) {
    return 0;
  }
  g.clear();
  g.resize(n);
  for (int i = 0; i < int(n - 1); ++i) {
    int a, b, val, col;
    scanf("%d%d%d%d", &a, &b, &val, &col);
    --a;
    --b;
    g[a].push_back(Edge{b, val, col});
    g[b].push_back(Edge{a, val, col});
  }
  return 1;
}
vector<int> used;
vector<int> sz;
void dfs_sz(int v, int p) {
  sz[v] = 1;
  for (auto e : g[v]) {
    if (e.to == p || used[e.to]) {
      continue;
    }
    dfs_sz(e.to, v);
    sz[v] += sz[e.to];
  }
}
int get_root(int v) {
  dfs_sz(v, -1);
  const int S = sz[v];
  int p = -1;
  while (1) {
    int mx_to = -1;
    for (auto e : g[v]) {
      if (e.to == p || used[e.to]) {
        continue;
      }
      if (mx_to == -1 || sz[e.to] > sz[mx_to]) {
        mx_to = e.to;
      }
    }
    if (mx_to == -1 || sz[mx_to] * 2 <= S) {
      return v;
    }
    p = v;
    v = mx_to;
  }
  assert(0);
  return -1;
}
struct Elem {
  int x, y, val;
  void print() const {
    ;
    ;
  }
};
void dfs_elems(int v, int p, int x, int y, int val, vector<Elem>& elems) {
  elems.push_back(Elem{x, y, val});
  for (auto e : g[v]) {
    if (e.to == p || used[e.to]) {
      continue;
    }
    dfs_elems(e.to, v, x + (e.col == 0), y + (e.col == 1), mul(val, e.val),
              elems);
  }
}
struct FenwTree {
  vector<int> t;
  FenwTree(int n = 0) { t.assign(n, 1); }
  void change(int pos, int val) {
    for (int i = pos; i < ((int)(t).size()); i |= i + 1) {
      t[i] = mul(t[i], val);
    }
  }
  int get(int r) {
    int ans = 1;
    for (int i = r; i >= 0; i &= i + 1, --i) {
      ans = mul(ans, t[i]);
    }
    return ans;
  }
};
const int ADD = 0;
const int ASK = 1;
struct Event {
  int type;
  int pos;
  int func;
  bool operator<(const Event& e) const {
    if (func != e.func) {
      return func < e.func;
    }
    return (type == ADD) > (e.type == ADD);
  }
};
int calc(vector<Elem> left_________________,
         vector<Elem> right_______________) {
  sort(begin(right_______________), end(right_______________),
       [](const Elem& e1, const Elem& e2) {
         return e1.x - 2 * e1.y < e2.x - 2 * e2.y;
       });
  vector<Event> es;
  for (int i = 0; i < int(((int)(left_________________).size())); ++i) {
    Event e{ASK, i,
            2 * left_________________[i].x - left_________________[i].y};
    es.push_back(e);
  }
  for (int i = 0; i < int(((int)(right_______________).size())); ++i) {
    Event e{ADD, i, right_______________[i].y - 2 * right_______________[i].x};
    es.push_back(e);
  }
  sort(begin(es), end(es));
  int ans = 1;
  FenwTree T(((int)(right_______________).size()));
  for (const auto& e : es) {
    if (e.type == ADD) {
      T.change(e.pos, right_______________[e.pos].val);
    } else {
      const auto elem = left_________________[e.pos];
      int L = -1;
      int R = ((int)(right_______________).size());
      while (L != R - 1) {
        int M = (L + R) >> 1;
        if (right_______________[M].x - 2 * right_______________[M].y <=
            2 * elem.y - elem.x) {
          L = M;
        } else {
          R = M;
        }
      }
      int prod = T.get(L);
      ans = mul(ans, prod);
    }
  }
  return ans;
}
int go(int tmp) {
  const int root = get_root(tmp);
  vector<vector<Elem>> elems;
  for (auto e : g[root]) {
    if (used[e.to]) {
      continue;
    }
    vector<Elem> cur_elems;
    dfs_elems(e.to, root, e.col == 0, e.col == 1, e.val, cur_elems);
    elems.push_back(cur_elems);
  }
  vector<Elem> all_elems;
  for (const auto& cur_elems : elems) {
    copy(begin(cur_elems), end(cur_elems), back_inserter(all_elems));
  }
  int ans = calc(all_elems, all_elems);
  for (const auto& cur_elems : elems) {
    int cur_ans = calc(cur_elems, cur_elems);
    ans = mul(ans, inv(cur_ans));
  }
  for (const auto& elem : all_elems) {
    if (elem.x * 2 >= elem.y && elem.y * 2 >= elem.x) {
      ans = mul(ans, elem.val);
    }
  }
  used[root] = 1;
  for (auto e : g[root]) {
    if (!used[e.to]) {
      int cur = go(e.to);
      ans = mul(ans, cur);
    }
  }
  return ans;
}
int solve() {
  used.assign(n, 0);
  sz.assign(n, 0);
  int ans = go(0);
  return ans;
}
int main() {
  while (read()) {
    printf("%d\n", solve());
  }
  return 0;
}
