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>
#pragma comment(linker, "/STACK:256000000")
using namespace std;
const long double PI = acosl((long double)-1.0);
const long long LINF = (long long)4e18;
int test;
const int MAXN = 20005;
struct edge {
  int v1, v2, color;
  inline int get_to(int v) { return v == v1 ? v2 : v1; }
};
int n, m;
edge e[MAXN];
vector<vector<int> > g, eg;
vector<vector<int> > cycles;
int used[MAXN];
int ccount;
int colors[MAXN];
bool del[MAXN];
int ptr[MAXN];
pair<int, int> dfs_init(int v, int p) {
  used[v] = 1;
  pair<int, int> res = pair<int, int>(0, 0);
  for (int i = 0; i < (int)g[v].size(); i++) {
    int num = g[v][i];
    int to = e[num].get_to(v);
    if (to == p) {
      continue;
    }
    if (used[to]) {
      if (used[to] == 1) {
        res = pair<int, int>(to, ++ccount);
        cycles[ccount].push_back(num);
      }
    } else {
      pair<int, int> r = dfs_init(to, v);
      if (r.second) {
        cycles[r.second].push_back(num);
      }
      if (r.first && r.first != v) {
        res = r;
      }
    }
  }
  used[v] = 2;
  return res;
}
void init() {
  scanf("%d%d", &n, &m);
  g.resize(n + 1);
  for (int i = 1; i <= m; i++) {
    scanf("%d%d%d", &e[i].v1, &e[i].v2, &e[i].color);
    g[e[i].v1].push_back(i);
    g[e[i].v2].push_back(i);
  }
}
bool edges_cmp(int num1, int num2) { return e[num1].color < e[num2].color; }
inline void make_edge(int v1, int v2) {
  eg[v1].push_back(v2);
  eg[v2].push_back(v1);
}
void get_init_colors() {
  for (int i = 1; i <= m; i++) {
    colors[e[i].color]++;
  }
  for (int i = 1; i <= ccount; i++) {
    sort(cycles[i].begin(), cycles[i].end(), edges_cmp);
    del[cycles[i][0]] = true;
    colors[e[cycles[i][0]].color]--;
  }
}
void get_graph() {
  eg.resize(m + 1);
  for (int i = 1; i <= ccount; i++) {
    for (int j = 1; j < (int)cycles[i].size(); j++) {
      make_edge(cycles[i][j - 1], cycles[i][j]);
    }
  }
  for (int j = 1; j <= m; j++) {
    int last = 0;
    for (int i = 1; i <= ccount; i++) {
      while (ptr[i] < (int)cycles[i].size() && e[cycles[i][ptr[i]]].color < j) {
        ptr[i]++;
      }
      if (ptr[i] < (int)cycles[i].size() && e[cycles[i][ptr[i]]].color == j) {
        if (last) {
          make_edge(last, cycles[i][ptr[i]]);
        }
        last = cycles[i][ptr[i]];
      }
    }
  }
}
bool dfs(int v, int p) {
  used[v] = 1;
  if (colors[e[v].color]) {
    return true;
  }
  for (int i = 0; i < (int)eg[v].size(); i++) {
    int to = eg[v][i];
    if (used[to]) {
      continue;
    }
    if (e[v].color != e[to].color) {
      del[v] = false;
      colors[e[v].color]++;
      del[to] = true;
      colors[e[to].color]--;
    }
    if (dfs(to, v)) {
      return true;
    }
  }
  if (p && e[v].color != e[p].color) {
    del[v] = false;
    colors[e[v].color]++;
    del[p] = true;
    colors[e[p].color]--;
  }
  return false;
}
void edit_colors() {
  for (int i = 1; i <= ccount; i++) {
    for (int j = 0; j < (int)cycles[i].size(); j++) {
      int num = cycles[i][j];
      if (del[num]) {
        if (!colors[e[num].color]) {
          memset(used, 0, sizeof(used));
          dfs(num, 0);
        }
        break;
      }
    }
  }
}
int calc_ans() {
  int res = 0;
  for (int i = 1; i <= m; i++) {
    if (colors[i]) {
      res++;
    }
  }
  return res;
}
void solve() {
  init();
  cycles.resize(m);
  dfs_init(1, 0);
  get_init_colors();
  get_graph();
  edit_colors();
  printf("%d\n", calc_ans());
}
void test_output() {}
int main() {
  srand(333);
  double start = clock();
  int tests = 1;
  for (test = 1; test <= tests; test++) {
    solve();
  }
  fprintf(stderr, "%.5lf\n", (clock() - start) / CLOCKS_PER_SEC);
  return 0;
}
