#include <bits/stdc++.h>
#pragma comment(linker, "/STACK:66777216")
#pragma warning(disable : 4996)
#pragma hdrstop
using namespace std;
void inputFiles();
struct Graph {
  enum Type { GT_WEIGHTED = 1, GT_FLOW = 2 };
  int *from, *to, *parent;
  long long* weight;
  vector<vector<int> > edges;
  int maxVertexNum, maxEdgesNum;
  int vertexCount, edgesCount;
  Graph(const int maxVertexNum, const int maxEdgesNum, const int mask = 0)
      : maxVertexNum(maxVertexNum), maxEdgesNum(maxEdgesNum) {
    from = new int[maxEdgesNum];
    to = new int[maxEdgesNum];
    edges.resize(maxVertexNum);
    weight = (mask & (1 << GT_WEIGHTED) ? new long long[maxEdgesNum] : NULL);
    vertexCount = 0;
    edgesCount = 0;
  }
  virtual ~Graph() {
    edges.clear();
    if (from != NULL) {
      delete[] from;
    }
    if (to != NULL) {
      delete[] to;
    }
    if (weight != NULL) {
      delete[] weight;
    }
    if (parent != NULL) {
      delete[] parent;
    }
  }
  void clear(int size = -1) {
    edgesCount = 0;
    size = (size == -1 ? ((int)edges.size()) : min(size, ((int)edges.size())));
    if (size == -1) {
      size = ((int)edges.size());
    }
    for (int i = 0; i < size; ++i) {
      edges[i].clear();
    }
  }
  int addDirectedEdge(const int _from, const int _to) {
    from[edgesCount] = _from;
    to[edgesCount] = _to;
    edges[_from].push_back(edgesCount);
    return edgesCount++;
  }

 private:
};
struct UndirectedGraph : Graph {
  UndirectedGraph(const int maxVertexNum, const int maxEdgesNum,
                  const int mask = 0)
      : Graph(maxVertexNum, maxEdgesNum << 1, mask) {}
  void initGraph(const int _vertexCount) { vertexCount = _vertexCount; }
  void addBidirectionalEdge(const int _from, const int _to) {
    addDirectedEdge(_from, _to);
    addDirectedEdge(_to, _from);
  }

 private:
};
const int MOD = 1000000007;
const int MAXN = 111111;
int n, m, x, y, t, w[MAXN], etp[MAXN << 1];
UndirectedGraph graph(MAXN, MAXN);
bool dfs(int v, int col) {
  w[v] = col;
  bool ret = true;
  for (auto& it : graph.edges[v]) {
    int to = graph.to[it], tp = etp[it];
    if (!w[to]) {
      ret &= dfs(to, (tp ? col : 3 - col));
    } else {
      ret &= (w[to] == (tp ? col : 3 - col));
    }
  }
  return ret;
}
void solve(istream& in, ostream& out) {
  inputFiles();
  in >> n >> m;
  graph.clear(n);
  graph.initGraph(n);
  for (int i = 0; i < m; ++i) {
    in >> x >> y >> t;
    --x, --y;
    etp[graph.edgesCount] = etp[graph.edgesCount + 1] = t;
    graph.addBidirectionalEdge(x, y);
  }
  bool ok = true;
  memset(w, 0, sizeof(w));
  int cnt = 0;
  for (int i = 0; i < n && ok; ++i) {
    if (!w[i]) {
      ok &= dfs(i, 1);
      ++cnt;
    }
  }
  if (!ok) {
    out << 0 << endl;
    return;
  }
  int ans = 1;
  for (int i = 1; i < cnt; ++i) {
    if ((ans <<= 1) >= MOD) {
      ans -= MOD;
    }
  }
  out << ans << endl;
}
inline void inputFiles() {}
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  istream& in = cin;
  ostream& out = cout;
  solve(in, out);
  return 0;
}
