import java.util.*
import java.util.ArrayDeque



fun main(args: Array<String>) {
    val sc = java.util.Scanner(System.`in`)
    val h = sc.nextInt()
    val w = sc.nextInt()

    val m = sc.asSequence().take(h).map {
        it.toCharArray().map { if (it == '#') 99999 else 0 }.toMutableList()
    }.toMutableList()

    var wall = 1
    var maxmax = 0
    (0 until h).forEach { y ->
        (0 until w).forEach { x ->
            wall++
            // 始点は x, y
            if (m[y][x] != 99999) {

                val start = Point(x, y)
                val dq = ArrayDeque<Point>()
                dq.add(start)

                val moves = Array(h) { IntArray(w) }
                var max = 0

                //スタート地点を"#"で埋めて、探索済みにする
                m[start.y][start.x] = wall

                val D4 = arrayOf(Point(0, 1), Point(1, 0), Point(0, -1), Point(-1, 0))

                //幅優先探索
                while (dq.size > 0) {

                    //Queueの先頭の座標を取り出し＆削除して、その四方を探索する。
                    val p = dq.removeFirst()

                    for (i in 0..3) {

                        val x = p.x + D4[i].x
                        val y = p.y + D4[i].y

                        if (x >= 0 && y >= 0 && x < w && y < h && m[y][x] < wall) {

                            //"."であれば探索可能なので、Queueの末尾に追加する
                            dq.addLast(Point(x, y))

                            //探索が終わった座標を"#"で埋めて、次回以降探索しないようにする
                            m[y][x] = wall

                            //座標pからpの四方の座標への移動距離は、pまでの移動距離+1
                            val m = moves[p.y][p.x] + 1
                            moves[y][x] = m
                            max = Math.max(max, m)
                        }

                    }

                }
                maxmax = Math.max(max, maxmax)

            }
        }
    }
    print(maxmax)
}

data class Point(val x: Int, val y: Int)