from collections import deque
 
H, W = map(int, input().split())
S = [input() for _ in range(H)]
INF = 10**15

answer = 0
for i in range(H):
  for j in range(W):
    if S[i][j] == "#":
      continue
    else:
      dist = [[INF for _ in range(W)] for _ in range(H)] # 始点からの距離
      dist[i][j] = 0 # 始点を定義
      stack = deque([(i, j)]) # 始点を"先入れ先出し"の配列に入れる
      
      while stack:
      # BFS
      # * 計算量 O(4HW:辺の数)
      si, sj = stack.popleft() 
        # "先入れ先出し"
        # * ⇔後入れ後出し。DFS
        #   si, sj = stack.pop()
        
        for ni, nj in [(si + 1, sj), (si - 1, sj), (si, sj + 1), (si, sj - 1)]:
        # 経路に重みがない場合、BFSでは先に入れた方がそのマスに対する最短経路になる...☆
        # * DFSを使用すると更新の必要があり、
        #    計算量が(4HW*HW:辺の数×グリッドの数)->TLE
        # ** 木だと経路は1つしかないため、BFSもDFSも計算量は同じ
        #     グラフでは基本的にBFS推奨[要出典]
        # * 経路に重みがある場合も更新の必要があり、計算量はO(4HW*HW)
        # ** Dijkstra法を使えば、計算量はO(4HW+HWlogHW)
        #     O(E + VlogV): E -> Edge, V -> Vertex
          if 0 <= ni <= H - 1 and 0 <= nj <= W - 1 and S[ni][nj] != "#":
            if dist[ni][nj] > dist[si][sj] + 1:
              dist[ni][nj] = dist[si][sj] + 1
              stack.append((ni, nj))
          # ☆より、最短経路をとるマスからの隣接が次の最短経路の候補となる
          # すでに最短経路を取っているものは排除
              
              
      max_dist = 0
      for ii in range(H):
        for jj in range(W):
          if dist[ii][jj] != INF:
            max_dist = max(max_dist, dist[ii][jj])
      answer = max(max_dist, answer)
      # * 添え字被りに注意
      
print(answer)
