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;
inline long long in() {
  int32_t x;
  scanf("%d", &x);
  return x;
}
inline long long lin() {
  long long x;
  scanf("%lld", &x);
  return x;
}
inline string get() {
  char ch[2000010];
  scanf("%s", ch);
  return ch;
}
inline void read(long long *a, long long n) {
  for (long long i = 0; i < n; i++) a[i] = in();
}
const long long maxn = 1e6 + 10;
const long long maxm = 1e6 + 10;
const long long maxlg = 21;
const long long base = 29;
const long long mod = 1e9 + 7;
const long long INF = 1e18 + 10;
stack<long long> st;
long long h[maxn], l[maxn], cnt = 2;
long long source = 0, sink = 1;
bool mark[maxn], mark2[maxn];
struct edge {
  long long v, u, flow, cap;
  edge() {}
  edge(long long v, long long u, long long flow, long long cap)
      : v(v), u(u), flow(flow), cap(cap) {}
} e[maxm];
struct connection {
  long long u, col, id;
  connection() {}
  connection(long long u, long long col, long long id)
      : u(u), col(col), id(id) {}
};
vector<connection> graph[maxn];
long long cur = 0;
vector<long long> g[maxn];
inline void add_edge(long long v, long long u, long long flow, long long cap) {
  g[v].push_back(cur);
  e[cur++] = {v, u, flow, cap};
  g[u].push_back(cur);
  e[cur++] = {u, v, -flow, 0};
}
vector<long long> finalColors;
vector<long long> colors[maxn];
inline void tarjan(long long node, long long fa = -1) {
  h[node] = l[node] = fa == -1 ? 0 : h[fa] + 1;
  st.push(node);
  mark[node] = true;
  for (auto u : graph[node]) {
    if (!mark[u.u]) {
      tarjan(u.u, node);
      l[node] = min(l[node], l[u.u]);
    } else
      l[node] = min(l[node], h[u.u]);
  }
  if (h[node] - 1 == l[node]) {
    long long x;
    vector<long long> nodes;
    do {
      x = st.top();
      st.pop();
      nodes.push_back(x);
      mark2[x] = true;
    } while (x != node);
    mark2[fa] = true;
    for (auto nd : nodes) {
      for (auto u : graph[nd]) {
        if (mark2[u.u]) {
          colors[cnt].push_back(u.col);
        }
      }
    }
    for (auto nd : nodes) mark2[nd] = false;
    mark2[fa] = false;
    long long curNode = cnt++;
    add_edge(source, curNode, 0, (long long)nodes.size());
  }
}
long long ptr[maxn], di[maxn], q[maxn];
inline bool bfs() {
  memset(di, 63, (cnt + (long long)finalColors.size() + 2) * sizeof di[0]);
  di[source] = 0;
  long long h = 0, t = 1;
  q[0] = source;
  while (h < t) {
    long long v = q[h++];
    for (long long i = 0; i < g[v].size(); i++) {
      long long u = e[g[v][i]].u;
      if (e[g[v][i]].flow == e[g[v][i]].cap) continue;
      long long cst = di[v] + 1;
      if (cst < di[u]) {
        di[u] = cst;
        q[t++] = u;
      }
    }
  }
  return di[sink] < INF;
}
inline long long push(long long node, long long flow) {
  if (node == sink || flow == 0) return flow;
  for (; ptr[node] < g[node].size(); ptr[node]++) {
    long long u = e[g[node][ptr[node]]].u;
    long long cap = e[g[node][ptr[node]]].cap, fl = e[g[node][ptr[node]]].flow;
    if (di[u] != di[node] + 1) continue;
    if (cap == fl) continue;
    long long pushed = push(u, min(flow, cap - fl));
    if (pushed == 0) continue;
    e[g[node][ptr[node]]].flow += pushed;
    e[g[node][ptr[node]] ^ 1].flow -= pushed;
    return pushed;
  }
  return 0;
}
inline long long max_flow() {
  long long x = 0;
  while (bfs()) {
    memset(ptr, 0, (cnt + (long long)finalColors.size() + 2) * sizeof ptr[0]);
    while (long long pushed = push(source, INF)) {
      x += pushed;
    }
  }
  return x;
}
int32_t main() {
  long long n = in(), m = in();
  for (long long i = 0; i < m; i++) {
    long long v = in(), u = in(), col = in();
    finalColors.push_back(col);
    graph[v].push_back({u, col, i});
    graph[u].push_back({v, col, i});
  }
  tarjan(1);
  sort(finalColors.begin(), finalColors.end());
  finalColors.resize(
      (long long)(unique(finalColors.begin(), finalColors.end()) -
                  finalColors.begin()));
  for (long long i = 2; i < cnt; i++) {
    for (long long j = 0; j < colors[i].size(); j++) {
      long long id = (long long)(lower_bound(finalColors.begin(),
                                             finalColors.end(), colors[i][j]) -
                                 finalColors.begin());
      add_edge(i, id + cnt, 0, 1);
    }
  }
  for (long long j = 0; j < finalColors.size(); j++)
    add_edge(j + cnt, sink, 0, 1);
  cout << max_flow();
}
