import java.util.*

data class Point(val x: Int, val y: Int)

fun main(args: Array<String>) {
    val (H, W) = readLine()!!.split(" ").map { it.toInt() }
    val s = (1..H).map { readLine()!!.map { it == '.' } }
    val sy = s.indexOfFirst { it.contains(true) }
    val sx = s[sy].indexOfFirst { it }

    val dist = Array(H) { i -> IntArray(W) { j -> if (s[i][j]) 1000 else -1 } }
    dist[sy][sx] = 0

    val q = ArrayDeque<Point>()
    q.offer(Point(sx, sy))
    while (q.isNotEmpty()) {
        val p = q.poll()
        if (p.y != 0 && s[p.y - 1][p.x] && dist[p.y - 1][p.x] > dist[p.y][p.x] + 1) {
            dist[p.y - 1][p.x] = dist[p.y][p.x] + 1
            q.offer(Point(p.x, p.y - 1))
        }
        if (p.y != H - 1 && s[p.y + 1][p.x] && dist[p.y + 1][p.x] > dist[p.y][p.x] + 1) {
            dist[p.y + 1][p.x] = dist[p.y][p.x] + 1
            q.offer(Point(p.x, p.y + 1))
        }
        if (p.x != 0 && s[p.y][p.x - 1] && dist[p.y][p.x - 1] > dist[p.y][p.x] + 1) {
            dist[p.y][p.x - 1] = dist[p.y][p.x] + 1
            q.offer(Point(p.x - 1, p.y))
        }
        if (p.x != W - 1 && s[p.y][p.x + 1] && dist[p.y][p.x + 1] > dist[p.y][p.x] + 1) {
            dist[p.y][p.x + 1] = dist[p.y][p.x] + 1
            q.offer(Point(p.x + 1, p.y))
        }
    }

    val max = dist.map { it.max()!! }.max()!!
    val sy2 = dist.indexOfFirst { it.contains(max) }
    val sx2 = dist[sy2].indexOfFirst { it == max }

    val dist2 = Array(H) { i -> IntArray(W) { j -> if (s[i][j]) 1000 else -1 } }
    dist2[sy2][sx2] = 0

    q.offer(Point(sx2, sy2))
    while (q.isNotEmpty()) {
        val p = q.poll()
        if (p.y != 0 && s[p.y - 1][p.x] && dist2[p.y - 1][p.x] > dist2[p.y][p.x] + 1) {
            dist2[p.y - 1][p.x] = dist2[p.y][p.x] + 1
            q.offer(Point(p.x, p.y - 1))
        }
        if (p.y != H - 1 && s[p.y + 1][p.x] && dist2[p.y + 1][p.x] > dist2[p.y][p.x] + 1) {
            dist2[p.y + 1][p.x] = dist2[p.y][p.x] + 1
            q.offer(Point(p.x, p.y + 1))
        }
        if (p.x != 0 && s[p.y][p.x - 1] && dist2[p.y][p.x - 1] > dist2[p.y][p.x] + 1) {
            dist2[p.y][p.x - 1] = dist2[p.y][p.x] + 1
            q.offer(Point(p.x - 1, p.y))
        }
        if (p.x != W - 1 && s[p.y][p.x + 1] && dist2[p.y][p.x + 1] > dist2[p.y][p.x] + 1) {
            dist2[p.y][p.x + 1] = dist2[p.y][p.x] + 1
            q.offer(Point(p.x + 1, p.y))
        }
    }

    val ans = dist2.map { it.max()!! }.max()!!
    println(ans)
}


