import Data.List hiding (find)
import Data.Tree
import Data.Array as A
import Data.Array.Unboxed
import Data.Array.MArray
import Data.Array.ST
import Data.Graph
--import Data.Vector as V
import Control.Monad
import Control.Monad.ST
import Control.Monad.State
import Debug.Trace

type DP s = STUArray s Int Int

dp_i :: DP s -> Vertex -> [Vertex] -> Int -> ST s Int
dp_i dparr v0 [] n = return 0
dp_i dparr v0 (v:vs) n = do
   dpv0 <- readArray dparr v0
   dpv  <- readArray dparr v
   -- 閉路はないので以下のことができる
   writeArray dparr v (dpv0+1)
   n <- dp_i dparr v0 vs n
   return $ max (dpv0+1) n

solve :: [Edge] -> Int -> Int -> ST s Int
solve ls' n m = do
  let  graph = buildG (1,n) ls'
       ls = topSort graph
  dparr <- newArray (1,n) 0
  list <- forM ls $ \v0 -> dp_i dparr v0 (graph A.! v0) n
  let ans = maximum list
  return ans

main :: IO ()
main = do
  [n,m] <- map read.words <$> getLine
  ls <- replicateM m $ do
    (x:y:e) <- map read.words <$> getLine
    return (x,y)
  putStrLn $ show $ runST $ solve ls n m
