from collections import deque
r, c = map(int, input().split())
 
orig_maze = [[val for val in list(input())] for _ in range(r)]

maze = [[None for _ in range(c+2)] for _ in range(r+2)]
for r_index in range(r+2):
  for c_index in range(c+2):
    if r_index == 0 or r_index == r+1 or c_index == 0 or c_index == c+1:
      maze[r_index][c_index] = "#"
    else:
      maze[r_index][c_index] = orig_maze[r_index-1][c_index-1]
      
def wfs(queue, goal):
    finish_dist = None
    while len(queue) > 0:
        a = queue.popleft()
        y = a[0]
        x = a[1]
        count = a[2]
        if checked_maze[y][x]:
            continue
 
        if a[0] == goal[0] and a[1] == goal[1]:
            finish_dist = count
            break
 
        checked_maze[y][x] = True
        if not maze[y][x] == "#":
            count += 1
            queue.append((a[0]+1, a[1], count))
            queue.append((a[0]-1, a[1], count))
            queue.append((a[0], a[1]+1, count))
            queue.append((a[0], a[1]-1, count))

    return finish_dist 
 
 
if __name__ == "__main__":
    result = 0
    for s_y in range(1, r+1):
      for s_x in range(1, c+1):
        for g_y in range(1, r+1):
          for g_x in range(1, r+1):
            if maze[s_y][s_x] == "." and maze[g_y][g_x] == ".":
              if s_y == g_y and s_x == g_x:
                finish_dist = 0
              else:
                checked_maze = [[None for _ in range(c+2)] for _ in range(r+2)]
                que = deque()
                checked_maze[s_y][s_x]= 0
                que.append((s_y, s_x, 0))
                finish_dist = wfs(que, (g_y, g_x))
            result = max(result,finish_dist)
    print(result)