### BUGGY CODE ###

from collections import defaultdict, deque, Counter
from heapq import heappush, heappop
from itertools import permutations, accumulate
from math import sqrt, ceil, floor, factorial
from bisect import bisect_left, bisect_right
from copy import deepcopy
from operator import itemgetter
from fractions import gcd
import sys
def I(): return int(input())  # '123' -> 123
def Is(): return map(int, input().split())  # '123 456' -> 123, 456
def LI(): return list(map(int, input().split()))  # '123 456' -> [123, 456]
def TI(): return tuple(map(int, input().split()))  # '123 456' -> (123, 456)
def IR(n): return [I() for _ in range(n)]
def LIR(n): return [LI() for _ in range(n)]
def TIR(n): return [TI() for _ in range(n)]
def S(): return input()
def Ss(): return input().split()  # 'aa bb' -> 'aa','bb' or ['aa','bb']
def LS(): return list(input())  # 'abc123' -> ['a','b','c','1','2','3']
def SR(n): return [S() for _ in range(n)]
def SsR(n): return [Ss() for _ in range(n)]
def LSR(n): return [LS() for _ in range(n)]
sys.setrecursionlimit(1000000)
MOD = 1000000007
INF = float('inf')

h, w = Is()
maze = LSR(h)

def bfs(sy, sx, gy, gx):
    vmaze = [[INF] * w for _ in range(h)]
    move = [(1, 0), (0, 1), (-1, 0), (0, -1)]
    que = deque()
    que.append((sy, sx))
    vmaze[sy][sx] = 0

    while que:
        py, px = que.popleft()
        if py == gy and px == gx:
            break
        for ymove, xmove in move:
            ny = py + ymove
            nx = px + xmove
            if 0 <= ny < h and 0 <= nx < w and maze[ny][nx] != '#' and vmaze[ny][nx] == INF:
                vmaze[ny][nx] = vmaze[py][px] + 1
                que.append((ny, nx))

    return vmaze[gy][gx]

ans = 0
for sy in range(h):
    for sx in range(w):
        if maze[sy][sx] == '#':
            continue
        for gy in range(h):
            for gx in range(w):
                if maze[gy][gx] == '#':
                    continue

                ans = max(ans, bfs(sy, sx, gy, gx))

print(ans)


### FIXED CODE ###

from collections import defaultdict, deque, Counter
from heapq import heappush, heappop
from itertools import permutations, accumulate
from math import sqrt, ceil, floor, factorial
from bisect import bisect_left, bisect_right
from copy import deepcopy
from operator import itemgetter
from fractions import gcd
import sys
def I(): return int(input())  # '123' -> 123
def Is(): return map(int, input().split())  # '123 456' -> 123, 456
def LI(): return list(map(int, input().split()))  # '123 456' -> [123, 456]
def TI(): return tuple(map(int, input().split()))  # '123 456' -> (123, 456)
def IR(n): return [I() for _ in range(n)]
def LIR(n): return [LI() for _ in range(n)]
def TIR(n): return [TI() for _ in range(n)]
def S(): return input()
def Ss(): return input().split()  # 'aa bb' -> 'aa','bb' or ['aa','bb']
def LS(): return list(input())  # 'abc123' -> ['a','b','c','1','2','3']
def SR(n): return [S() for _ in range(n)]
def SsR(n): return [Ss() for _ in range(n)]
def LSR(n): return [LS() for _ in range(n)]
sys.setrecursionlimit(1000000)
MOD = 1000000007
INF = float('inf')

h, w = Is()
maze = LSR(h)

def bfs(sy, sx):
    vmaze = [[INF] * w for _ in range(h)]
    move = [(1, 0), (0, 1), (-1, 0), (0, -1)]
    que = deque()
    que.append((sy, sx))
    vmaze[sy][sx] = 0

    while que:
        py, px = que.popleft()
        for ymove, xmove in move:
            ny = py + ymove
            nx = px + xmove
            if 0 <= ny < h and 0 <= nx < w and maze[ny][nx] != '#' and vmaze[ny][nx] == INF:
                vmaze[ny][nx] = vmaze[py][px] + 1
                que.append((ny, nx))

    ret = 0
    for y in range(h):
        for x in range(w):
            if vmaze[y][x] != INF:
                ret = max(ret, vmaze[y][x])
    return ret

ans = 0
for sy in range(h):
    for sx in range(w):
        if maze[sy][sx] == '#':
            continue
        ans = max(ans, bfs(sy, sx))

print(ans)