import numpy as np
from collections import deque
# h, w = map(int,input().split())
# maze = [list(input()) for i in range(h)]
# seen = [[-1]*w for _ in range(h)]
# move = [[1,0],[-1,0],[0,1],[0,-1]]
# # start = [0,0]
# start = [2,2]
# g = [4,5]
# que = [start]
# seen[start[0]][start[1]] = 0
# que.append(start)
# while que:
#     y,x = que.pop(0)
#     if (y == g[0]) and (x == g[1]):
#         break
#     for i in range(len(move)):
#         ny,nx = y+move[i][0], x+move[i][1]
#         if (0 <= ny < h) and (0 <= nx < w):
#             if maze[ny][nx] == '.':
#                 if seen[ny][nx] == -1:
#                     seen[ny][nx] = seen[y][x]+1
#                     que.append([ny,nx])

# print(seen[])

def bfs(maze, visited, sy, sx):
    queue = deque([[sy, sx]])
    visited[sy][sx] = 0
    while queue:
        y, x = queue.popleft()
        # if [y, x] == [gy, gx]:
            # return visited[y][x]
        for j, k in ([1, 0], [-1, 0], [0, 1], [0, -1]):
            new_y, new_x = y+j, x+k
            if (0<=new_y<len(maze)) and (0<=new_x<len(maze[0])):
                if maze[new_y][new_x] == "." and \
                    visited[new_y][new_x] == -1:
                    
                    visited[new_y][new_x] = visited[y][x] + 1
                    queue.append([new_y, new_x])
    return visited

h, w = map(int, input().split())
maze = [input() for i in range(h)]
ans = 0
for i in range(h):
    for j in range(w):
        if (maze[i][j] == '.'):
            sy,sx = i,j
            visited = [[-1]*w for j in range(h)]
            vi = bfs(maze,visited,sy,sx)
            a = np.array(vi).flatten().max()
            ans = max(ans, a)
# sy,sx = 0,0
# visited = [[-1]*w for j in range(h)]
# r = bfs(maze, visited, sy, sx)
print(ans)


### FIXED CODE ###

import numpy as np
from collections import deque
# h, w = map(int,input().split())
# maze = [list(input()) for i in range(h)]
# seen = [[-1]*w for _ in range(h)]
# move = [[1,0],[-1,0],[0,1],[0,-1]]
# # start = [0,0]
# start = [2,2]
# g = [4,5]
# que = [start]
# seen[start[0]][start[1]] = 0
# que.append(start)
# while que:
#     y,x = que.pop(0)
#     if (y == g[0]) and (x == g[1]):
#         break
#     for i in range(len(move)):
#         ny,nx = y+move[i][0], x+move[i][1]
#         if (0 <= ny < h) and (0 <= nx < w):
#             if maze[ny][nx] == '.':
#                 if seen[ny][nx] == -1:
#                     seen[ny][nx] = seen[y][x]+1
#                     que.append([ny,nx])

# print(seen[])

def bfs(maze, visited, sy, sx):
    queue = deque([[sy, sx]])
    visited[sy][sx] = 0
    while queue:
        y, x = queue.popleft()
        # if [y, x] == [gy, gx]:
            # return visited[y][x]
        for j, k in ([1, 0], [-1, 0], [0, 1], [0, -1]):
            new_y, new_x = y+j, x+k
            if (0<=new_y<len(maze)) and (0<=new_x<len(maze[0])):
                if maze[new_y][new_x] == "." and \
                    visited[new_y][new_x] == -1:
                    
                    visited[new_y][new_x] = visited[y][x] + 1
                    queue.append([new_y, new_x])
    return visited

h, w = map(int, input().split())
maze = [input() for i in range(h)]
ans = 0
for i in range(h):
    for j in range(w):
        if (maze[i][j] == '.'):
            sy,sx = i,j
            visited = [[-1]*w for j in range(h)]
            vi = bfs(maze,visited,sy,sx)
            a = np.array(vi).flatten().max()
            ans = max(ans, a)
# sy,sx = 0,0
# visited = [[-1]*w for j in range(h)]
# r = bfs(maze, visited, sy, sx)
print(ans)