### BUGGY CODE ###

import copy

H, W = map(int, input().split())

maze = [[False for i in range(W)] for j in range(H)]

for h in range(H):
    ret = input()
    for i, x in enumerate(ret):
        if x == "#":
            pass
        else: # == "."
            maze[h][i] = True

class MazePath():
    def __init__(self, H, W, maze):
        self.H = H
        self.W = W
        self.maze = maze
        self.path_list = []
    
    def start_find(self, y, x):
        start_pos = [[y, x]]
        self.path_list.append(start_pos)
        self.find_next_path(y, x, start_pos)

    def can_move(self, y, x, visited_pos):
        if y < 0 or x < 0:
            return False
        if y >= H or x >= W:
            return False
        for yy, xx in visited_pos:
            if y == yy and x == xx:
                return False
        return self.maze[y][x]

    def find_next_path(self, y, x, visited_pos):
        next_pathes = []
        for dy, dx in [[1, 0], [-1, 0], [0, 1], [0, -1]]:
            next_y = y + dy
            next_x = x + dx
            if self.can_move(next_y, next_x, visited_pos):
                new_path = copy.copy(visited_pos)
                new_path.append([next_y, next_x])
                next_pathes.append(new_path)
        if len(next_pathes) == 0:
            return
        self.path_list.extend(next_pathes)
        for new_visited_pos in next_pathes:
            new_y, new_x = new_visited_pos[-1]
            self.find_next_path(new_y, new_x, new_visited_pos)

    def min_len(self, y, x):
        min_len = self.H * self.W
        for path in self.path_list:
            for l, (yy, xx) in enumerate(path):
                if y == yy and x == xx:
                    if l < min_len:
                        min_len = l
        if min_len == self.H * self.W:
            return -1
        return min_len

max_len = 0
for j in range(H):
    for i in range(W):
        if maze[j][i] == False:
            continue
        start_maze = MazePath(H, W, maze)
        start_maze.start_find(j, i)
        # for path in start_maze.path_list:
        #     print(len(path), path)
        for yy in range(H):
            for xx in range(W):
                # print(start_maze.min_len(yy, xx))
                cur_min_len = start_maze.min_len(yy, xx)
                if cur_min_len > max_len:
                    max_len = cur_min_len
print(max_len)


### FIXED CODE ###

H, W = map(int, input().split())

maze = [["."for i in range(W)] for j in range(H)]

for h in range(H):
    ret = input()
    for i, x in enumerate(ret):
        if x == "#":
            maze[h][i] = "#"
        # else: # == "."
        #     maze[h][i] = True

# print(maze)

def bfs(maze, y, x):
    q = [[y, x]]
    res = 0
    dist = [[-1] * W for j in range(H)]
    dist[y][x] = 0
    while len(q) > 0:
        yy, xx = q[0]
        res = max(res, dist[yy][xx])
        q.pop(0)
        for dy, dx in [[1,0], [0,1], [-1,0], [0,-1]]:
            ny = yy + dy
            nx = xx + dx
            if nx < 0 or ny < 0 or nx >= W or ny >= H:
                continue
            if maze[ny][nx] == '#':
                continue
            if dist[ny][nx] == -1:
                dist[ny][nx] = dist[yy][xx] + 1
                q.append([ny, nx])
    return res

res_max = 0
for j in range(H):
    for i in range(W):
        if maze[j][i] == '#':
            continue
        res_max = max(res_max, bfs(maze, j, i))
print(res_max)