from queue import Queue
H, W = map(int, input().split())
S = [input() for _ in range(H)]
f = [0, 0]
seen = [[False]*W for _ in range(H)]
for i in range(H):
    for j in range(W):
        if S[i][j] == '.':
            f[0] = i
            f[1] = j
            break
    else:
        continue
    break
q = Queue()
q.put((f[0], f[1], 0))
D = [[0]*(W) for _ in range(H)]
seen[f[0]][f[1]] = True
while not q.empty():
    h, w, d = q.get()
    for vh, vw in [(h+1, w), (h-1, w), (h, w+1), (h, w-1)]:
        if vh < 0 or vw < 0:
            continue
        try:
            if not seen[vh][vw] and S[vh][vw] == '.':
                q.put((vh, vw, d+1))
                seen[vh][vw] = True
                D[vh][vw] = d+1
        except IndexError:
            pass
m = max([max(d) for d in D])
for h in range(H):
    for w in range(W):
        if D[h][w] == m:
            f[0] = h
            f[1] = w
            break
    else:
        continue
    break
q = Queue()
q.put((f[0], f[1], 0))
D = [[0]*(W) for _ in range(H)]
seen = [[False]*W for _ in range(H)]
seen[f[0]][f[1]] = True
while not q.empty():
    h, w, d = q.get()
    for vh, vw in [(h+1, w), (h-1, w), (h, w+1), (h, w-1)]:
        if vh < 0 or vw < 0:
            continue
        try:
            if not seen[vh][vw] and S[vh][vw] == '.':
                q.put((vh, vw, d+1))
                seen[vh][vw] = True
                D[vh][vw] = d+1
        except IndexError:
            pass
print(max([max(d) for d in D]))
