#include <bits/stdc++.h>
using namespace std;
struct unionfind {
  vector<int> par, sz;
  vector<bool> gomi;
  unionfind() {}
  unionfind(int n) : par(n), sz(n, 1), gomi(n) {
    for (int i = 0; i < n; i++) par[i] = i;
  }
  int find(int x) {
    if (par[x] == x) return x;
    return par[x] = find(par[x]);
  }
  void unite(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y) return;
    if (sz[x] > sz[y]) swap(x, y);
    par[x] = y;
    sz[y] += sz[x];
    if (gomi[x]) gomi[y] = 1;
  }
  bool same(int x, int y) { return find(x) == find(y); }
  int size(int x) { return sz[find(x)]; }
};
const long long int MOD = 1e9 + 7;
int main() {
  int n, m;
  cin >> n >> m;
  unionfind uf(2 * m), uf0(m);
  int k[500050];
  int x1[500050], x2[500050];
  for (int i = 0; i < n; i++) {
    scanf("%d", &k[i]);
    scanf("%d", &x1[i]);
    x1[i]--;
    if (k[i] == 2) {
      scanf("%d", &x2[i]);
      x2[i]--;
    }
  }
  vector<int> ans;
  auto ok = [&](int r) {
    if (!uf.same(r, r + m) && !uf.gomi[uf.find(r)])
      return true;
    else
      return false;
  };
  for (int i = 0; i < n; i++) {
    if (k[i] == 1) {
      if (ok(x1[i])) {
        ans.push_back(i);
      }
      int r = uf.find(x1[i]);
      uf.gomi[r] = 1;
      uf.gomi[r + m] = 1;
    } else {
      if (!uf0.same(x1[i], x2[i])) {
        if (ok(x1[i]) || ok(x2[i])) {
          ans.push_back(i);
        }
      } else {
        if (ok(x1[i]) && !uf.same(x1[i], x2[i] + m)) {
          ans.push_back(i);
        }
      }
      uf.unite(x1[i], x2[i] + m);
      uf.unite(x1[i] + m, x2[i]);
      uf0.unite(x1[i], x2[i]);
    }
  }
  int s = ans.size();
  long long int t = 1;
  for (int i = 0; i < s; i++) {
    t = t * 2 % MOD;
  }
  cout << t << " " << s << endl;
  for (int i = 0; i < s; i++) {
    cout << ans[i] + 1;
    if (i < s - 1) cout << " ";
  }
  cout << endl;
  return 0;
}
