Heidi got tired of deciphering the prophecy hidden in the Tree of Life and decided to go back to her headquarters, rest a little and try there. Of course, she cannot uproot the Tree and take it with her, so she made a drawing of the Tree on a piece of paper. On second thought, she made more identical drawings so as to have n in total (where n is the number of vertices of the Tree of Life) – who knows what might happen?

Indeed, on her way back Heidi was ambushed by a group of zombies. While she managed to fend them off, they have damaged her drawings in a peculiar way: from the i-th copy, the vertex numbered i was removed, along with all adjacent edges. In each picture, the zombies have also erased all the vertex numbers and relabeled the remaining n - 1 vertices arbitrarily using numbers 1 to n (fortunately, each vertex still has a distinct number). What's more, the drawings have been arbitrarily shuffled/reordered.

Now Heidi wants to recover the Tree of Life from her descriptions of all the drawings (as lists of edges).

Input

The first line of the input contains Z ≤ 20 – the number of test cases. Z descriptions of single test cases follow.

In each test case, the first line of input contains numbers n (2 ≤ n ≤ 100) and k (where k is the number of drawings; we have k = n). In the following lines, the descriptions of the k drawings are given. The description of the i-th drawing is a line containing mi – the number of edges in this drawing, followed by mi lines describing edges, each of which contains two space-separated integers –- the numbers of the two vertices connected by the edge.

Output

If Heidi's drawings cannot possibly come from a single tree, you should output the word NO. Otherwise, output one line containing the word YES and n - 1 lines describing any tree that Heidi's drawings could have come from. For every edge you should output the numbers of the vertices that it connects, separated with a single space. If there are many solutions, print any of them.

Example

Input

1
5 5
2
4 1
2 1
1
3 1
3
4 1
4 3
2 1
3
3 1
3 2
4 1
3
2 1
3 2
4 2


Output

YES
2 5
4 2
3 2
5 1
#include <bits/stdc++.h>
using namespace std;
const int mo[2] = {998244353, 1000000007};
pair<long long, long long> operator+(const pair<long long, long long> &a,
                                     const pair<long long, long long> &b) {
  return pair<long long, long long>(
      (a.first + 1ll * b.first * b.first + 19260817) % mo[0],
      (a.second + 1ll * b.second * b.second + 18931226) % mo[1]);
}
pair<long long, long long> operator-(const pair<long long, long long> &a,
                                     const pair<long long, long long> &b) {
  return pair<long long, long long>(
      (a.first + 2ll * mo[0] - 1ll * b.first * b.first % mo[0] - 19260817) %
          mo[0],
      (a.second + 2ll * mo[1] - 1ll * b.second * b.second % mo[1] - 18931226) %
          mo[1]);
}
struct edge {
  int to, next;
};
const int N = 105;
bool GG;
int n;
struct forest {
  edge e[N * 2];
  int head[N], tot;
  int fa[N], m, vis[N];
  pair<long long, long long> hsh[N], fhsh[N];
  void clear() {
    memset(head, 0, sizeof(head));
    tot = 0;
  }
  int get(int x) { return x == fa[x] ? x : fa[x] = get(fa[x]); }
  void add(int x, int y) {
    e[++tot] = (edge){y, head[x]};
    head[x] = tot;
    e[++tot] = (edge){x, head[y]};
    head[y] = tot;
  }
  void init() {
    clear();
    for (int i = (int)(1); i <= (int)(n); i++) fa[i] = i;
    scanf("%d", &m);
    for (int i = (int)(1); i <= (int)(m); i++) {
      int x, y;
      scanf("%d%d", &x, &y);
      if (get(x) != get(y))
        fa[get(x)] = get(y);
      else
        GG = 1;
      add(x, y);
    }
    int tmp = 0;
    for (int i = (int)(1); i <= (int)(n); i++) tmp += (head[i] != 0);
    if (tmp == n) GG = 1;
  }
  void dfs1(int x, int fa) {
    hsh[x] = (pair<long long, long long>){459, 47293};
    vis[x] = 1;
    for (int i = head[x]; i; i = e[i].next)
      if (e[i].to != fa) {
        dfs1(e[i].to, x);
        hsh[x] = hsh[x] + hsh[e[i].to];
      }
  }
  void dfs2(int x, int fa) {
    for (int i = head[x]; i; i = e[i].next)
      if (e[i].to != fa) {
        hsh[e[i].to] = hsh[e[i].to] + (hsh[x] - hsh[e[i].to]);
        dfs2(e[i].to, x);
      }
  }
  pair<long long, long long> calc() {
    memset(vis, 0, sizeof(vis));
    for (int i = (int)(1); i <= (int)(n); i++)
      if (!vis[i] && head[i]) {
        dfs1(i, 0);
        dfs2(i, 0);
      }
    pair<long long, long long> ans(0, 0);
    for (int i = (int)(1); i <= (int)(n); i++)
      if (head[i]) {
        ans.first = (ans.first + hsh[i].first) % mo[1];
        ans.second = (ans.second + hsh[i].second) % mo[1];
      }
    return ans;
  }
  void output() {
    for (int i = (int)(1); i <= (int)(n); i++)
      for (int j = head[i]; j; j = e[j].next)
        if (i < e[j].to) printf("%d %d\n", i, e[j].to);
  }
} f[N];
vector<pair<long long, long long> > A, B;
void solve() {
  A.clear();
  int spe = GG = 0;
  scanf("%d%*d", &n);
  for (int i = (int)(1); i <= (int)(n); i++) {
    f[i].init();
    if (!spe && f[i].m == n - 2) spe = i;
  }
  if (GG || !spe) {
    puts("NO");
    return;
  }
  for (int i = (int)(1); i <= (int)(n); i++) A.push_back(f[i].calc());
  sort(A.begin(), A.end());
  int p = 1;
  for (;; p++)
    if (!f[spe].head[p]) break;
  for (int i = (int)(1); i <= (int)(n); i++)
    if (i != p) {
      B.clear();
      forest tr = f[spe], G;
      tr.add(i, p);
      for (int j = (int)(1); j <= (int)(n); j++) {
        G.clear();
        for (int x = (int)(1); x <= (int)(n); x++)
          if (x != j)
            for (int k = tr.head[x]; k; k = tr.e[k].next)
              if (tr.e[k].to != j && x < tr.e[k].to) G.add(x, tr.e[k].to);
        B.push_back(G.calc());
      }
      sort(B.begin(), B.end());
      if (A == B) {
        puts("YES");
        tr.output();
        return;
      }
    }
  puts("NO");
}
int main() {
  int T;
  scanf("%d", &T);
  while (T--) solve();
}
