module m_deque
  ! 双端キュー. リングバッファ実装.
  ! 大文字 INTEGER を変更すると他のデータ型に使える.
  implicit none

  integer, parameter :: MINSIZE = 4
  type deque_int
    integer :: n = 0, st = 1, memsize = 0
    INTEGER, allocatable :: ary(:, :)
  contains
    procedure :: push_left, push_right, pop_left, pop_right, slice, dump
  end type deque_int

  contains

  subroutine resize_up(dq)
    ! 初めの要素追加または n == memsize で呼ばれる
    type(deque_int), intent(inout) :: dq
    INTEGER, allocatable :: tmp(:, :)
    if (dq%memsize == 0) then
      dq%memsize = MINSIZE
      allocate (dq%ary(3, dq%memsize))
      dq%n = 0
      dq%st = max(1, dq%memsize / 8)
    else
      if (dq%n /= dq%memsize) stop 2
      allocate (tmp(3, dq%n))
      tmp(:, :) = slice(dq, 1, dq%n)
      dq%memsize = dq%memsize * 2
      deallocate (dq%ary)
      allocate (dq%ary(3, dq%memsize))
      dq%st = max(1, dq%memsize / 8)
      dq%ary(:, dq%st:dq%st + dq%n - 1) = tmp(:, :)
      deallocate (tmp)
    end if
  end subroutine resize_up

  subroutine may_resize_down(dq)
    ! 必要なら小さい配列に移し替える
    type(deque_int), intent(inout) :: dq
    INTEGER, allocatable :: tmp(:, :)
    if (dq%memsize <= MINSIZE) return
    if (mod(dq%memsize, 2) /= 0) stop 1
    if (dq%n * 4 > dq%memsize) return

    allocate (tmp(3, dq%n))
    tmp(:, :) = slice(dq, 1, dq%n)
    dq%memsize = dq%memsize / 2
    deallocate (dq%ary)
    allocate (dq%ary(3, dq%memsize))
    dq%st = max(1, dq%memsize / 8)
    dq%ary(:, dq%st:dq%st + dq%n - 1) = tmp(:, :)
    deallocate (tmp)
  end subroutine may_resize_down

  subroutine push_left(dq, x)
    class(deque_int), intent(inout) :: dq
    INTEGER, intent(in) :: x(:)

    if (dq%n == dq%memsize) call resize_up(dq)
    dq%n = dq%n + 1
    dq%st = imod(dq%st - 1, dq%memsize)
    dq%ary(:, dq%st) = x(:)
  end subroutine push_left

  subroutine push_right(dq, x)
    class(deque_int), intent(inout) :: dq
    INTEGER, intent(in) :: x(:)
    integer :: idx

    if (dq%n == dq%memsize) call resize_up(dq)
    dq%n = dq%n + 1
    idx = dq%st + dq%n - 1
    idx = imod(idx, dq%memsize)
    dq%ary(:, idx) = x(:)
  end subroutine push_right

  function pop_left(dq)
    class(deque_int), intent(inout) :: dq
    INTEGER :: pop_left(3)
    if (dq%n == 0) stop 1
    pop_left(:) = dq%ary(:, dq%st)
    dq%n = dq%n - 1
    dq%st = imod(dq%st + 1, dq%memsize)
    call may_resize_down(dq)
  end function pop_left

  function pop_right(dq)
    class(deque_int), intent(inout) :: dq
    INTEGER :: pop_right(3)
    if (dq%n == 0) stop 1
    pop_right(:) = dq%ary(:, imod(dq%st + dq%n - 1, dq%memsize))
    dq%n = dq%n - 1
    call may_resize_down(dq)
  end function pop_right

  function slice(dq, istart, iend)
    ! 実データの [istart:iend] の範囲を切り出す
    class(deque_int), intent(in) :: dq
    INTEGER, allocatable :: slice(:, :)
    integer, intent(in) :: istart, iend  ! 実データ内のインデックス
    integer :: dstart, dend
    if (istart < 1) stop 1
    if (iend < istart) stop 1
    if (iend > dq%n) stop 1

    dstart = imod(istart + dq%st - 1, dq%memsize)
    dend = imod(dstart + (iend - istart), dq%memsize)

    allocate (slice(3, iend - istart + 1))
    slice(:, :) = 0
    if (dend < dstart) then
      slice(:, 1:dq%memsize - dstart + 1) = dq%ary(:, dstart:dq%memsize)
      slice(:, dq%memsize - dstart + 2:iend - istart + 1) = dq%ary(:, 1:dend)
    else
      slice(:, :) = dq%ary(:, dstart:dend)
    end if
  end function slice

  subroutine dump(dq)
    class(deque_int), intent(in) :: dq
    print *, "Data count:               ", dq%n
    print *, "Physical starting index:  ", dq%st
    print *, "Physical memory allocated:", dq%memsize
    print *, slice(dq, 1, dq%n)
  end subroutine dump

  pure integer function imod(idx, ms)
    ! メモリサイズ ms でインデックスを丸める
    ! [1 - ms <= idx <= ms + ms] を仮定
    integer, intent(in) :: idx, ms
    imod = idx
    if (imod > ms) then
      imod = imod - ms
    else if (imod < 1) then
      imod = imod + ms
    end if
  end function imod
end module m_deque

program main
  use m_deque, only: deque_int
  implicit none
  integer :: h, w, i, j, res, di
  character(100) :: s(100)
  read *, h, w
  do i = 1, h
    read *, s(i)
  end do
  res = 0
  do i = 1, h
    do j = 1, w
      di = maxdistfrom(s, i, j)
      res = max(res, di)
    end do
  end do
  print "(i0)", res

  contains

  integer function maxdistfrom(s, i, j)
    integer, intent(in) :: i, j
    character(100), intent(in) :: s(100)
    logical :: queued(100, 100)
    type(deque_int) :: dq
    integer :: triple(3), k, l, d, dx, dy, k2, l2, p, xs(4), ys(4)

    if (s(i)(j:j) == "#") then
      maxdistfrom = 0
      return
    end if

    queued(:, :) = .false.
    triple = (/i, j, 0/)
    call dq%push_right(triple)
    queued(i, j) = .true.
    maxdistfrom = 0
    do while (dq%n > 0)
      triple = dq%pop_left()
      k = triple(1)
      l = triple(2)
      d = triple(3)
      res = max(res, d)
      ys = (/-1, 1, 0, 0/)
      xs = (/0, 0, -1, 1/)
      do p = 1, 4
        dy = ys(p)
        dx = xs(p)
        k2 = k + dy
        l2 = l + dx
        if (k2 < 1) cycle
        if (k2 > h) cycle
        if (l2 < 1) cycle
        if (l2 > w) cycle
        if (s(k2)(l2:l2) == "#") cycle
        if (queued(k2, l2)) cycle
        triple = (/k2, l2, d + 1/)
        call dq%push_right(triple)
        queued(k2, l2) = .true.
      end do
    end do
  end function maxdistfrom
end program main
