from collections import deque

 

H, W = list(map(int, input().split()))

S = [eval(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)
from collections import deque

 

H, W = list(map(int, input().split()))

S = [eval(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 # 始点を定義

      queue = deque([(i, j)]) # 始点を"先入れ先出し"の配列に入れる

      

      while queue:

      # BFS

      # * 計算量 O(4HW:辺の数)

        si, sj = queue.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

              queue.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)





from collections import deque

H, W = list(map(int, input().split()))
S = [eval(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)

from collections import deque

H, W = list(map(int, input().split()))
S = [eval(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  # 始点を定義
            queue = deque([(i, j)])  # 始点を"先入れ先出し"の配列に入れる
            while queue:
                # BFS
                # * 計算量 O(4HW:辺の数)
                si, sj = queue.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
                            queue.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)

-            stack = deque([(i, j)])  # 始点を"先入れ先出し"の配列に入れる -            while stack: +            queue = deque([(i, j)])  # 始点を"先入れ先出し"の配列に入れる +            while queue: -                si, sj = stack.popleft() +                si, sj = queue.popleft() -                # * ⇔後入れ後出し。DFS +                # * ⇔後入れ先出し。DFS -                    #    計算量が(4HW*HW:辺の数×グリッドの数)->TLE +                    #   計算量が(4HW*HW:辺の数×グリッドの数) -> TLE -                    #     グラフでは基本的にBFS推奨[要出典] +                    #    グラフでは基本的にBFS推奨[要出典] -                    #     O(E + VlogV): E -> Edge, V -> Vertex +                    #    O(E + VlogV): E -> Edge, V -> Vertex -                            stack.append((ni, nj)) +                            queue.append((ni, nj)) -            # * 添え字被りに注意 +            # 添え字被りに注意