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
//package com.company;

import java.io.*;
import java.util.*;

public class Main {
    public static class Task {

        public class Maxflow {
            class Edge {
                int t, rev;
                long cap, f;
                public Edge(int t, int rev, long cap) {
                    this.t = t;
                    this.rev = rev;
                    this.cap = cap;
                }
            }
            public Maxflow(int n) {
                graph = new List[n];
                for (int i = 0; i < n; i++) {
                    graph[i] = new ArrayList<>();
                }
            }
            List<Edge>[] graph;
            void addEdge(int s, int t, long cap) {
                graph[s].add(new Edge(t, graph[t].size(), cap));
                graph[t].add(new Edge(s, graph[s].size() - 1, 0));
//                System.err.println(s + " " + t + " " + cap);
            }

            boolean dinicBFS(int src, int dest, int[] dist) {
                Arrays.fill(dist, -1);
                dist[src] = 0;
                int[] Q = new int[graph.length];
                int sizeQ = 0;
                Q[sizeQ++] = src;
                for (int i = 0; i < sizeQ; i++) {
                    int u = Q[i];
                    for (Edge e: graph[u]) {
                        if (dist[e.t] < 0 && e.f < e.cap) {
                            dist[e.t] = dist[u] + 1;
                            Q[sizeQ++] = e.t;
                        }
                    }
                }
                return dist[dest] >= 0;
            }

            long dinicDFS(int[] ptr, int[] dist, int dest, int u, long f) {
                if (u == dest) return f;
                for (;ptr[u] < graph[u].size(); ++ptr[u]) {
                    Edge e =  graph[u].get(ptr[u]);
                    if (dist[e.t] == dist[u] + 1 && e.f < e.cap) {
                        long df = dinicDFS(ptr, dist, dest, e.t, Math.min(f, e.cap - e.f));
                        if (df > 0) {
                            e.f += df;
                            graph[e.t].get(e.rev).f -= df;
                            return df;
                        }

                    }
                }
                return 0;
            }

            long maxFLow(int src, int dest) {
                long flow = 0;
                int[] dist = new int[graph.length];
                while (dinicBFS(src, dest, dist)) {
                    int[] ptr = new int[graph.length];
                    while (true) {
                        long df = dinicDFS(ptr, dist, dest, src, Long.MAX_VALUE);
                        if (df == 0) break;
                        flow += df;
                    }
                }
                return flow;
            }
        }

        class ColorEdge {
            int minEnd, maxEnd, color;

            public ColorEdge(int minEnd, int maxEnd, int color) {
                this.minEnd = minEnd;
                this.maxEnd = maxEnd;
                this.color = color;
            }

            int getOtherEnd(int oneEnd) {
                return oneEnd == minEnd ? maxEnd: minEnd;
            }
        }


        void findCyclesInCactus(int u, int p, List<ColorEdge>[] graph, int[] state, List<List<Integer>> components, ColorEdge[] from) {
            state[u] = 1;
            for (ColorEdge e: graph[u]) if (e.getOtherEnd(u) != p) {
                int v = e.getOtherEnd(u);
                if (state[v] == 0) {
                    from[v] = e;
                    findCyclesInCactus(v, u, graph, state, components, from);
                } else if (state[v] == 1) {
                    List<Integer> cycle = new ArrayList<>();
                    cycle.add(e.color);
                    int t = u;
                    while (t != v) {
                        cycle.add(from[t].color);
                        int tt = from[t].getOtherEnd(t);
                        from[t] = null;
                        t = tt;
                    }
                    components.add(cycle);
                }
            }
            state[u] = 2;
        }

        public void solve(Scanner sc, PrintWriter pw) throws IOException {
            int n = sc.nextInt();
            int m = sc.nextInt();
            List<ColorEdge>[] graph = new List[n];
            int maxColor = 0;
            for (int i = 0; i < n; i++) {
                graph[i] = new ArrayList<>();
            }
            for (int i = 0; i < m; i++) {
                int a = sc.nextInt() - 1;
                int b = sc.nextInt() - 1;
                int c = sc.nextInt() - 1;
                ColorEdge e = new ColorEdge(Math.min(a, b), Math.max(a, b), c);
                graph[a].add(e);
                graph[b].add(e);
                maxColor = Math.max(maxColor, c + 1);
            }
            List<List<Integer>> components = new ArrayList<>();
            ColorEdge[] colorEdges = new ColorEdge[n];
            findCyclesInCactus(0, -1, graph, new int[n], components, colorEdges);
            for (ColorEdge ce: colorEdges) {
                if (ce != null) {
                    List<Integer> arr = new ArrayList<>();
                    arr.add(ce.color);
                    components.add(arr);
                }
            }
            Maxflow mf = new Maxflow(2 + components.size() + maxColor);
            for (int i = 0; i < components.size(); i++) {
                for (int color: components.get(i)) {
                    mf.addEdge(2 + i, 2 + components.size() + color, 1);
                }
                int cur = components.get(i).size() == 1 ? 1 : components.get(i).size() - 1;
                mf.addEdge(0, 2 + i, cur);
            }
            for (int i = 0; i < maxColor; i++) {
                mf.addEdge(2 + components.size() + i, 1, 1);
            }
            pw.println(mf.maxFLow(0, 1));
        }
    }

    static long TIME_START, TIME_END;

    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
//        Scanner sc = new Scanner(new FileInputStream("input"));
        PrintWriter pw = new PrintWriter(new BufferedOutputStream(System.out));
//        PrintWriter pw = new PrintWriter(new FileOutputStream("output"));

        Runtime runtime = Runtime.getRuntime();
        long usedMemoryBefore = runtime.totalMemory() - runtime.freeMemory();
        TIME_START = System.currentTimeMillis();
        Task t = new Task();
        t.solve(sc, pw);
        TIME_END = System.currentTimeMillis();
        long usedMemoryAfter = runtime.totalMemory() - runtime.freeMemory();
        pw.close();
        System.err.println("Memory increased: " + (usedMemoryAfter - usedMemoryBefore) / 1000000);
        System.err.println("Time used: " + (TIME_END - TIME_START) + ".");
    }

    static class Scanner {
        StringTokenizer st;
        BufferedReader br;

        public Scanner(InputStream s) {
            br = new BufferedReader(new InputStreamReader(s));
        }

        public Scanner(FileReader s) throws FileNotFoundException {
            br = new BufferedReader(s);
        }

        public String next() throws IOException {
            while (st == null || !st.hasMoreTokens())
                st = new StringTokenizer(br.readLine());
            return st.nextToken();
        }

        public int nextInt() throws IOException {
            return Integer.parseInt(next());
        }

        public long nextLong() throws IOException {
            return Long.parseLong(next());
        }

        public String nextLine() throws IOException {
            return br.readLine();
        }

        public double nextDouble() throws IOException {
            return Double.parseDouble(next());
        }

        public boolean ready() throws IOException {
            return br.ready();
        }
    }
}
