### BUGGY CODE ###

import sys
import itertools
# import numpy as np
import time
import math
 
sys.setrecursionlimit(10 ** 7)
 
from collections import defaultdict
 
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
 
 
from functools import reduce
# from math import *
from fractions import *
H, W = map(int, readline().split())
S = [0 for i in range(H)]
for i in range(H):
    S[i] = readline().decode().strip()

# adj = [[] for _ in range(H * W)]
# for i in range(H):
#     for j in range(W):
#         v = i * W + j
#         if S[i][j] == '.':
#             for dx in range(-1, 2):
#                 for dy in range(-1, 2):
#                     if dx * dy != 0 or dx == dy:
#                         continue
#                     if i + dy < 0 or i + dy >= H or j + dx < 0 or j + dx >= W:
#                         continue
#                     if S[i + dy][j + dx] == '#':
#                         continue
#                     u = (i + dy) * W + j + dx
#                     adj[v].append(u)
# print(adj)



def bfs(start, goal, H, W):
    visited = [False for _ in range(H * W)]
    import queue
    q = queue.Queue()
    q.put((start[0], start[1], 0))
    while not q.empty():
        (i, j, dist) = q.get()
        if (i, j) == goal:
            return dist
        for dy in range(-1, 2):
            for dx in range(-1, 2):
                if dx * dy != 0 or dx == dy:
                    continue
                if i + dy < 0 or i + dy >= H or j + dx < 0 or j + dx >= W:
                    continue
                if S[i + dy][j + dx] == '#':
                    continue
                if visited[(i + dy) * W + j + dx]:
                    continue
                q.put((i + dy, j + dx, dist + 1))
    return -1

ans = 0
for i in range(H * W):
    start = (i // W, i % W)
    if S[start[0]][start[1]] == '#':
        continue
    for j in range(H * W):
        goal = (j // W, j % W)
        if S[goal[0]][goal[1]] == '#':
            continue
        if start == goal:
            continue
        ans = max(ans, bfs(start, goal, H, W))
print(ans)


### FIXED CODE ###

import sys
import itertools
# import numpy as np
import time
import math
 
sys.setrecursionlimit(10 ** 7)
 
from collections import defaultdict
 
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
 
 
from functools import reduce
# from math import *
from fractions import *
H, W = map(int, readline().split())
S = [0 for i in range(H)]
for i in range(H):
    S[i] = readline().decode().strip()

from collections import deque
def bfs(start, H, W):
    INF = 10 ** 9
    dist = [INF] * (H * W)
    q = deque([start])
    dist[start[0] * W + start[1]] = 0
    while q:
        (i, j) = q.popleft()
        d = dist[i * W + j]
        for dy in range(-1, 2):
            for dx in range(-1, 2):
                if dx * dy != 0:
                    continue
                if dx == dy:
                    continue
                if i + dy < 0 or i + dy >= H or j + dx < 0 or j + dx >= W:
                    continue
                if S[i + dy][j + dx] == '#':
                    continue
                if dist[(i + dy) * W + j + dx] != INF:
                    continue
                dist[(i + dy) * W + j + dx] = d + 1
                q.append((i + dy, j + dx))
    return max(x for x in dist if x < INF)

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