import java.util.*

fun main(args: Array<String>) {
    val (h, w) = readIntegerList()
    val matrix = Array(h) { readLine()!! }

    var max = 0
    for (i in 0 until (h * w)) {
        for (j in i until (h * w)) {
            max = Math.max(max, calc(i % w, i / w, j % w, j / w, matrix))
        }
    }

    println(max)
}

fun calc(x1: Int, y1: Int, x2: Int, y2: Int, matrix: Array<String>): Int {
    if (matrix[y1][x1] == '#' || matrix[y2][x2] == '#') {
        return 0
    }

    val map = Array(matrix.size) { Array(matrix[0].length) { -1 } }
    val queue = ArrayDeque<Pair<Int, Int>>().apply { addLast(Pair(x1, y1)) }
    map[y1][x1] = 0
    while (queue.isNotEmpty()) {
        val point = queue.removeFirst()
        val cost = map[point.second][point.first]

        if (point.first == x2 && point.second == y2) {
            return cost
        }

        for (i in -1..1 step 2) {
            val x = point.first + i
            val y = point.second

            if (y in matrix.indices && x in matrix[y].indices) {
                if (map[y][x] == -1 && matrix[y][x] == '.') {
                    map[y][x] = cost + 1
                    queue.addLast(Pair(x, y))
                }
            }
        }

        for (i in -1..1 step 2) {
            val x = point.first
            val y = point.second + i

            if (y in matrix.indices && x in matrix[y].indices) {
                if (map[y][x] == -1 && matrix[y][x] == '.') {
                    map[y][x] = cost + 1
                    queue.addLast(Pair(x, y))
                }
            }
        }
    }

    return 0
}

fun readInteger() = readLine()!!.toInt()
fun readLong() = readLine()!!.toLong()
fun readStringList() = readLine()!!.split(" ")
fun readIntegerList() = readStringList().map(String::toInt)
fun readLongList() = readStringList().map(String::toLong)
