import Foundation

// MARK: READ INPUTS

func readInt() -> Int {
    Int(readLine()!)!
}

func readInts() -> [Int] {
    readLine()!.split(separator: " ").map { Int($0)! }
}

// MARK: COLLECTION

extension Collection {
    func tuple() -> (Element, Element) {
        var i = makeIterator()
        return (i.next()!, i.next()!)
    }
    func tuple() -> (Element, Element, Element) {
        var i = makeIterator()
        return (i.next()!, i.next()!, i.next()!)
    }
    func tuple() -> (Element, Element, Element, Element) {
        var i = makeIterator()
        return (i.next()!, i.next()!, i.next()!, i.next()!)
    }
    
    func safe(at index: Index) -> Element? {
        self.indices.contains(index) ? self[index] : nil
    }
}

// MARK: DP

struct DP<Argument: Hashable, Element> {
    var dictionary = [Argument: Element]()
    
    var expression: (Argument, (Argument) -> Element) -> Element
    
    init(expression: @escaping (_ argument: Argument, _ note: (Argument) -> Element) -> Element) {
        self.expression = expression
    }
    
    subscript(_ argument: Argument) -> Element {
        mutating _read {
            if let note = dictionary[argument] {
                yield note
            } else {
                let result = expression(argument) { self[$0] }
                dictionary[argument] = result
                yield result
            }
        }
    }
}

// MARK: SOME EXTENSIONS

extension Dictionary {
    init(_ initialize: (inout Self) -> ()) {
        var dictionary = Self()
        initialize(&dictionary)
        self = dictionary
    }
}

extension SignedNumeric where Self: Comparable {
    var abs: Self {
        return self < .zero ? -self : self
    }
}

// MARK: MOD

@propertyWrapper
struct Mod {
    
    let base: Int
    private var store: Int
    
    var value: Int {
        get { return store }
        set {
            store = newValue % base
            if store < 0 { store += base }
        }
    }
    
    static var defaultBaseNumber = 1_000_000_007
    
    init(_ value: Int, base: Int = defaultBaseNumber) {
        self.base = base
        self.store = value % base
        if store < 0 { self.store += base }
    }
    
    private init(unchecked value: Int, base: Int = defaultBaseNumber) {
        self.store = value
        self.base = base
    }
    
    init(wrappedValue: Int, base: Int = defaultBaseNumber) {
        self = .init(wrappedValue, base: base)
    }
    
    var wrappedValue: Int {
        get { return value }
        set { value = newValue }
    }
    
    var projectedValue: Int { base }
}

extension Mod: ExpressibleByIntegerLiteral {
    init(integerLiteral value: Int) {
        self = .init(value)
    }
}

extension Mod: AdditiveArithmetic {
    
    private static func assert(_ a: Mod, _ b: Mod) {
        Swift.assert(b.base == b.base, "Base should be same number .")
    }
    
    private static func operate(_ f: @escaping (Int, Int) -> Int) -> (Mod, Mod) -> Mod {
        return { lhs, rhs in
            assert(lhs, rhs)
            let num = f(lhs.value, rhs.value)
            return Mod(num, base: lhs.base)
        }
    }
    
    static func + (lhs: Mod, rhs: Mod) -> Mod { operate(+)(lhs, rhs) }
    static func - (lhs: Mod, rhs: Mod) -> Mod { operate(-)(lhs, rhs) }
    static func * (lhs: Mod, rhs: Mod) -> Mod { operate(*)(lhs, rhs) }
    static func *= (lhs: inout Mod, rhs: Mod) { lhs = lhs * rhs }
}

extension Mod: Numeric {
    init?<T>(exactly source: T) where T : BinaryInteger {
        guard let int = Int(exactly: source) else { return nil }
        self = Mod(int)
    }
    
    var magnitude: Int { value.abs }
}

extension Mod: SignedNumeric {}

extension Mod: CustomStringConvertible {
    var description: String {
        let digit = String(base).count
        let string = String(format: "%\(digit)d", value)
        return "Mod(\(string), base: \(base))"
    }
}

extension Mod: Equatable {
    static func == (lhs: Mod, rhs: Mod) -> Bool {
        assert(lhs, rhs)
        return lhs.value == rhs.value
    }
}

extension Mod: Hashable {
    func hash(into hasher: inout Hasher) {
        hasher.combine(base)
        hasher.combine(value)
    }
}

extension Mod: Comparable {
    static func < (lhs: Mod, rhs: Mod) -> Bool {
        assert(lhs, rhs)
        return lhs.value < rhs.value
    }
}

extension Mod: Strideable {
    typealias Stride = Int
    
    func distance(to other: Mod) -> Int {
        return (other - self).value
    }
    
    func advanced(by n: Int) -> Mod {
        return self + Mod(n, base: base)
    }
}

// MARK: PAIR and EITHER

struct Pair<T> {
    var x, y: T
    init(_ x: T, _ y: T) {
        self.x = x
        self.y = y
    }
}

extension Pair: Equatable where T: Equatable {}
extension Pair: Hashable where T: Hashable {}
extension Pair: Codable where T: Codable {}

enum Either<T, U> {
    case a(T), b(U)
}

extension Either: Equatable where T: Equatable, U: Equatable {}
extension Either: Hashable where T: Hashable, U: Hashable {}

// MARK: -- MAIN

func problem_c(_ an: [Mod]) -> Int {
    var res = Mod(0)
    var sum = an.reduce(0, +)
    for i in an {
        sum -= i
        res += i * sum
    }
    return res.value
}

func heavy_problem_c(_ an: [Mod]) -> Int {
    var res = Mod(0)
    for i in an.indices {
        let under = an[i]
        for j in 0..<i {
            let upper = an[j]
//            print(under.value, "*", upper.value, "=", (under * upper).value)
            res += under * upper
        }
    }
    return res.value
}


func problem_d(n: Int, data: [Pair<Int>]) -> Int {
    var result = [Set<Int>]()
    guard let first = data.first else { return 1 }
    
    result.append([first.x, first.y])
    
    for pair in data {
        for i in result.indices {
            if result[i].contains(pair.x) {
                result[i].insert(pair.y)
            }
            if result[i].contains(pair.y) {
                result[i].insert(pair.x)
            }
        }
    }
    
    return result.max(by: { $0.count < $1.count })?.count ?? 1
}



func main() {
    let (n, m) = readInts().tuple()
    let data: [Pair<Int>] = (0..<m).map { _ in
        let (a, b) = readInts().tuple()
        return Pair(a, b)
    }
    print(problem_d(n: n, data: data))
}

func test(_ n: Int = 10) {
    func printResult<T: Equatable>(_ answer: T, expected: T) {
        let success = "SUCCESS: \(answer)"
        let failed  = "FAILED:  \(answer) (expected \(expected))"
        print(answer == expected ? success : failed)
    }
    
    let ex1 = problem_d(n: n, data: [.init(1, 2), .init(3, 4), .init(5, 1)])
    printResult(ex1, expected: 3)
    
    for _ in 0..<n {
//        let ans = problem_c(an)
//        let hev = heavy_problem_c(an)
//        printResult(ans, expected: hev)
    }
}

main()
