import java.lang.StringBuilder

fun main(arr:Array<String>) {
    val (h,w) = readLine()!!.split(" ").map { it.toInt() }
    val map = (1..h).map { readLine()!!.map { it } }
    val posList = mutableListOf<Pos>()
    (0 until h).forEach {
        val row = it
        posList.addAll((0 until w).map {a-> Pos(row, a, w, map) })
    }
    val saitan = (0 until posList.size).map { (0 until posList.size).map { 800 }.toMutableList() }
    for(i in posList.indices) {
        for(j in posList.indices) {
            for(k in posList.indices) {
                if(posList[j].isSame(posList[k])) {
                    saitan[j][k] = 0
                }
                if(posList[j].isNear(posList[k])) {
                    saitan[j][k] = 1
                }
                if(saitan[j][i] + saitan[i][k] < saitan[j][k]) {
                    saitan[j][k] = saitan[j][i] + saitan[i][k]
                }
            }
        }
    }
    var ans = 0
    for(row in saitan) {
        for(col in row) {
            if(col >= 800) {
                continue
            }
            if(col == 0) {
                continue
            }
            ans = Math.max(ans, col)
        }
    }
    println(ans)

}

class Pos(val row:Int, val col:Int, val maxCol:Int, val map:List<List<Char>>) {
    val index = row*maxCol+col
    fun isSame(target:Pos):Boolean {
        return this.row == target.row && this.col == target.col && map[row][col] == '.'
    }
    fun isNear(target: Pos):Boolean {
        if(this.isSame(target)) {
            return false
        }
        if(map[row][col] != '.' || map[target.row][target.col] != '.') {
            return false
        }
        if(this.row == target.row) {
            return Math.abs(this.col - target.col) == 1
        }
        if(this.col == target.col) {
            return Math.abs(this.row - target.row) == 1
        }
        return false
    }
}
