import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Data.Text.Read as T
import Data.IntMap.Strict (IntMap)
import qualified Data.IntMap.Strict as IMS
import Data.Bool (bool)

main :: IO ()
main = do
  [n, m] <- map unsafeTextToInt . T.words <$> T.getLine :: IO [Int]
  abs <- sequence . replicate m $ unsafeListToPair . map (pred . unsafeTextToInt) . T.words <$> T.getLine :: IO [(Int, Int)]
  let
    (u, v) = foldl step (IMS.empty, IMS.empty) abs :: (IntMap Int, IntMap Int)
      where
        step uv (i, j) = fst $ unite i j uv
  print . maximum . map (\i -> IMS.findWithDefault 1 (snd $ root i u) v) $ [0..(n - 1)]

type UF = IntMap Int

parent :: Int -> UF -> Maybe Int
parent = IMS.lookup

root :: Int -> UF -> (UF, Int)
root i u = maybe (u, i) (\j -> let (u', j') = root j u in (bool (IMS.insert i j' u') u (j' == j), j')) (parent i u)

unite :: Int -> Int -> (UF, IntMap Int) -> ((UF, IntMap Int), ())
unite i j (u, v) | i' == j'  = ((u'', v), ())
                 | otherwise = ((IMS.insert j' i' u'', IMS.alter (Just . ((IMS.findWithDefault 1 j' v) +) . maybe 1 id) i' v), ())
  where
    (u', i') = root i u
    (u'', j') = root j u'

isSame :: Int -> Int -> UF -> (UF, Bool)
isSame i j u = (u'', i' == j')
  where
    (u', i') = root i u
    (u'', j') = root j u'

unsafeListToPair :: [Int] -> (Int, Int)
unsafeListToPair [x, y] = (x, y)
{-# INLINE unsafeListToPair #-}

unsafeTextToInt :: T.Text -> Int
unsafeTextToInt s = case T.signed T.decimal s of
  Right (n, _) -> n
{-# INLINE unsafeTextToInt #-}
