import std.stdio;
import std.string;
import std.conv;
import std.typecons;
import std.algorithm;
import std.functional;
import std.bigint;
import std.numeric;
import std.array;
import std.math;
import std.range;
import std.container;
import std.ascii;
import std.concurrency;

int N, M;
Vertex[] vs;
Edge[] es;
long INF = long.max/3;

void main() {
    readf("%d %d\n", &N, &M);
    vs = N.iota.map!(i => new Vertex(i)).array;
    es = M.rep!({
        int a, b; long c;
        readf("%d %d %d\n", &a, &b, &c);
        a--; b--;
        Edge e = new Edge(vs[a], vs[b], c);
        vs[a].edges ~= e;
        vs[b].edges ~= e;
        return e;
    });

    foreach(s; vs) {
        dijkstra(s);
        foreach(v; vs) {
            foreach(e; v.rev) {
                e.used = true;
            }
        }
    }

    es.map!(e => e.used).count!"!a".writeln;
}

void dijkstra(Vertex s) {
    foreach(v; vs) {
        v.visited = false;
        v.cost = INF;
        v.rev = [];
    }
    s.cost = 0;

    auto tree = redBlackTree!(
        (a, b) => a.cost==b.cost ? a.cost<b.cost : a.index<b.index
    )(s);

    while(!tree.empty) {
        Vertex v1 = tree.front;
        tree.removeFront;
        v1.visited = true;
        foreach(e; v1.edges) {
            Vertex v2 = (v1 !is e.fst) ? e.fst : e.snd;
            long po = v1.cost + e.weight;
            if (po < v2.cost && !v2.visited) {
                tree.removeKey(v2);
                v2.cost = po;
                v2.rev = [e];
                tree.insert(v2);
            } else if (po == v2.cost) {
                v2.rev ~= e;
            }
        }
    }
}

class Vertex {
    int index;
    Edge[] edges;
    bool visited;
    long cost;
    Edge[] rev;
    this(int index) {
        this.index = index;
    }
    override string toString() const {return "";}
}

class Edge {
    Vertex fst, snd;
    long weight;
    bool used;
    this(Vertex fst, Vertex snd, long weight) {
        this.fst = fst;
        this.snd = snd;
        this.weight = weight;
    }
}

// -------------------------------------------
void times(alias fun)(int n) {
    foreach(i; 0..n) fun();
}
auto rep(alias fun, T = typeof(fun()))(int n) {
    T[] res = new T[n];
    foreach(ref e; res) e = fun();
    return res;
}

// fold was added in D 2.071.0.
static if (__VERSION__ < 2071) {
    template fold(fun...) if (fun.length >= 1) {
        auto fold(R, S...)(R r, S seed) {
            static if (S.length < 2) {
                return reduce!fun(seed, r);
            } else {
                return reduce!fun(tuple(seed), r);
            }
        }
    }
}
