import util.control.Breaks._

object Main extends App {
  val Array(h, w) = io.StdIn.readLine().split(' ').map(_.toInt)
  val field = Array.fill(h)(io.StdIn.readLine().toCharArray)
  val starts = for (j <- 0 until h; i <- 0 until w; if field(j)(i) == '.') yield (i, j)
  def search(start: (Int, Int)): Int = {
    val heap = collection.mutable.PriorityQueue.empty[((Int, Int), Int)](Ordering.by(-_._2))
    val taken = Array.fill(h)(Array.fill(w)(Int.MaxValue))
    var times = 0
    heap.enqueue((start, 0))
    breakable {
      while (heap.nonEmpty) {
        val ((x, y), t) = heap.dequeue()
        if (field(y)(x) == '#') {times = t; break()}
        else {
          val nt = t + 1
          Seq((x,y-1),(x,y+1),(x-1,y),(x+1,y))
            .withFilter(p => p._1 >= 0 && p._1 < w && p._2 >= 0 && p._2 < h)
            .withFilter(p => nt < taken(p._2)(p._1))
            .foreach(p => heap.enqueue((p, nt)))
        }
      }
    }
    times
  }
  println(starts.map(search).max)
}