fun main(args: Array<String>) {
  val (H, W) = readInts()
  val S = (1..H).map { readString() }

  val INF = Int.MAX_VALUE / 2
  val N = H * W
  val dp = Array(N) { Array(N) { INF } }
  for (i in 0 until H) {
    for (j in 0 until W) {
      val c = S[i][j]
      if (c == '.') {
        dp[i * W + j][i * W + j] = 0
        val d = listOf(-1 to 0, 0 to 1, 1 to 0, 0 to -1)
        d.forEach {
          val ii = i + it.first
          val jj = j + it.second
          val cc = S.getOrNull(ii)?.getOrNull(jj)
          if (cc == '.') {
            dp[i * W + j][ii * W + jj] = 1
            dp[ii * W + jj][i * W + j] = 1
          }
        }
      }
    }
  }

//  for (i in 0 until N) {
//    for (j in 0 until N) {
//      val n = dp[i][j]
//      print(if (n == INF) '-' else n.toString())
//      print(" ")
//    }
//    println()
//  }

  for (k in 0 until N) {
    for (i in 0 until N) {
      for (j in 0 until N) {
        dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[k][j])
      }
    }
  }

  var result = 0
  for (i in 0 until N) {
    for (j in 0 until N) {
      val n = dp[i][j]
      if (n == INF) continue
      result = Math.max(result, n)
    }
  }
  println(result)
}

fun readString() = readLine()!!
fun readStrings() = readString().split(" ")
fun readInt() = readString().toInt()
fun readInts() = readStrings().map { it.toInt() }
fun readLongs() = readStrings().map { it.toLong() }
