import java.util.*

fun main(args: Array<String>) {
    val INF = -100000007
    val (H, W) = readLine()!!.split(" ").map(String::toInt)
    val maze = Array(H) {
       readLine()!!.toCharArray()
    }
    fun bfs(sx: Int, sy: Int): Triple<Int, Int, Int> {
        var dmax = 0
        var dmax_x = sx
        var dmax_y = sy
        val dx = arrayOf(1,0,-1,0)
        val dy = arrayOf(0,1,0,-1)
        val que = ArrayDeque<Pair<Int,Int>>()
        que.addLast(Pair(sx, sy))
        val d = Array(H){ Array(W) {INF} }
        d[sy][sx] = 0
        while (que.size > 0) {
            val p = que.removeFirst()
            for (i in 0..3) {
                val nx = p.first + dx[i]
                val ny = p.second + dy[i]
                if ((nx in 0 until W) && (ny in 0 until H) && maze[ny][nx] == '.' && d[ny][nx] == INF) {
                    que.addLast(Pair(nx, ny))
                    d[ny][nx] = d[p.second][p.first] + 1
                    if (dmax <  d[ny][nx]) {
                        dmax = d[ny][nx]
                        dmax_x = nx
                        dmax_y = ny
                    }
                }
            }
        }
        return Triple(dmax_x, dmax_y, dmax)
    }
    var sx = -1
    var sy = -1
    loop@ for (h in 0 until H) {
        for (w in 0 until W) {
            if (maze[h][w] != '.') continue
            sx = w
            sy = h
            break@loop
        }
    }
    val cond = bfs(sx, sy)
    val ans = bfs(cond.first, cond.second)
    println(ans.third)
}