#include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
using namespace std;
template <class T>
ostream& operator<<(ostream& os, vector<T> V) {
  os << "[ ";
  for (auto v : V) os << v << " ";
  return os << "]";
}
template <class L, class R>
ostream& operator<<(ostream& os, pair<L, R> P) {
  return os << "(" << P.first << "," << P.second << ")";
}
template <typename Arg1>
void __f(const char* name, Arg1&& arg1) {
  cerr << name << " : " << arg1 << endl;
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args) {
  const char* comma = strchr(names + 1, ',');
  cerr.write(names, comma - names) << " : " << arg1 << " | ";
  __f(comma + 1, args...);
}
const long long INF = 0x3f3f3f3f;
const long long LINF = 0x3f3f3f3f3f3f3f3f;
const long long mod = (119 << 23) + 1;
const long long M = 1e9 + 7;
const long long N = 1e5 + 5;
struct UF {
  vector<long long> e;
  long long nc;
  UF(long long n) : e(n, -1), nc(n) {}
  bool same_set(long long a, long long b) { return find(a) == find(b); }
  long long size(long long x) { return -e[find(x)]; }
  long long find(long long x) { return e[x] < 0 ? x : e[x] = find(e[x]); }
  long long comp() { return nc; }
  bool join(long long a, long long b) {
    a = find(a), b = find(b);
    if (a == b) return false;
    if (e[a] > e[b]) swap(a, b);
    e[a] += e[b];
    e[b] = a;
    nc--;
    return true;
  }
};
long long power(long long x, long long y, long long m) {
  long long res = 1;
  while (y > 0) {
    if (y & 1) res = res * x % m;
    y /= 2;
    x = x * x % m;
  }
  return res;
}
signed main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);
  cout << fixed << setprecision(15);
  long long n, m;
  cin >> n >> m;
  UF uf(n + 1);
  UF red(n + 1);
  vector<vector<long long> > adj(n + 1);
  bool flag = false;
  vector<long long> va, vb, vc;
  for (long long i = 0; i < m; ++i) {
    long long a, b, c;
    cin >> a >> b >> c;
    uf.join(a, b);
    if (c == 0) {
      va.push_back(a), vb.push_back(b), vc.push_back(c);
    } else {
      red.join(a, b);
    }
  }
  for (long long i = 0; i < (long long)(va).size(); ++i) {
    long long a = va[i], b = vb[i], c = vc[i];
    if (red.same_set(a, b)) flag = true;
    adj[red.find(a)].push_back(red.find(b));
    adj[red.find(b)].push_back(red.find(a));
  }
  vector<long long> side(n + 1, -1);
  bool is_bipartite = true;
  queue<long long> q;
  for (long long st = 0; st < n + 1; ++st) {
    if (side[st] == -1) {
      q.push(st);
      side[st] = 0;
      while (!q.empty()) {
        long long v = q.front();
        q.pop();
        for (long long u : adj[v]) {
          if (side[u] == -1) {
            side[u] = side[v] ^ 1;
            q.push(u);
          } else {
            is_bipartite &= side[u] != side[v];
          }
        }
      }
    }
  }
  if (!is_bipartite) flag = true;
  if (flag)
    cout << 0 << '\n';
  else
    cout << power(2, uf.comp() - 2, M) << '\n';
}
