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;
long long rdtsc() {
  long long tmp;
  asm("rdtsc" : "=A"(tmp));
  return tmp;
}
inline int myrand() { return rand(); }
inline int rnd(int x) { return myrand() % x; }
const int inf = (int)1.01e9;
const long double eps = 1e-9;
const long double pi = acos((long double)-1.0);
void precalc() {}
namespace Flow {
const static long long inff = (long long)1e18;
struct Edge {
  int t;
  long long f, c;
  Edge() {}
  Edge(int _t, long long _f, long long _c) : t(_t), f(_f), c(_c) {}
};
struct Graph {
  vector<Edge> edges;
  int n;
  vector<vector<int> > es;
  Graph(int _n = 0, int _m = 0) : n(_n), es(_n) {
    edges.reserve(_m);
    edges.clear();
    st.reserve(n);
    dist.reserve(n);
    its.reserve(n);
  }
  void adde(int s, int t, long long c, long long c2 = 0) {
    assert(0 <= s && s < n);
    assert(0 <= t && t < n);
    es[s].push_back(((int)(edges).size()));
    edges.push_back(Edge(t, 0, c));
    es[t].push_back(((int)(edges).size()));
    edges.push_back(Edge(s, 0, c2));
  }
  vector<int> st, its;
  vector<long long> dist;
  long long dfs(int v, int T, long long maxPush) {
    if (v == T) {
      return maxPush;
    }
    long long res = 0;
    for (int &it = its[v]; it < ((int)(es[v]).size()); ++it) {
      int eid = es[v][it];
      Edge &e = edges[eid];
      if (e.c == e.f) {
        continue;
      }
      int u = e.t;
      if (dist[u] != dist[v] + 1) {
        continue;
      }
      long long push = dfs(u, T, min(maxPush, e.c - e.f));
      if (push) {
        res += push;
        maxPush -= push;
        e.f += push;
        edges[eid ^ 1].f -= push;
        if (maxPush == 0) {
          break;
        }
      }
    }
    return res;
  }
  long long dinic(int S, int T) {
    its.resize(n);
    dist.resize(n);
    long long res = 0;
    while (1) {
      for (int i = 0; i < n; ++i) {
        dist[i] = inff;
      }
      dist[S] = 0;
      st.clear();
      st.push_back(S);
      for (int l = 0; l < ((int)(st).size()); ++l) {
        int v = st[l];
        for (int eid : es[v]) {
          Edge &e = edges[eid];
          if (e.f == e.c) {
            continue;
          }
          int u = e.t;
          if (dist[u] <= dist[v] + 1) {
            continue;
          }
          dist[u] = dist[v] + 1;
          st.push_back(u);
        }
      }
      if (dist[T] == inff) {
        break;
      }
      for (int i = 0; i < n; ++i) {
        its[i] = 0;
      }
      while (1) {
        long long push = dfs(S, T, inff);
        if (!push) {
          break;
        }
        res += push;
      }
    }
    return res;
  }
};
};  // namespace Flow
const int maxn = (int)3e5 + 10;
int n, m;
vector<vector<int> > es, cs;
int cntc[maxn];
int read() {
  if (scanf("%d%d", &n, &m) < 2) {
    return 0;
  }
  for (int i = 0; i < m; ++i) {
    cntc[i] = 0;
  }
  es = cs = vector<vector<int> >(n);
  for (int i = 0; i < m; ++i) {
    int s, t, c;
    scanf("%d%d%d", &s, &t, &c);
    --s, --t, --c;
    es[s].push_back(t), es[t].push_back(s);
    cs[s].push_back(c), cs[t].push_back(c);
    cntc[c] += 1;
  }
  return 1;
}
Flow::Graph g;
vector<pair<int, int> > st;
int used[maxn];
vector<vector<int> > cycles;
void dfs(int v, int pr = -1) {
  used[v] = 1;
  for (int it = 0; it < ((int)(es[v]).size()); ++it) {
    int u = es[v][it];
    if (used[u]) {
      if (used[u] == 1 && u != pr) {
        vector<int> cycle;
        cycle.push_back(cs[v][it]);
        for (int i = ((int)(st).size()) - 1; i >= 0; --i) {
          cycle.push_back(st[i].second);
          if (st[i].first == u) {
            break;
          }
        }
        sort(cycle.begin(), cycle.end());
        cycle.resize(unique(cycle.begin(), cycle.end()) - cycle.begin());
        cycles.push_back(cycle);
      }
      continue;
    }
    st.push_back(make_pair(v, cs[v][it]));
    dfs(u, v);
    st.pop_back();
  }
  used[v] = 2;
}
void solve() {
  for (int i = 0; i < n; ++i) {
    used[i] = 0;
  }
  st.clear();
  cycles.clear();
  dfs(0);
  g = Flow::Graph(m + ((int)(cycles).size()) + 2);
  for (int i = 0; i < ((int)(cycles).size()); ++i) {
    for (int c : cycles[i]) {
      g.adde(2 + i, c + ((int)(cycles).size()) + 2, 1);
    }
    g.adde(0, 2 + i, 1);
  }
  assert(((int)(cycles).size()) + n - 1 == m);
  int nozero = 0;
  for (int i = 0; i < m; ++i) {
    nozero += (cntc[i] > 0);
    int c = cntc[i] - 1;
    if (c > 0) {
      g.adde(2 + i + ((int)(cycles).size()), 1, c);
    }
  }
  int got = g.dinic(0, 1);
  printf("%d\n", nozero - (((int)(cycles).size()) - got));
}
int main() {
  srand(rdtsc());
  precalc();
  while (1) {
    if (!read()) {
      break;
    }
    solve();
  }
  return 0;
}
