Tree is a connected undirected graph that has no cycles. Edge cactus is a connected undirected graph without loops and parallel edges, such that each edge belongs to at most one cycle.

Vasya has an edge cactus, each edge of this graph has some color.

Vasya would like to remove the minimal number of edges in such way that his cactus turned to a tree. Vasya wants to make it in such a way that there were edges of as many different colors in the resulting tree, as possible. Help him to find how many different colors can the resulting tree have.

Input

The first line contains two integers: n, m (2 ≤ n ≤ 10 000) — the number of vertices and the number of edges in Vasya's graph, respectively.

The following m lines contain three integers each: u, v, c (1 ≤ u, v ≤ n, u ≠ v, 1 ≤ c ≤ m) — the numbers of vertices connected by the corresponding edge, and its color. It is guaranteed that the described graph is indeed an edge cactus.

Output

Output one integer: the maximal number of different colors that the resulting tree can have.

Examples

Input

4 4
1 2 4
2 3 1
3 4 2
4 2 3


Output

3


Input

7 9
1 2 1
2 3 4
3 1 5
1 4 5
4 5 2
5 1 6
1 6 4
6 7 6
7 1 3


Output

6
#include <bits/stdc++.h>
using namespace std;
vector<int> v[100100];
int v1[100100];
int v2[100100];
int color[100100];
bool in_cycle[100100];
int getnext(int s, int eid) {
  if (v1[eid] == s)
    return v2[eid];
  else
    return v1[eid];
}
vector<vector<int> > cycles;
int stcnt = 0;
int st[100100];
int vis[100100];
map<pair<int, int>, int> wtf;
vector<int> getedges(vector<int> cycle) {
  vector<int> res;
  for (int i = 0; i < (int)(cycle).size(); i++) {
    int cur = cycle[i];
    int nxt = cycle[(i + 1) % (int)(cycle).size()];
    res.push_back(wtf[make_pair(cur, nxt)]);
  }
  return res;
}
void go(int s, int lst = -1) {
  if (vis[s] == 2) {
    vector<int> cycle;
    for (int i = stcnt - 1; i >= 0; i--) {
      cycle.push_back(st[i]);
      if (st[i] == s) break;
    }
    cycles.push_back(getedges(cycle));
    return;
  }
  if (vis[s] == 1) return;
  st[stcnt++] = s;
  vis[s] = 2;
  for (int i = 0; i < (int)(v[s]).size(); i++) {
    int eid = v[s][i];
    int nxt = getnext(s, eid);
    if (nxt == lst) continue;
    go(nxt, s);
  }
  vis[s] = 1;
  stcnt--;
}
int good_color[100100];
vector<int> who_cycles[100100];
bool bad_cycle[100100];
void make_bad_cycle(int cyc);
void make_good_color(int col);
void make_bad_cycle(int cyc) {
  if (bad_cycle[cyc]) return;
  bad_cycle[cyc] = true;
  for (int i = 0; i < (int)(cycles[cyc]).size(); i++) {
    int eid = cycles[cyc][i];
    int col = color[eid];
    make_good_color(col);
  }
}
void make_good_color(int col) {
  if (good_color[col]) return;
  good_color[col] = true;
  for (int i = 0; i < (int)(who_cycles[col]).size(); i++) {
    make_bad_cycle(who_cycles[col][i]);
  }
}
vector<int> graph[100100];
int F[100100];
int C[100100];
int frfr[100100];
int toto[100100];
bool VIS[100100];
vector<int> VISITED;
bool dfs(int s, int T) {
  if (s == T) return true;
  if (VIS[s]) return false;
  VIS[s] = true;
  VISITED.push_back(s);
  for (int i = 0; i < (int)(graph[s]).size(); i++) {
    int nxt = toto[graph[s][i]];
    int fff = F[graph[s][i]];
    int ccc = C[graph[s][i]];
    if (ccc - fff > 0 && dfs(nxt, T)) {
      F[graph[s][i]]++;
      F[graph[s][i] ^ 1]--;
      return true;
    }
  }
  return false;
}
int solve(int S, int T) {
  int res = 0;
  while (dfs(S, T)) {
    while (!VISITED.empty()) {
      VIS[VISITED.back()] = false;
      VISITED.pop_back();
    }
    res++;
  }
  return res;
}
void add_edge(int FROM, int TO, int eid, int c) {
  graph[FROM].push_back(eid);
  graph[TO].push_back(eid ^ 1);
  frfr[eid] = FROM;
  toto[eid] = TO;
  frfr[eid ^ 1] = TO;
  toto[eid ^ 1] = FROM;
  C[eid] = c;
  C[eid ^ 1] = 0;
  F[eid] = 0;
  F[eid ^ 1] = 0;
}
int main() {
  int n, m;
  scanf("%d %d", &n, &m);
  for (int i = 1; i <= m; i++) {
    int a, b, c;
    scanf("%d %d %d", &a, &b, &c);
    v1[i] = a;
    v2[i] = b;
    color[i] = c;
    v[a].push_back(i);
    v[b].push_back(i);
    wtf[make_pair(a, b)] = i;
    wtf[make_pair(b, a)] = i;
  }
  go(1);
  for (int i = 0; i < (int)(cycles).size(); i++) {
    for (int j = 0; j < (int)(cycles[i]).size(); j++) {
      int eid = cycles[i][j];
      int col = color[eid];
      in_cycle[eid] = true;
      who_cycles[col].push_back(i);
    }
  }
  for (int i = 1; i <= m; i++) {
    if (!in_cycle[i]) {
      make_good_color(color[i]);
    }
  }
  for (int i = 1; i <= m; i++) {
    sort(who_cycles[i].begin(), who_cycles[i].end());
    for (int j = 1; j < (int)(who_cycles[i]).size(); j++) {
      if (who_cycles[i][j] == who_cycles[i][j - 1]) {
        make_bad_cycle(who_cycles[i][j]);
      }
    }
  }
  int res = 0;
  int S = 0;
  vector<vector<int> > good_cycles;
  for (int i = 0; i < (int)(cycles).size(); i++) {
    if (!bad_cycle[i]) {
      vector<int> tmp;
      for (int j = 0; j < (int)(cycles[i]).size(); j++) {
        tmp.push_back(color[cycles[i][j]]);
      }
      good_cycles.push_back(tmp);
    }
  }
  int CUREID = 0;
  if ((int)(good_cycles).size() != 0) {
    int CUR = 1;
    int CYC_BEGIN = CUR;
    for (int i = 0; i < (int)(good_cycles).size(); i++) {
      add_edge(S, CUR, CUREID, (int)(good_cycles[i]).size() - 1);
      CUREID += 2;
      CUR++;
    }
    int CYC_END = CUR - 1;
    int COL_BEGIN = CUR;
    int COL_END = CUR + m - 1;
    for (int i = 0; i < (int)(good_cycles).size(); i++) {
      for (int j = 0; j < (int)(good_cycles[i]).size(); j++) {
        int col = good_cycles[i][j];
        int FROM = i + 1;
        int TO = COL_BEGIN + col - 1;
        add_edge(FROM, TO, CUREID, 1);
        CUREID += 2;
      }
    }
    int T = COL_END + 1;
    for (int i = COL_BEGIN; i <= COL_END; i++) {
      int FROM = i;
      int TO = T;
      add_edge(FROM, TO, CUREID, 1);
      CUREID += 2;
    }
    res += solve(S, T);
  }
  for (int i = 1; i <= m; i++) {
    if (good_color[i]) {
      res++;
    }
  }
  printf("%d\n", res);
  return 0;
}
