#include <bits/stdc++.h>
using namespace std;
static const int MOD = 1000000007;
template <class T>
inline T MIN(const T x, const T y) {
  return (x < y) ? x : y;
}
template <class T>
inline T MAX(const T x, const T y) {
  return (x > y) ? x : y;
}
template <class T>
inline void UPDMIN(T &x, const T y) {
  if (x > y) x = y;
}
template <class T>
inline void UPDMAX(T &x, const T y) {
  if (x < y) x = y;
}
template <class T>
inline int SIZE(const T &x) {
  return (int)x.size();
}
template <class T>
inline int LENGTH(const T &x) {
  return (int)x.length();
}
template <class T1, class T2>
inline pair<T1, T2> MP(const T1 &x, const T2 &y) {
  return make_pair(x, y);
}
inline int BINT(const int x) { return 1 << x; }
inline long long BLLD(const int x) { return 1LL << x; }
inline int BINT_TEST(const int s, const int x) { return (s & BINT(x)) != 0; }
inline int BLLD_TEST(const long long s, const int x) {
  return (s & BLLD(x)) != 0LL;
}
template <class T>
inline T LOWBIT(const T x) {
  return (x ^ (x - 1)) & x;
}
template <class T>
inline int BITCOUNT(const T x) {
  return (!x) ? x : (1 + BITCOUNT(x & (x - 1)));
}
const double PI = acos(-1.0);
const double EPS = 1e-5;
template <class T>
inline T SQR(const T x) {
  return x * x;
}
template <class T1, class T2>
inline T1 POW(const T1 x, const T2 y) {
  if (!y)
    return 1;
  else if ((y & 1) == 0) {
    return SQR(POW(x, y >> 1));
  } else
    return POW(x, y ^ 1) * x;
}
template <class T>
inline T GCD(const T x, const T y) {
  if (x < 0) return GCD(-x, y);
  if (y < 0) return GCD(x, -y);
  return (!y) ? x : GCD(y, x % y);
}
template <class T>
inline T LCM(const T x, const T y) {
  if (x < 0) return LCM(-x, y);
  if (y < 0) return LCM(x, -y);
  return x * (y / GCD(x, y));
}
template <class T>
inline T EEA(const T a, const T b, T &x, T &y) {
  if (a < 0) {
    T d = EEA(-a, b, x, y);
    x = -x;
    return d;
  }
  if (b < 0) {
    T d = EEA(a, -b, x, y);
    y = -y;
    return d;
  }
  if (!b) {
    x = 1;
    y = 0;
    return a;
  } else {
    T d = EEA(b, a % b, x, y);
    T t = x;
    x = y;
    y = t - (a / b) * y;
    return d;
  }
}
template <class T>
inline vector<pair<T, int> > FACTORIZE(T x) {
  vector<pair<T, int> > ret;
  if (x < 0) x = -x;
  for (T i = 2; x > 1;) {
    if (x % i == 0) {
      int cnt = 0;
      for (; x % i == 0; x /= i) cnt++;
      ret.push_back(MP(i, cnt));
    }
    i++;
    if (i > x / i) i = x;
  }
  return ret;
}
template <class T>
inline int ISPRIME(const T x) {
  if (x <= 1) return 0;
  for (T i = 2; SQR(i) <= x; i++)
    if (x % i == 0) return 0;
  return 1;
}
template <class T>
inline T EULARFUNCTION(T x) {
  vector<pair<T, int> > f = FACTORIZE(x);
  for (typename vector<pair<T, int> >::iterator it = f.begin(); it != f.end();
       it++) {
    x = x / it->first * (it->first - 1);
  }
  return x;
}
template <class T>
inline T INVERSEE(const T a, const T b) {
  T x, y;
  EEA(a, b, x, y);
  return x ? x : 1;
}
template <class T>
inline T MOD_STD(const T x, const T m) {
  return (x % m + m) % m;
}
template <class T>
inline T MOD_STD(const T x) {
  return (x % MOD + MOD) % MOD;
}
template <class T>
inline T MOD_ADD(const T x, const T y, const T m) {
  return (x + y) % m;
}
template <class T>
inline T MOD_ADD(const T x, const T y) {
  return (x + y) % MOD;
}
template <class T>
inline void MOD_ADD(T *x, const T y, const T m) {
  *x = (*x + y) % m;
}
template <class T>
inline void MOD_ADD(T *x, const T y) {
  *x = (*x + y) % MOD;
}
template <class T>
inline T MOD_MUL(const T x, const T y, const T m) {
  return (T)((1LL * x * y) % m);
}
template <class T>
inline T MOD_MUL(const T x, const T y) {
  return (T)((1LL * x * y) % MOD);
}
template <class T>
inline void MOD_MUL(T *x, const T y, const T m) {
  *x = (T)((1LL * (*x) * y) % m);
}
template <class T>
inline void MOD_MUL(T *x, const T y) {
  *x = (T)((1LL * (*x) * y) % MOD);
}
template <class T1, class T2>
inline T1 MOD_POW(const T1 x, const T2 y, const T1 m) {
  if (y == 0)
    return 1 % m;
  else if ((y & 1) == 0) {
    T1 z = MOD_POW(x, y >> 1, m);
    return MOD_MUL(z, z, m);
  } else
    return MOD_MUL(MOD_POW(x, y ^ 1, m), x, m);
}
template <class T1, class T2>
inline T1 MOD_POW(const T1 x, const T2 y) {
  if (y == 0)
    return 1 % MOD;
  else if ((y & 1) == 0) {
    T1 z = MOD_POW(x, y >> 1);
    return MOD_MUL(z, z);
  } else
    return MOD_MUL(MOD_POW(x, y ^ 1), x);
}
template <class T>
class MATX {
 private:
  unsigned long hig, wid;
  T *data;
  void __init() {
    this->data = (T *)malloc(sizeof(T) * this->hig * this->wid);
    memset(this->data, 0, sizeof(T) * this->hig * this->wid);
  }

 public:
  MATX() {
    this->hig = this->wid = 1;
    __init();
  }
  MATX(const unsigned long _len) {
    this->hig = this->wid = _len;
    __init();
  }
  MATX(const unsigned long _hig, const unsigned long _wid) {
    this->hig = _hig;
    this->wid = _wid;
    __init();
  }
  MATX(const MATX &rhs) {
    this->hig = rhs.hig;
    this->wid = rhs.wid;
    this->data = (T *)malloc(sizeof(T) * this->hig * this->wid);
    for (unsigned long x = 0; x < this->hig; x++)
      for (unsigned long y = 0; y < this->wid; y++)
        this->data[x * this->wid + y] = rhs.at(x, y);
  }
  ~MATX() { free(this->data); }
  T &operator()(const unsigned long x, const unsigned long y) {
    if (x >= this->hig || y >= this->wid) return (*(T *)NULL);
    return this->data[x * wid + y];
  }
  MATX &operator=(const MATX &rhs) {
    if (this->hig != rhs.hig || this->wid != rhs.wid) {
      free(this->data);
      this->hig = rhs.hig;
      this->wid = rhs.wid;
      this->data = (T *)malloc(sizeof(T) * this->hig * this->wid);
    }
    for (unsigned long x = 0; x < this->hig; x++)
      for (unsigned long y = 0; y < this->wid; y++)
        this->data[x * this->wid + y] = rhs.at(x, y);
    return *this;
  }
  const MATX operator+(const MATX &opn) const {
    MATX ret(*this);
    for (unsigned long x = 0; x < ret.hig; x++)
      for (unsigned long y = 0; y < ret.wid; y++)
        ret.data[x * ret.wid + y] += opn.at(x, y);
    return ret;
  }
  const MATX operator-(const MATX &opn) const {
    MATX ret(*this);
    for (unsigned long x = 0; x < ret.hig; x++)
      for (unsigned long y = 0; y < ret.wid; y++)
        ret.data[x * ret.wid + y] -= opn.at(x, y);
    return ret;
  }
  const MATX operator*(const MATX &opn) const {
    MATX ret(this->hig, opn.wid);
    const unsigned long len = MIN(this->wid, opn.hig);
    for (unsigned long x = 0; x < ret.hig; x++)
      for (unsigned long y = 0; y < ret.wid; y++)
        for (unsigned long z = 0; z < len; z++)
          ret.data[x * ret.wid + y] += this->at(x, z) * opn.at(z, y);
    return ret;
  }
  const MATX mul(const MATX &opn) const { return *this * opn; }
  template <class T2>
  const MATX mul(const MATX &opn, const T2 m) const {
    MATX ret(this->hig, opn.wid);
    const unsigned long len = MIN(this->wid, opn.wid);
    for (unsigned long x = 0; x < ret.hig; x++)
      for (unsigned long y = 0; y < ret.wid; y++)
        for (unsigned long z = 0; z < len; z++)
          MOD_ADD(&ret.data[x * ret.wid + y],
                  MOD_MUL(this->at(x, z), opn.at(z, y), m), m);
    return ret;
  }
  MATX &operator+=(const MATX &rhs) {
    *this = *this + rhs;
    return *this;
  }
  MATX &operator-=(const MATX &rhs) {
    *this = *this - rhs;
    return *this;
  }
  MATX &operator*=(const MATX &rhs) {
    *this = *this * rhs;
    return *this;
  }
  const MATX pow(const unsigned long p) const {
    MATX buff(*this), ret(this->hig, this->wid);
    ret.set_one();
    if (p > 0)
      for (unsigned long i = 1;; i <<= 1) {
        if (p & i) ret *= buff;
        buff *= buff;
        if (i > (p >> 1)) break;
      }
    return ret;
  }
  template <class T2>
  const MATX pow(const unsigned long p, const T2 m) const {
    MATX buff(*this), ret(this->hig, this->wid);
    ret.set_one();
    if (p > 0)
      for (unsigned long i = 1;; i <<= 1) {
        if (p & i) ret = ret.mul(buff, m);
        buff = buff.mul(buff, m);
        if (i > (p >> 1)) break;
      }
    return ret;
  }
  const T at(const unsigned long x, const unsigned long y) const {
    if (x >= this->hig || y >= this->wid) return 0;
    return this->data[x * wid + y];
  }
  void show() const {
    for (unsigned long x = 0; x < this->hig; x++) {
      for (unsigned long y = 0; y < this->wid; y++)
        cout << this->at(x, y) << " ";
      cout << endl;
    }
  }
  void set_one() {
    for (unsigned long x = 0; x < this->hig; x++)
      for (unsigned long y = 0; y < this->wid; y++)
        this->data[x * this->wid + y] = (x == y) ? 1 : 0;
  }
};
template <class T>
class Complex {
 public:
  T r, i;
  Complex(T x = 0.0, T y = 0.0) {
    this->r = x;
    this->i = y;
  }
  Complex operator+(const Complex &opn) const {
    return Complex(this->r + opn.r, this->i + opn.i);
  }
  Complex operator-(const Complex &opn) const {
    return Complex(this->r - opn.r, this->i - opn.i);
  }
  Complex operator*(const Complex &opn) const {
    return Complex(this->r * opn.r - this->i * opn.i,
                   this->r * opn.i + this->i * opn.r);
  }
};
int n, m, cnt;
int u[110000], v[110000], c[110000], f[110000];
int nbs[110000], nxt[210000], dst[210000], enm;
int msk[110000];
inline int find(const int u) {
  if (f[u] != u) f[u] = find(f[u]);
  return f[u];
}
inline void addedge(const int u, const int v) {
  nxt[++enm] = nbs[u];
  nbs[u] = enm;
  dst[enm] = v;
  nxt[++enm] = nbs[v];
  nbs[v] = enm;
  dst[enm] = u;
}
int mark(const int u, const int k) {
  msk[u] = k;
  for (int i = nbs[u]; i; i = nxt[i]) {
    int v = dst[i];
    if (~msk[v]) {
      if (msk[v] == k) return 0;
      continue;
    }
    if (!mark(v, k ^ 1)) return 0;
  }
  return 1;
}
int main() {
  while (scanf("%d%d", &n, &m) != EOF) {
    for (int i = 0; i < n; i++) f[i] = i;
    for (int i = 0; i < m; i++) {
      scanf("%d%d%d", &u[i], &v[i], &c[i]);
      u[i]--;
      v[i]--;
    }
    for (int i = 0; i < m; i++) {
      if (!c[i]) continue;
      if (find(u[i]) == find(v[i])) continue;
      f[find(u[i])] = find(v[i]);
    }
    memset(msk, 0xff, sizeof(msk));
    memset(nbs, 0, sizeof(nbs));
    enm = 0;
    int flag = 0;
    for (int i = 0; i < m; i++) {
      if (c[i]) continue;
      if (find(u[i]) == find(v[i])) {
        flag = 1;
        break;
      }
      addedge(find(u[i]), find(v[i]));
    }
    cnt = 0;
    for (int i = 0; !flag && i < n; i++) {
      if (find(i) != i || ~msk[i]) continue;
      cnt++;
      if (!mark(i, 0)) {
        flag = 1;
        break;
      }
    }
    if (flag) {
      printf("0\n");
      break;
    }
    printf("%d\n", MOD_POW(2, cnt - 1));
  }
  return 0;
}
