import Data.List hiding (find)
import Data.Array as A
import Data.Array.Unboxed
import Data.Array.MArray
import Data.Array.ST
import Data.Graph
import Control.Monad
import Control.Monad.ST

type DP s = STUArray s Int Int

--DFS
dp_i :: DP s -> Graph -> Vertex -> Int -> ST s Int
dp_i dparr graph v0 n | graph A.! v0 == [] = writeArray dparr v0 0 >> return 0
                      | otherwise = do
   let vs = graph A.! v0
   forM_ vs $ \v -> do
     dpv0 <- readArray dparr v0
     dpv  <- readArray dparr v
     dpv' <- if dpv == (-1) then dp_i dparr graph v n >> readArray dparr v else return dpv
     writeArray dparr v0 $ max dpv0 (dpv'+1)
   dpv0' <- readArray dparr v0
   return dpv0'

solve :: [Edge] -> Int -> Int -> ST s Int
solve ls n m = do
  let graph = buildG (1,n) ls
  dparr <- newArray (1,n) (-1)
  list  <- forM [1..n] $ \v0 -> dp_i dparr graph 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
