You are given N-1 subsets of \\{1,2,...,N\\}. Let the i-th set be E_i.

Let us choose two distinct elements u_i and v_i from each set E_i, and consider a graph T with N vertices and N-1 edges, whose vertex set is \\{1,2,..,N\\} and whose edge set is (u_1,v_1),(u_2,v_2),...,(u_{N-1},v_{N-1}). Determine if T can be a tree by properly deciding u_i and v_i. If it can, additionally find one instance of (u_1,v_1),(u_2,v_2),...,(u_{N-1},v_{N-1}) such that T is actually a tree.

Constraints

* 2 \leq N \leq 10^5
* E_i is a subset of \\{1,2,..,N\\}.
* |E_i| \geq 2
* The sum of |E_i| is at most 2 \times 10^5.

Input

Input is given from Standard Input in the following format:


N
c_1 w_{1,1} w_{1,2} ... w_{1,c_1}
:
c_{N-1} w_{N-1,1} w_{N-1,2} ... w_{N-1,c_{N-1}}


Here, c_i stands for the number of elements in E_i, and w_{i,1},...,w_{i,c_i} are the c_i elements in c_i. Here, 2 \leq c_i \leq N, 1 \leq w_{i,j} \leq N, and w_{i,j} \neq w_{i,k} (1 \leq j < k \leq c_i) hold.

Output

If T cannot be a tree, print `-1`; otherwise, print the choices of (u_i,v_i) that satisfy the condition, in the following format:


u_1 v_1
:
u_{N-1} v_{N-1}

Output

If T cannot be a tree, print `-1`; otherwise, print the choices of (u_i,v_i) that satisfy the condition, in the following format:


u_1 v_1
:
u_{N-1} v_{N-1}

Examples

Input

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


Output

1 2
1 3
3 4
4 5


Input

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


Output

-1


Input

10
5 1 2 3 4 5
5 2 3 4 5 6
5 3 4 5 6 7
5 4 5 6 7 8
5 5 6 7 8 9
5 6 7 8 9 10
5 7 8 9 10 1
5 8 9 10 1 2
5 9 10 1 2 3


Output

1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
#include <bits/stdc++.h>

using namespace std;

const int inf = 0x3f3f3f3f;

namespace flow {
struct edge_t {
  int to, cap, rev;

  edge_t(int t, int c, int r) {
    to = t;
    cap = c;
    rev = r;
  }
};

int n, source, sink, answer;
vector<vector<edge_t>> adj;
vector<int> dist, current;

void init(int v, int s, int t) {
  n = v;
  source = s;
  sink = t;
  answer = 0;
  adj.clear();
  adj.resize(n);
  dist.resize(n);
  current.resize(n);
}

void add(int x, int y, int c) {
  adj[x].push_back(edge_t(y, c, adj[y].size()));
  adj[y].push_back(edge_t(x, 0, adj[x].size() - 1));
}

bool bfs() {
  queue<int> q;
  for (int i = 0; i < n; ++i) {
    dist[i] = -1;
  }
  dist[source] = 0;
  q.push(source);
  while (!q.empty()) {
    int x = q.front();
    q.pop();
    for (auto e : adj[x]) {
      if (e.cap && !~dist[e.to]) {
        dist[e.to] = dist[x] + 1;
        if (e.to == sink) {
          return true;
        }
        q.push(e.to);
      }
    }
  }
  return false;
}

int dfs(int x, int f) {
  if (x == sink) {
    return f;
  }
  for (int &i = current[x]; ~i; --i) {
    edge_t &e = adj[x][i];
    if (e.cap && dist[e.to] == dist[x] + 1) {
      int w = dfs(e.to, min(e.cap, f));
      if (w) {
        e.cap -= w;
        adj[e.to][e.rev].cap += w;
        return w;
      }
    }
  }
  return 0;
}

int max_flow() {
  while (bfs()) {
    for (int i = 0; i < n; ++i) {
      current[i] = adj[i].size() - 1;
    }
    while (true) {
      int flow = dfs(source, inf);
      if (!flow) {
        break;
      }
      answer += flow;
    }
  }
  return answer;
}
}

using flow::source;
using flow::sink;
using flow::init;
using flow::add;
using flow::adj;
using flow::max_flow;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int n;
  scanf("%d", &n);
  vector<vector<int>> a(n - 1);
  vector<vector<int>> v(n);
  init(n * 2, n * 2 - 2, n * 2 - 1);
  for (int i = 0; i < n - 1; ++i) {
    int s;
    scanf("%d", &s);
    a[i].resize(s);
    add(source, i, 1);
    for (int j = 0; j < s; ++j) {
      scanf("%d", &a[i][j]);
      --a[i][j];
      v[a[i][j]].push_back(i);
      if (a[i][j]) {
        add(i, a[i][j] - 1 + n - 1, 1);
      }
    }
  }
  for (int i = 0; i < n - 1; ++i) {
    add(i + n - 1, sink, 1);
  }
  if (max_flow() != n - 1) {
    puts("-1");
    return 0;
  }
  vector<int> match(n - 1);
  for (int i = 0; i < n - 1; ++i) {
    for (auto e : adj[i]) {
      if (e.to < n * 2 - 2 && !e.cap) {
        match[i] = e.to - (n - 1) + 1;
      }
    }
  }
  vector<bool> visit(n);
  vector<int> parent(n - 1);
  int cc = 0;
  function<void(int)> insert = [&](int x) {
    ++cc;
    visit[x] = true;
    for (auto i : v[x]) {
      if (!visit[match[i]]) {
        parent[i] = x;
        insert(match[i]);
      }
    }
  };
  insert(0);
  if (cc != n) {
    puts("-1");
    return 0;
  }
  for (int i = 0; i < n - 1; ++i) {
    printf("%d %d\n", match[i] + 1, parent[i] + 1);
  }
  return 0;
}
