Problem: 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

Solution (in CPP):

Solution:
#include <bits/stdc++.h>
using namespace std;
void _dbg(string) { cout << endl; }
template <class H, class... T>
void _dbg(string s, H h, T... t) {
  int l = s.find(',');
  cout << s.substr(0, l) << " = " << h << ", ";
  _dbg(s.substr(l + 1), t...);
}
template <class T, class U>
ostream& operator<<(ostream& o, const pair<T, U>& p) {
  o << "(" << p.first << "," << p.second << ")";
  return o;
}
template <class T>
ostream& operator<<(ostream& o, const vector<T>& v) {
  o << "[";
  for (T t : v) {
    o << t << ",";
  }
  o << "]";
  return o;
}
vector<int> tree[105][105];
map<vector<int>, int> conv;
int pre[105];
int val[105];
bool checked[105];
vector<int> center(int v, vector<int>* vec) {
  auto bfs = [&](int d) {
    queue<pair<int, int>> q;
    q.push(make_pair((d), (-1)));
    val[d] = 0;
    int last = d;
    while (q.size()) {
      auto p = q.front();
      q.pop();
      int node = p.first;
      int from = p.second;
      checked[node] = true;
      for (auto to : vec[node])
        if (to != from) {
          q.push(make_pair((to), (node)));
          val[to] = val[node] + 1;
          pre[to] = node;
        }
      last = node;
    }
    return last;
  };
  int p = bfs(v);
  int q = bfs(p);
  int d = q;
  for (int i = (int)(0); i < (int)(val[q] / 2); i++) d = pre[d];
  if (val[q] % 2 == 1)
    return {d, pre[d]};
  else
    return {d};
}
pair<int, int> tree2idx(int i, vector<int>* vec) {
  auto c = center(i, vec);
  function<int(int, int)> dfs = [&](int d, int from) {
    vector<int> ord;
    queue<pair<int, int>> q;
    q.push(make_pair((d), (from)));
    while (q.size()) {
      auto p = q.front();
      q.pop();
      int node = p.first;
      int prev = p.second;
      ord.push_back((node));
      pre[node] = prev;
      for (auto to : vec[node])
        if (to != prev) {
          q.push(make_pair((to), (node)));
        }
    }
    reverse((ord).begin(), (ord).end());
    for (auto node : ord) {
      vector<int> v;
      for (auto to : vec[node])
        if (to != pre[node]) v.push_back((val[to]));
      sort((v).begin(), (v).end());
      if (conv.count(v) == 0) conv[v] = conv.size();
      val[node] = conv[v];
    }
    return val[d];
  };
  if (c.size() == 1) {
    return make_pair((-1), (dfs(c[0], -1)));
  } else if (c.size() == 2) {
    int a = dfs(c[0], c[1]);
    int b = dfs(c[1], c[0]);
    return make_pair((min(a, b)), (max(a, b)));
  } else
    assert(false);
}
bool solve() {
  int n, k;
  scanf("%d %d", &n, &k);
  assert(n == k);
  for (int i = (int)(0); i < (int)(100); i++)
    for (int j = (int)(0); j < (int)(100); j++) tree[i][j].clear();
  conv.clear();
  vector<vector<pair<int, int>>> nums(k);
  vector<vector<pair<int, int>>> pq(k);
  for (int i = (int)(0); i < (int)(k); i++) {
    int m;
    scanf("%d", &m);
    pq[i].resize(m);
    for (int j = (int)(0); j < (int)(m); j++) {
      int a, b;
      scanf("%d %d", &a, &b);
      a--;
      b--;
      pq[i][j] = make_pair((a), (b));
      tree[i][a].push_back((b));
      tree[i][b].push_back((a));
    }
    fill(checked, checked + n, false);
    for (int j = (int)(0); j < (int)(n); j++)
      if (!checked[j] && tree[i][j].size() > 0)
        nums[i].push_back((tree2idx(j, tree[i])));
    sort((nums[i]).begin(), (nums[i]).end());
  }
  for (int i = (int)(0); i < (int)(k); i++)
    if (pq[i].size() >= n - 1) return false;
  int cand = -1;
  for (int i = (int)(0); i < (int)(k); i++)
    if (pq[i].size() == n - 2) cand = i;
  if (cand == -1) return false;
  vector<bool> used(n, false);
  for (auto p : pq[cand]) {
    used[p.first] = used[p.second] = true;
  }
  int xxx = 0;
  while (used[xxx]) xxx++;
  sort((nums).begin(), (nums).end());
  for (int i = (int)(0); i < (int)(n); i++)
    if (i != xxx) {
      pq[cand].push_back((make_pair((i), (xxx))));
      auto check = [&]() {
        vector<vector<pair<int, int>>> nnums(n);
        for (int j = (int)(0); j < (int)(n); j++) {
          for (int kk = (int)(0); kk < (int)(n); kk++) tree[100][kk].clear();
          for (auto p : pq[cand])
            if (p.first != j && p.second != j) {
              tree[100][p.first].push_back((p.second));
              tree[100][p.second].push_back((p.first));
            }
          fill(checked, checked + n, false);
          for (int kk = (int)(0); kk < (int)(n); kk++)
            if (!checked[kk] && tree[100][kk].size() > 0)
              nnums[j].push_back((tree2idx(kk, tree[100])));
          sort((nnums[j]).begin(), (nnums[j]).end());
        }
        sort((nnums).begin(), (nnums).end());
        return nnums == nums;
      };
      if (check()) {
        puts("YES");
        for (auto p : pq[cand]) {
          printf("%d %d\n", p.first + 1, p.second + 1);
        }
        return true;
      }
      pq[cand].pop_back();
    }
  return false;
}
int main() {
  int z;
  scanf("%d", &z);
  for (int i = (int)(0); i < (int)(z); i++) {
    if (!solve()) puts("NO");
  }
  return 0;
}