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<vector<int> > cykle;
vector<pair<int, int> > stos;
using namespace std;
struct krawedz;
const int MAX = 1e9;
struct krawedz {
  int a, b, przeplyw, max_przeplyw;
  krawedz(int a, int b, int max_przeplyw) {
    this->a = a;
    this->b = b;
    this->przeplyw = 0;
    this->max_przeplyw = max_przeplyw;
  }
  int dokad(int skad) { return a == skad ? b : a; }
  int war_przeplywu(int skad) {
    if (a == skad) return przeplyw;
    if (b == skad) return -przeplyw;
    return 0;
  }
  void zmien_przeplyw(int skad, int ile) {
    if (a == skad)
      przeplyw += ile;
    else
      przeplyw -= ile;
  }
  bool jest_w_sieci(int skad) {
    return (skad == a && przeplyw < max_przeplyw) ||
           (skad == b && przeplyw > 0);
  }
};
void dodaj_krawedz(vector<krawedz>& krawedzie,
                   vector<vector<int> >& siec_rezydualna, int skad, int dokad,
                   int waga, int num) {
  krawedzie.push_back(krawedz(skad, dokad, waga));
  siec_rezydualna[skad].push_back(num);
  siec_rezydualna[dokad].push_back(num);
}
vector<vector<int> > bfs_graf_warstwowy(vector<vector<int> >& graf,
                                        vector<krawedz>& krawedzie, int s) {
  vector<vector<int> > warstwowy(graf.size(), vector<int>());
  queue<int> q;
  q.push(s);
  vector<int> odleglosc(graf.size(), -1);
  odleglosc[s] = 0;
  while (!q.empty()) {
    int a = q.front();
    q.pop();
    for (int i = 0; i < graf[a].size(); ++i)
      if (krawedzie[graf[a][i]].jest_w_sieci(a)) {
        int koniec = krawedzie[graf[a][i]].dokad(a);
        if (odleglosc[koniec] < 0) {
          q.push(koniec);
          odleglosc[koniec] = odleglosc[a] + 1;
        }
        if (odleglosc[koniec] == odleglosc[a] + 1)
          warstwowy[a].push_back(graf[a][i]);
      }
  }
  return warstwowy;
}
bool dfs_sciezka(int v, vector<vector<int> >& warstwowy,
                 vector<krawedz>& krawedzie, vector<int>& nast_krawedz,
                 vector<int>& poprz_krawedz, int t) {
  for (int i = nast_krawedz[v]; i < warstwowy[v].size(); ++i) {
    int koniec = krawedzie[warstwowy[v][i]].dokad(v);
    if (poprz_krawedz[koniec] < 0 &&
        krawedzie[warstwowy[v][i]].jest_w_sieci(v)) {
      poprz_krawedz[koniec] = warstwowy[v][nast_krawedz[v]];
      if (dfs_sciezka(koniec, warstwowy, krawedzie, nast_krawedz, poprz_krawedz,
                      t))
        return true;
    }
    if ((!krawedzie[warstwowy[v][i]].jest_w_sieci(v) ||
         nast_krawedz[koniec] >= warstwowy[koniec].size()) &&
        i == nast_krawedz[v])
      nast_krawedz[v]++;
  }
  if (v == t)
    return true;
  else
    return false;
}
void dinic(vector<vector<int> >& graf, vector<krawedz>& krawedzie, int s,
           int t) {
  while (true) {
    vector<vector<int> > warstwowy = bfs_graf_warstwowy(graf, krawedzie, s);
    bool niezerowy_przeplyw = false;
    vector<int> nastepna_krawedz(graf.size(), 0);
    while (true) {
      vector<int> poprzednia_krawedz(graf.size(), -1);
      if (!dfs_sciezka(s, warstwowy, krawedzie, nastepna_krawedz,
                       poprzednia_krawedz, t))
        break;
      niezerowy_przeplyw = true;
      int x = t;
      int min_sciezka = MAX;
      while (poprzednia_krawedz[x] >= 0) {
        int k = poprzednia_krawedz[x];
        int skad = krawedzie[k].dokad(x);
        if (krawedzie[k].war_przeplywu(skad) < 0)
          min_sciezka = min(min_sciezka, -krawedzie[k].war_przeplywu(skad));
        else
          min_sciezka = min(min_sciezka, krawedzie[k].max_przeplyw -
                                             krawedzie[k].war_przeplywu(skad));
        x = skad;
      }
      x = t;
      while (poprzednia_krawedz[x] >= 0) {
        int k = poprzednia_krawedz[x];
        int skad = krawedzie[k].dokad(x);
        krawedzie[k].zmien_przeplyw(skad, min_sciezka);
        x = skad;
      }
    }
    if (!niezerowy_przeplyw) break;
  }
}
void dfs_cykle_kaktusa(int v, vector<vector<pair<int, int> > >& graf,
                       vector<bool>& odwiedzone,
                       vector<bool>& odwiedzone_krawedzie) {
  odwiedzone[v] = true;
  for (int i = 0; i < graf[v].size(); ++i)
    if (!odwiedzone[graf[v][i].first]) {
      stos.push_back(make_pair(v, graf[v][i].second));
      odwiedzone_krawedzie[graf[v][i].second] = true;
      dfs_cykle_kaktusa(graf[v][i].first, graf, odwiedzone,
                        odwiedzone_krawedzie);
      stos.pop_back();
    } else if (!odwiedzone_krawedzie[graf[v][i].second]) {
      odwiedzone_krawedzie[graf[v][i].second] = true;
      vector<int> cykl;
      cykl.push_back(graf[v][i].second);
      int j = stos.size() - 1;
      while (stos[j].first != graf[v][i].first) {
        cykl.push_back(stos[j].second);
        j--;
      }
      cykl.push_back(stos[j].second);
      cykle.push_back(cykl);
    }
}
int main() {
  int n, m, i, j, a, b;
  scanf("%d%d", &n, &m);
  vector<bool> odwiedzone(n + 1, false), odwiedzone_krawedzie(m + 1, false);
  vector<int> kolor(m + 1, 0);
  vector<vector<pair<int, int> > > graf(n + 1, vector<pair<int, int> >());
  for (i = 0; i < m; ++i) {
    scanf("%d%d%d", &a, &b, &kolor[i]);
    graf[a].push_back(make_pair(b, i));
    graf[b].push_back(make_pair(a, i));
  }
  for (i = 1; i <= n; ++i)
    if (!odwiedzone[i])
      dfs_cykle_kaktusa(i, graf, odwiedzone, odwiedzone_krawedzie);
  vector<bool> krawedzie_na_cyklu(m + 1, false);
  for (i = 0; i < cykle.size(); ++i)
    for (j = 0; j < cykle[i].size(); ++j)
      krawedzie_na_cyklu[cykle[i][j]] = true;
  vector<bool> kolor_poza_cyklami(m + 1, false);
  for (i = 0; i < m; ++i)
    if (!krawedzie_na_cyklu[i]) kolor_poza_cyklami[kolor[i]] = true;
  int liczba_kolorow_poza_cyklami = 0;
  for (i = 1; i <= m; ++i)
    if (kolor_poza_cyklami[i]) liczba_kolorow_poza_cyklami++;
  vector<vector<int> > dwudzielny(cykle.size() + m + 2, vector<int>());
  vector<krawedz> dwudzielny_krawedzie;
  int num = 0;
  for (i = 1; i <= cykle.size(); ++i) {
    dodaj_krawedz(dwudzielny_krawedzie, dwudzielny, 0, i,
                  cykle[i - 1].size() - 1, num);
    num++;
  }
  for (i = 0; i < cykle.size(); ++i)
    for (j = 0; j < cykle[i].size(); ++j)
      if (!kolor_poza_cyklami[kolor[cykle[i][j]]]) {
        dodaj_krawedz(dwudzielny_krawedzie, dwudzielny, i + 1,
                      cykle.size() + kolor[cykle[i][j]], 1, num);
        num++;
      }
  for (i = 1; i <= m; ++i)
    if (!kolor_poza_cyklami[i]) {
      dodaj_krawedz(dwudzielny_krawedzie, dwudzielny, i + cykle.size(),
                    dwudzielny.size() - 1, 1, num);
      num++;
    }
  dinic(dwudzielny, dwudzielny_krawedzie, 0, dwudzielny.size() - 1);
  int max_przeplyw = 0;
  for (i = 0; i < dwudzielny_krawedzie.size(); ++i)
    max_przeplyw += dwudzielny_krawedzie[i].war_przeplywu(0);
  printf("%d", liczba_kolorow_poza_cyklami + max_przeplyw);
  return 0;
}
