#include <bits/stdc++.h>
using namespace std;
const long long MOD = 1e9 + 7;
namespace mod {
template <long long MOD>
struct Int {
  long long x;
  Int(long long x = 0) : x((x % MOD + MOD) % MOD) {}
  Int operator-() const { return Int<MOD>(-x); }
  Int& operator+=(const Int<MOD> a) {
    if ((x += a.x) >= MOD) x -= MOD;
    return *this;
  }
  Int& operator-=(const Int<MOD> a) {
    if ((x += MOD - a.x) >= MOD) x -= MOD;
    return *this;
  }
  Int& operator*=(const Int<MOD> a) {
    (x *= a.x) %= MOD;
    return *this;
  }
  Int operator+(const Int<MOD> a) const { return Int<MOD>(*this) += a; }
  Int operator-(const Int<MOD> a) const { return Int<MOD>(*this) -= a; }
  Int operator*(const Int<MOD> a) const { return Int<MOD>(*this) *= a; }
  Int pow(long long t) const {
    if (!t) return 1;
    Int<MOD> a = pow(t >> 1);
    a *= a;
    if (t & 1) a *= *this;
    return a;
  }
  Int inv() const { return pow(MOD - 2); }
  Int& operator/=(const Int<MOD> a) { return *this *= a.inv(); }
  Int operator/(const Int<MOD> a) const { return Int<MOD>(*this) /= a; }
};
}  // namespace mod
std::istream& operator>>(std::istream& is, const mod::Int<MOD>& a) {
  return is >> a.x;
}
std::ostream& operator<<(std::ostream& os, const mod::Int<MOD>& a) {
  return os << a.x;
}
class UnionFind {
  vector<int> _nodes;

 public:
  UnionFind(int size) : _nodes(vector<int>(size + 1, -1)) {}
  int findRoot(int a) {
    if (_nodes[a] == -1) return a;
    const int root = findRoot(_nodes[a]);
    _nodes[a] = root;
    return root;
  }
  void unite(int a, int b) {
    const int rootA = findRoot(a);
    const int rootB = findRoot(b);
    if (rootA == rootB) return;
    _nodes[rootB] = rootA;
  }
};
class FEuclidsNightmare {
 public:
  void solve(std::istream& in, std::ostream& out) {
    int n, m;
    in >> n >> m;
    vector<vector<int>> v(n);
    vector<vector<int>> edges(m + 1);
    vector<int> bit(m + 1, false);
    UnionFind uf(m + 1);
    mod::Int<MOD> answer;
    vector<int> t;
    for (long long i = (0); i < (n); i++) {
      int k;
      in >> k;
      v[i] = vector<int>(k);
      for (long long j = (0); j < (k); j++) in >> v[i][j];
      if (k == 2) {
        if (bit[v[i][0]] && bit[v[i][1]]) continue;
        if (uf.findRoot(v[i][0]) == uf.findRoot(v[i][1])) continue;
        t.emplace_back(i + 1);
        if (bit[v[i][0]]) bit[v[i][1]] = true;
        if (bit[v[i][1]]) bit[v[i][0]] = true;
        edges[v[i][0]].emplace_back(v[i][1]);
        edges[v[i][1]].emplace_back(v[i][0]);
      } else {
        if (bit[v[i][0]]) continue;
        bit[v[i][0]] = true;
        for (const auto& e : edges[v[i][0]]) bit[e] = true;
        t.emplace_back(i + 1);
      }
    }
    out << mod::Int<MOD>(2).pow(t.size()) << " " << t.size() << endl;
    for (int i = 0; i < t.size(); i++) {
      out << t[i] << (i == t.size() - 1 ? "\n" : " ");
    };
  }
};
signed main() {
  FEuclidsNightmare solver;
  std::istream& in(std::cin);
  std::ostream& out(std::cout);
  solver.solve(in, out);
  return 0;
}
