import java.util.*
fun main () {
    val (h, w) = readLine()!!.split(" ").map { it.toInt() }
    val maze = MutableList(h) {
        readLine()!!.toString().toCharArray()
    }
    val dx = listOf(1, 0, -1, 0)
    val dy = listOf(0, 1, 0, -1)
    var res_max = 0
    fun bfs(sx: Int, sy: Int) {
        if (maze[sy][sx] == '#') return
        var d: MutableList<MutableList<Int>> = mutableListOf()
        var queue = ArrayDeque<Pair<Int, Int>>()
        for (i in 0 until h) {
            d.add(mutableListOf())
            for (j in 0 until w) {
                d[i].add(-1)
            }
        }
        queue.add(Pair(sy, sx))
        d[sy][sx] = 0
        //println("$sx, $sy, $gx, $gy")
        while (queue.size > 0) {
            var p = queue.removeLast()
            //println(p)
            //if(p.first == gy && p.second == gx) break
            for (i in 0 until 4) {
                val nx = p.second + dx[i]
                val ny = p.first + dy[i]
                if (nx in 0 until w &&  ny in 0 until h && maze[ny][nx] == '.' && d[ny][nx] == -1) {
                    queue.push(Pair(ny, nx))
                    d[ny][nx] = d[p.first][p.second] + 1
                    if(res_max < d[ny][nx]) res_max = d[ny][nx]
                    //println(d[ny][nx].toString()+ " " + ny.toString() + "," + nx.toString())
                }
            }
        }
    }
    for(i in 0 until w){
        for(j in 0 until h){
            val res = bfs(i, j)
        }
    }
    println(res_max)
}

