#include <bits/stdc++.h>
using namespace std;
const long long INF = 1 << 28;
const long long LINF = 1ll << 61;
const int maxn = 40111;
const int maxm = 60011;
struct MAX_FLOW {
  int head[maxn], to[maxm * 2], nxt[maxm * 2], cap[maxm * 2], tot;
  void init() {
    tot = 1;
    memset(head, 0, sizeof(head));
  }
  MAX_FLOW() { init(); }
  void add_edge(int x, int y, int c) {
    nxt[++tot] = head[x];
    head[x] = tot;
    to[tot] = y;
    cap[tot] = c;
    nxt[++tot] = head[y];
    head[y] = tot;
    to[tot] = x;
    cap[tot] = c;
  }
  int dis[maxn];
  int que[maxn], qsz;
  void bfs(int S) {
    memset(dis, -1, sizeof(dis));
    qsz = 0;
    dis[S] = 0;
    que[qsz++] = S;
    for (int i = 0; i < qsz; i++) {
      int x = que[i];
      for (int j = head[x]; j; j = nxt[j]) {
        if (cap[j] && dis[to[j]] == -1) {
          dis[to[j]] = dis[x] + 1;
          que[qsz++] = to[j];
        }
      }
    }
  }
  int it[maxn];
  int dfs(int x, int T, int f) {
    if (x == T) return f;
    int l = f;
    for (int &i = it[x]; i; i = nxt[i]) {
      if (dis[to[i]] == dis[x] + 1 && cap[i]) {
        int d = dfs(to[i], T, min(l, cap[i]));
        if (d > 0) {
          cap[i] -= d;
          cap[i ^ 1] += d;
          l -= d;
          if (l == 0) break;
        }
      }
    }
    return f - l;
  }
  int max_flow(int S, int T) {
    int ret = 0;
    while (true) {
      bfs(S);
      if (dis[T] == -1) return ret;
      for (int i = 0; i < maxn; i++) it[i] = head[i];
      int f;
      while ((f = dfs(S, T, 2e9)) > 0) ret += f;
    }
  }
} owo;
int n, m, S, T;
int head[10011], nxt[40011], to[40011], col[40011], tot = 1;
int dfn[10011], dfntot, p[10011], gtot;
bool onc[20011];
void cycle(int x, int y, int cur) {
  gtot++;
  int cnt = 1;
  owo.add_edge(gtot, m + col[cur], 1);
  onc[cur / 2] = 1;
  while (x != y) {
    owo.add_edge(gtot, m + col[p[x]], 1);
    onc[p[x] / 2] = 1;
    x = to[p[x]];
    cnt++;
  }
  owo.add_edge(S, gtot, cnt - 1);
}
void dfs(int x, int pre = -1) {
  dfn[x] = ++dfntot;
  for (int i = head[x]; i; i = nxt[i]) {
    if (!dfn[to[i]]) {
      p[to[i]] = i ^ 1;
      dfs(to[i], x);
    } else if (to[i] != pre) {
      if (dfn[to[i]] <= dfn[x]) {
        cycle(x, to[i], i);
      }
    }
  }
}
int main() {
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= m; i++) {
    int x, y, c;
    scanf("%d%d%d", &x, &y, &c);
    nxt[++tot] = head[x];
    head[x] = tot;
    to[tot] = y;
    col[tot] = c;
    nxt[++tot] = head[y];
    head[y] = tot;
    to[tot] = x;
    col[tot] = c;
  }
  S = 2 * m + 1, T = 2 * m + 2;
  dfs(1);
  for (int i = 1; i <= m; i++) {
    if (onc[i]) continue;
    owo.add_edge(S, m + col[i * 2], 1);
  }
  for (int i = 1; i <= m; i++) owo.add_edge(m + i, T, 1);
  cout << owo.max_flow(S, T) << endl;
  return 0;
}
