import java.io._
import java.util.StringTokenizer
import scala.util.control.Breaks.{breakable,break}
import scala.collection.mutable.{Map, Stack, Queue, PriorityQueue, Set}

object Main extends App {
  val in = new InputReader(System.in)
  val pw = new PrintWriter(System.out)

  val H, W = in.next().toInt
  val S = new Array[String](H)
  for (i <- 0 until H)
    S(i) = in.next()


  //
  var ans = 0
  val q = new Queue[((Int, Int), Int)]
  val dp = Array.ofDim[Boolean](H, W)

  for (ny <- 0 until H)
    for (nx <- 0 until W) {
      for (y <- 0 until H; x <- 0 until W) {
        dp(y)(x) = false
      }

      q.enqueue(((nx, ny), 0))
      while (!q.isEmpty) {
        val ((x, y), d) = q.dequeue()
        if (!dp(y)(x) && S(y)(x) == '.') {
          dp(y)(x) = true
          ans = ans max d

          Seq((x-1, y), (x+1, y), (x, y-1), (x, y+1))
            .filter { case (x, y) => 0 <= x && x < W && 0 <= y && y < H }
            .foreach { p =>
              q.enqueue((p, d+1))
            }
        }
      }
    }

  println(ans)


}

object Sub {
  def print2DimArray[A](mat: Array[Array[A]]): Unit = {
    mat.foreach(lin => println(lin.deep))
  }
}

class InputReader(stream: InputStream) {
  private[this] val reader = new BufferedReader(new InputStreamReader(stream))
  private[this] var tokenizer: StringTokenizer = new StringTokenizer(reader.readLine())
  def next(): String = {
    while (!tokenizer.hasMoreTokens()) {
      tokenizer = new StringTokenizer(reader.readLine())
    }
    tokenizer.nextToken()
  }
}
