#include <bits/stdc++.h>
using namespace std;
template <class T>
bool mmin(T& a, const T& b) {
  return b < a ? a = b, 1 : 0;
}
template <class T>
bool mmax(T& a, const T& b) {
  return a < b ? a = b, 1 : 0;
}
void yesno(bool c) { cout << (c ? "YES" : "NO") << '\n'; }
void yes() { yesno(true); }
void no() { yesno(false); }
void imp() { cout << "-1" << '\n'; }
const int inf = 0x3f3f3f3f;
const long long infl = 0x3f3f3f3f3f3f3f3f;
struct base_graph {
  int n, ecnt = 0;
  vector<int> from, to;
  vector<long long> w;
  bool is_wei;
  base_graph(int n, bool is_wei = false) : n(n), is_wei(is_wei) {}
  virtual int add(int a, int b, long long ww = 0) = 0;
  int base_add(int a, int b, long long ww = 0) {
    assert(0 <= a && a < n);
    assert(0 <= b && b < n);
    from.push_back(a);
    to.push_back(b);
    if (is_wei) w.push_back(ww);
    return ecnt++;
  }
  void readin(int m, bool add_rev = false, int offset = 1) {
    reserve(add_rev ? 2 * m : m);
    for (int i = 0; i < m; i++) {
      int a, b, ww = 0;
      cin >> a >> b;
      a -= offset;
      b -= offset;
      if (is_wei) cin >> ww;
      add(a, b, ww);
      if (add_rev) add(b, a, ww);
    }
  }
  void readin_tree(bool add_rev, int offset = 1) {
    int m = n - 1;
    reserve(add_rev ? 2 * m : m);
    for (int i = 2; i <= m; i++) {
      int p;
      cin >> p;
      int a = i - offset;
      add(a, p);
      if (add_rev) add(p, a);
    }
  }

 protected:
  void reserve(int m) {
    from.reserve(m);
    to.reserve(m);
    if (is_wei) w.reserve(m);
  }
};
struct my_hash {
  const uint64_t RANDOM =
      chrono::steady_clock::now().time_since_epoch().count();
  static uint64_t splitmix64(uint64_t x) {
    x += 0x9e3779b97f4a7c15;
    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
    x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
    return x ^ (x >> 31);
  }
  size_t operator()(uint64_t x) const { return splitmix64(x + RANDOM); }
};
using myset = unordered_set<int, my_hash>;
struct undir_graph : public base_graph {
  vector<vector<pair<int, int>>> edg;
  undir_graph(int n, bool is_wei = false) : base_graph(n, is_wei), edg(n) {}
  int add(int a, int b, long long ww = 0) {
    if (b > a) swap(a, b);
    int e = base_add(a, b, ww);
    edg[a].push_back({e, b});
    edg[b].push_back({e, a});
    return e;
  }
  void readin(int m, int offset = 1) { base_graph::readin(m, false, offset); }
  void readin_tree(int offset = 1) { base_graph::readin_tree(false, offset); }
};
template <class T, class Comp = less<T>>
struct prioset {
  using P = pair<T, int>;
  struct pcomp {
    Comp cmp;
    bool operator()(const P& lhs, const P& rhs) const {
      if (lhs.first == rhs.first) return lhs.second < rhs.second;
      return cmp(lhs.first, rhs.first);
    }
  };
  set<P, pcomp> s;
  unordered_map<int, T> m;
  void push(T val, int id) {
    if (m.count(id)) {
      s.erase({m[id], id});
    }
    s.insert({val, id});
    m[id] = val;
  }
  void pop() {
    m.erase(s.begin()->second);
    s.erase(s.begin());
  }
  T topval() { return s.begin()->first; }
  T topvalpop() {
    T ans = topval();
    pop();
    return ans;
  }
  int topid() { return s.begin()->second; }
  int topidpop() {
    int ans = topid();
    pop();
    return ans;
  }
  P top() { return *s.begin(); }
  P toppop() {
    P ans = top();
    pop();
    return ans;
  }
  int size() { return s.size(); }
  bool empty() { return s.size() == 0; }
};
using uset = myset;
void solve() {
  int n, m, k;
  cin >> n >> m >> k;
  undir_graph g(n);
  g.readin(m);
  for (int i = 0; i < (n); i++) sort((g.edg[i]).begin(), (g.edg[i]).end());
  vector<myset> edg(n);
  for (int i = 0; i < (n); i++)
    for (auto [e, v] : g.edg[i]) edg[i].insert(v);
  vector<int> deg(n), alive(n, 1);
  for (int i = 0; i < (n); i++) deg[i] = ((int)(edg[i]).size());
  prioset<int> s;
  for (int i = 0; i < (n); i++) {
    s.push(deg[i], i);
  }
  while (!s.empty()) {
    int u = s.topid();
    int val = s.topval();
    if (val >= k - 1) break;
    s.pop();
    alive[u] = 0;
    for (auto v : edg[u]) {
      if (!alive[v]) continue;
      deg[v]--;
      s.push(deg[v], v);
    }
  }
  while (!s.empty()) {
    int u = s.topid();
    int val = s.topval();
    s.pop();
    ;
    alive[u] = false;
    if (val >= k) {
      cout << 1 << " " << (((int)(s).size()) + 1) << '\n';
      cout << (u + 1) << " ";
      while (!s.empty()) {
        cout << (s.topid() + 1) << " ";
        s.pop();
      }
      cout << '\n';
      return;
    } else if (val < k - 1) {
      for (auto v : edg[u]) {
        if (!alive[v]) continue;
        deg[v]--;
        s.push(deg[v], v);
      }
    } else {
      vector<int> group;
      group.push_back(u);
      for (auto v : edg[u]) {
        if (alive[v]) group.push_back(v);
      }
      int ok = 1;
      for (int i = 0; i < ((int)(group).size()); i++) {
        for (int j = i + 1; j < ((int)(group).size()); j++) {
          if (edg[group[i]].find(group[j]) == edg[group[i]].end()) {
            ok = 0;
            break;
          }
        }
      }
      if (ok) {
        cout << 2 << '\n';
        for (int v : group) {
          cout << (v + 1) << " ";
        }
        cout << '\n';
        return;
      }
      for (auto v : edg[u]) {
        if (!alive[v]) continue;
        deg[v]--;
        s.push(deg[v], v);
      }
    }
  }
  imp();
}
int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  int tc = 1;
  cin >> tc;
  while (tc--) solve();
  return 0;
}
