### BUGGY CODE ###

# import sys, re, os
# from collections import deque, defaultdict, Counter
# from math import ceil, sqrt, hypot, factorial, pi, sin, cos, radians
# from itertools import permutations, combinations, product, accumulate
# from operator import itemgetter, mul
# from copy import deepcopy
# from string import ascii_lowercase, ascii_uppercase, digits
# from fractions import gcd
 
# def input(): return sys.stdin.readline().strip()
# def INT(): return int(input())
# def MAP(): return map(int, input().split())
# def S_MAP(): return map(str, input().split())
# def LIST(): return list(map(int, input().split()))
# def S_LIST(): return list(map(str, input().split()))
 
# sys.setrecursionlimit(10 ** 9)
# INF = float('inf')
# mod = 10 ** 9 + 7

# # 最大公約数 
# def gcd(a, b):
#   if a < b:
#       a, b = b, a
#   while a % b != 0:
#       a, b = b, a % b
#   return b

# # 最小公倍数
# def lcm(a, b):
#   y = a*b / gcd(a, b)
#   return int(y)

# H, W = MAP()


# L = []
# for i in range(m):
#   l = list(input())
#   L.append(l)
# print(L)


from collections import deque
H, W = map(int, input().split())
maze = [list(input()) for i in range(H)]
# print(maze)
n = H
m = W

# (sx, sy) から (gx, gy) への最短距離を求める
# 辿り着けないと INF
def bfs(sy, sx, gy,gx):
    # すべての点を INF で初期化
    d = [[float("inf")] * m for i in range(n)]

    # 移動4方向のベクトル
    dx = [1, 0, -1, 0]
    dy = [0, 1, 0, -1]

    # for i in range(n):
    #     for j in range(m):
    #         # スタートとゴールの座標を探す
    #         if maze[i][j] == "S":
    #             sx = i
    #             sy = j
    #         if maze[i][j] == "G":
    #             gx = i
    #             gy = j

    # スタート地点をキューに入れ、その点の距離を0にする
    que = deque([])
    que.append((sx, sy))
    d[sx][sy] = 0

    # キューが空になるまでループ
    while que:
        # キューの先頭を取り出す
        p = que.popleft()
        # 取り出してきた状態がゴールなら探索をやめる
        if p[0] == gx and p[1] == gy:
            break
        # 移動4方向をループ
        for i in range(4):
            # 移動した後の点を (nx, ny) とする
            nx = p[0] + dx[i]
            ny = p[1] + dy[i]

            # 移動が可能かの判定とすでに訪れたことがあるかの判定
            # d[nx][ny] != INF なら訪れたことがある
            if 0 <= nx < n and 0 <= ny < m and maze[nx][ny] != "#" and d[nx][ny] == float("inf"):
                # 移動できるならキューに入れ、その点の距離を p からの距離 +1 で確定する
                que.append((nx, ny))
                d[nx][ny] = d[p[0]][p[1]] + 1

    return d[gx][gy]



ans = 0
l = []
for h in range(H):
    for w in range(W):
        for h1 in range(H):
            for w1 in range(W):
                # ans = max(ans, bfs(w, h, w1, h1))
                if bfs(w, h, w1, h1) != float("inf"):
                    l.append(bfs(w, h, w1, h1))
print(max(l))

# print(ans)
# print(bfs())      




### FIXED CODE ###

from collections import deque

H, W = map(int, input().split())
maze = [list(input()) for i in range(H)]
# print(maze)

# (sx, sy) から (gx, gy) への最短距離を求める
# 辿り着けないと INF
def bfs(sy, sx):
    # すべての点を INF で初期化
    d = [[float("inf")] * W for i in range(H)]

    # 移動4方向のベクトル
    dx = [1, 0, -1, 0]
    dy = [0, 1, 0, -1]

    # for i in range(n):
    #     for j in range(m):
    #         # スタートとゴールの座標を探す
    #         if maze[i][j] == "S":
    #             sx = i
    #             sy = j
    #         if maze[i][j] == "G":
    #             gx = i
    #             gy = j

    # スタート地点をキューに入れ、その点の距離を0にする
    que = deque([])
    que.append((sy, sx))
    d[sy][sx] = 0
    
    max_root = 0
    # キューが空になるまでループ
    while que:
        # キューの先頭を取り出す
        p = que.popleft()
        # 取り出してきた状態がゴールなら探索をやめる
        # if p[0] == gx and p[1] == gy:
        #     break
        # 移動4方向をループ
        for i in range(4):
            # 移動した後の点を (nx, ny) とする
            nx = p[1] + dx[i]
            ny = p[0] + dy[i]

            # 移動が可能かの判定とすでに訪れたことがあるかの判定
            # d[nx][ny] != INF なら訪れたことがある
            if 0 <= nx < W and 0 <= ny < H and maze[ny][nx] != "#" and d[ny][nx] == float("inf"):
                # 移動できるならキューに入れ、その点の距離を p からの距離 +1 で確定する
                que.append((ny, nx))
                d[ny][nx] = d[p[0]][p[1]] + 1
                max_root = max(max_root, d[ny][nx])    
    return max_root



ans = 0
for h in range(H):
    for w in range(W):
        if maze[h][w] == ".":
            ans = max(bfs(h, w), ans)
print(ans)

# print(ans)
# print(bfs())