unittest
{
	assert( [ "3 3", "1 2 1", "1 3 1", "2 3 3" ].parse.expand.solve == 1 );
	assert( [ "3 2", "1 2 1", "2 3 1" ].parse.expand.solve == 0 );
}



import std.algorithm;
import std.conv;
import std.range;
import std.stdio;
import std.typecons;

void main()
{
	stdin.byLineCopy.parse.expand.solve.writeln;
}

auto parse( Range )( Range input )
if( isInputRange!Range && is( ElementType!Range == string ) )
{
	auto nm = input.front.split.to!( long[] );
	auto abcs = new long[ 3 ][ nm[ 1 ] ];
	foreach( ref abc; abcs )
	{
		input.popFront;
		abc = input.front.split.to!( long[] );
		abc[ 0 .. 2 ] -= 1;
	}
	return tuple( nm[ 0 ], abcs );
}

auto solve( long n, long[ 3 ][] abcs )
{
	auto dss = warshallfloyd!( true )( n, abcs );
	auto ans = 0L;
	foreach( abc; abcs )
	{
		ans += ( dss[ abc[ 0 ] ][ abc[ 1 ] ] < abc[ 2 ] );
	}
	return ans;
}

// 正負の重み付きグラフの全二点間最短経路探索（ワーシャルフロイド法）
auto warshallfloyd( bool undirected = false )( long n, long[ 3 ][] es )
{
	auto dss = new long[][]( n, n );
	foreach( i, ref ds; dss )
	{
		ds[] = long.max;
		ds[ i ] = 0;
	}
	foreach( e; es )
	{
		dss[ e[ 0 ] ][ e[ 1 ] ] = e[ 2 ];
		static if( undirected ) dss[ e[ 1 ] ][ e[ 0 ] ] = e[ 2 ];
	}
	
	foreach( p; 0L .. dss.length )
	{
		foreach( f; 0L .. dss.length )
		{
			foreach( t; 0L .. dss.length )
			{
				if( dss[ f ][ p ] == long.max || dss[ p ][ t ] == long.max ) continue;
				dss[ f ][ t ] = min( dss[ f ][ t ], dss[ f ][ p ] + dss[ p ][ t ] );
			}
		}
	}
	return dss;
}
