#include <bits/stdc++.h>
using namespace std;
template <int SZ>
struct DSU {
  int par[SZ];
  int size[SZ];
  DSU() {
    for (int i = 0; i < SZ; i++) par[i] = i, size[i] = 1;
  }
  int get(int node) {
    if (par[node] != node) par[node] = get(par[node]);
    return par[node];
  }
  bool connected(int n1, int n2) { return (get(n1) == get(n2)); }
  int sz(int node) { return size[get(node)]; }
  void unite(int n1, int n2) {
    n1 = get(n1);
    n2 = get(n2);
    if (n1 == n2) return;
    if (rand() % 2) {
      par[n1] = n2;
      size[n2] += size[n1];
    } else {
      par[n2] = n1;
      size[n1] += size[n2];
    }
  }
};
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
  int n, m;
  cin >> n >> m;
  vector<int> ans;
  DSU<500000> G;
  vector<bool> bad(n, false);
  for (int i = 0; i < n; i++) {
    int x;
    cin >> x;
    int a, b;
    if (x == 1) {
      cin >> a;
      a--;
      int par = G.get(a);
      if (!bad[par]) {
        ans.push_back(i);
        bad[par] = true;
      }
    } else {
      cin >> a >> b;
      a--;
      b--;
      int para = G.get(a);
      int parb = G.get(b);
      if (para == parb) {
        if (!bad[para]) {
          ans.push_back(i);
          bad[para] = true;
        }
      } else {
        if (!bad[para] && !bad[parb]) {
          G.unite(a, b);
          ans.push_back(i);
        } else if (!bad[para]) {
          ans.push_back(i);
          bad[para] = true;
        } else if (!bad[parb]) {
          ans.push_back(i);
          bad[parb] = true;
        }
      }
    }
  }
  long long MOD = 1e9 + 7;
  long long num = 1;
  for (int i = 0; i < ans.size(); i++) {
    num = (2 * num) % MOD;
  }
  cout << num << " " << ans.size() << endl;
  for (int i = 0; i < ans.size(); i++) {
    cout << ans[i] + 1 << " ";
  }
  cout << endl;
}
