import algorithm, complex, macros, math, sequtils, sets, strutils, tables
# import future

macro unpack*(rhs: seq, cnt: static[int]): auto =
  let v = genSym(); result = quote do:(let `v` = `rhs`;())
  if NimMinor <= 17:
    for i in 0..<cnt: result[0][1].add(quote do:`v`[`i`])
  else:
    for i in 0..<cnt: result[1].add(quote do:`v`[`i`])

template input*(T: typedesc, cnt: Natural = 1): untyped =
  let line = stdin.readLine.split(" ")
  when T is int:         line.map(parseInt).unpack(cnt)
  elif T is float:       line.map(parseFloat).unpack(cnt)
  elif T is string:      line.unpack(cnt)
  elif T is char:        line.mapIt(it[0]).unpack(cnt)
  elif T is seq[int]:    line.map(parseint)
  elif T is seq[float]:  line.map(parseFloat)
  elif T is seq[string]: line
  elif T is seq[char]:   line.mapIt(it[0])

proc `|=`*(n: var int, m: int) = n = n or m
proc `&=`*(n: var int, m: int) = n = n and m
proc `%=`*(n: var int, m: int) = n = n mod m
proc `^=`*(n: var int, m: int) = n = n xor m
proc `//=`*(n: var int, m: int) = n = n div m
proc `<<=`*(n: var int, m: int) = n = n shl m
proc `>>=`*(n: var int, m: int) = n = n shr m
proc `<?=`*(n: var SomeNumber, m: SomeNumber) = n = min(n, m)
proc `>?=`*(n: var SomeNumber, m: SomeNumber) = n = max(n, m)
proc newSeq2*[T](n1, n2: Natural): seq[seq[T]] = newSeqWith(n1, newSeq[T](n2))
proc newSeq3*[T](n1, n2, n3: Natural): seq[seq[seq[T]]] = newSeqWith(n1, newSeqWith(n2, newSeq[T](n3)))

# -------------------------------------------------- #

type
  Deque[T] = object
    data: seq[T]
    mask, head, tail, count: int

proc initDeque[T](initialSize: int = 4): Deque[T] =
  result.data = newSeq[T](initialSize.nextPowerOfTwo)
  result.mask = initialSize.nextPowerOfTwo - 1
  result.head = 0
  result.tail = 0
  result.count = 0
  
proc len[T](deq: Deque[T]): int =
  result = deq.count

template emptyCheck(deq) =
  when compileOption("boundChecks"):
    if unlikely(deq.count < 1):
      raise newException(IndexError, "Empty deque.")

iterator pairs[T](deq: Deque[T]): tuple[key: int, val: T] =
  var i = deq.head
  for c in 0 ..< deq.count:
    yield (c, deq.data[i])
    i = (i + 1) and deq.mask

proc expandIfNeeded[T](deq: var Deque[T]) =
  var cap = deq.mask + 1
  if unlikely(deq.count >= cap):
    var n = newSeq[T](cap * 2)
    for i, x in pairs(deq):
      shallowCopy(n[i], x)
    shallowCopy(deq.data, n)
    deq.mask = cap * 2 - 1
    deq.head = 0
    deq.tail = deq.count

proc addFirst[T](deq: var Deque[T], item: T) =
  expandIfNeeded(deq)
  inc deq.count
  deq.head = (deq.head - 1) and deq.mask
  deq.data[deq.head] = item

proc addLast[T](deq: var Deque[T], item: T) =
  expandIfNeeded(deq)
  inc deq.count
  deq.data[deq.tail] = item
  deq.tail = (deq.tail + 1) and deq.mask

proc peekFirst[T](deq: Deque[T]): T =
  emptyCheck(deq)
  result = deq.data[deq.head]

proc peekLast[T](deq: Deque[T]): T =
  emptyCheck(deq)
  result = deq.data[(deq.tail - 1) and deq.mask]

proc popFirst[T](deq: var Deque[T]): T {.discardable.} =
  emptyCheck(deq)
  dec deq.count
  result = deq.data[deq.head]
  deq.head = (deq.head + 1) and deq.mask

proc popLast[T](deq: var Deque[T]): T {.discardable.} =
  emptyCheck(deq)
  dec deq.count
  deq.tail = (deq.tail - 1) and deq.mask
  result = deq.data[deq.tail]

proc clear[T](deq: var Deque[T]) =
  deq.count = 0
  deq.tail = deq.head

# -------------------------------------------------- #

type C = tuple[x: int, y: int]

var (H, W) = input(int, 2)
var S = newseq[string](H + 2)
S[0] = "#".repeat(W + 2)
S[H + 1] = "#".repeat(W + 2)
for i in 1 .. H:
  S[i] = "#" & input(string) & "#"

var dx = @[0, 1, 0, -1]
var dy = @[1, 0, -1, 0]

proc bfs(Start: C, G: C): int =
  var que = initDeque[C]()
  var d = inittable[C, int]()
  que.addFirst(Start)
  d[Start] = 0
  while que.len() > 0:
    var now = que.popLast()
    var nowdist = d[now]
    for i in 0 .. 3:
      var nx = now.x + dx[i]
      var ny = now.y + dy[i]
      if d.contains((nx, ny)):
        continue
      else:
        if S[nx][ny] == '#':
          continue
        d[(nx, ny)] = nowdist + 1
        que.addFirst((nx, ny))
  return d[G]

var res = 0
for i in 1 .. H:
  for j in 1 .. W:
    for i2 in 1 .. H:
      for j2 in 1 .. W:
        if S[i][j] == '#' or S[i2][j2] == '#':
          continue
        else:
          res >?= bfs((i, j), (i2, j2))
echo res