import java.util.*

fun main(args: Array<String>) {
    abc151d()
}

fun abc151d() {
    val (h, w) = readLine()!!.split(' ').map { it.toInt() }
    val isRoad = (1..h).map { readLine()!!.map { it == '.' }.toBooleanArray() }.toTypedArray()

    val direction = listOf(-1 to 0, 1 to 0, 0 to -1, 0 to 1)

    var answer = 0

    for (y in 0 until h) {
        for (x in 0 until w) {
            if (!isRoad[y][x]) continue

            val visited = Array(h) { BooleanArray(w) }
            val minCosts = Array(h) { IntArray(w) { 1000000 } }
            val queue = ArrayDeque(listOf(listOf(Coordinate(y, x, -1))))

            while (queue.isNotEmpty()) {
                val coordinates = queue.poll()
                for (c in coordinates) {
                    val currCost = c.beforeCost + 1
                    if (c.y in 0 until h && c.x in 0 until w && isRoad[c.y][c.x] && !visited[c.y][c.x]) {
                        visited[c.y][c.x] = true
                        minCosts[c.y][c.x] = Math.min(minCosts[c.y][c.x], currCost)
                        queue.add(
                            listOf(
                                Coordinate(c.y + 1, c.x, currCost),
                                Coordinate(c.y - 1, c.x, currCost),
                                Coordinate(c.y, c.x + 1, currCost),
                                Coordinate(c.y, c.x - 1, currCost)
                            )
                        )
                    }
                }
            }

            answer = Math.max(answer, minCosts.map { it.filterNot { it == 1000000 }.max() ?: 0 }.max() ?: 0)
        }
    }

    println(answer)
}

private data class Coordinate(val y: Int, val x: Int, val beforeCost: Int)
