def num():
    return int(input())
def nums():
    return list(map(int,input().split()))

import itertools as iter
import math
import fractions
from functools import reduce

def lcm_base(x, y):
    return (x * y) // fractions.gcd(x, y)

def lcm(*numbers):
    return reduce(lcm_base, numbers, 1)

def lcm_list(numbers):
    return reduce(lcm_base, numbers, 1)

H,W = nums()
meiro = [[1] + [int(n == "#") for n in list(input())] + [1] for _ in range(H)]
meiro.insert(0,[1 for _ in range(W+2)])
meiro.insert(len(meiro),[1 for _ in range(W+2)])



import math

class MazeNode:
    def __init__(self,x,y,st,cond):
        self.x = x
        self.y = y
        self.state = st
        self.cond = cond
        self.parent = None
        self.fs = 0
        self.hs = 0
        self.gs = 0

    def calc_hs(self,gx,gy):
        dx = self.x - gx
        dy = self.y - gy
        self.hs = math.sqrt(dx ** 2 + dy ** 2)
    
    def update_gs(self):
        self.gs = self.fs - self.hs

    def set_gs(self,val):
        self.gs = val

    def set_cond(self,cond):
        if cond == "open" or cond == "close":
            self.cond = cond
        else:
            ##print("cond set error")
            pass
    
    # debug
    def show_pos(self):
        pass
        ##print("(%d:%d) %d %s" % (self.x,self.y,self.state,self.cond))

def get_min_fs_node(maze_nodes):
    # open_nodeのうちmin_fsのものを1つreturn
    res_node = None
    for row in maze_nodes:
        for node in row:
            if node.cond != "open":
                continue
            if not res_node:
                res_node = node
            elif node.fs < res_node.fs:
                res_node = node
    return res_node

def check_next_node(target_node,maze_nodes):
    # get next nods
    tx = target_node.x
    ty = target_node.y
    next_nodes = [
            maze_nodes[ty-1][tx  ],
            maze_nodes[ty  ][tx+1],
            maze_nodes[ty+1][tx  ],
            maze_nodes[ty  ][tx-1]
            ]

    # process next nodes
    target_node.update_gs()
    for node in next_nodes:
        if node.state == 1:
            continue
        f_dash = target_node.gs + node.hs + 1
        if node.cond == "none":
            node.set_cond("open")
            node.fs = f_dash
            node.parent = target_node
        elif node.cond == "open" and f_dash < node.fs:
            node.fs = f_dash
            node.parent = target_node
        elif node.cond == "close" and f_dash < node.fs:
            node.set_cond("open")
            node.fs = f_dash
            node.parent = target_node

def print_route(maze,fin_node):
    # make map data
    print()
    map = []
    for y in range(len(maze)):
        row = []
        for x in range(len(maze[0])):
            row.append("-" if maze[y][x] == 1 else " ")
        map.append(row)

    # make route data
    node = fin_node
    while node:
        map[node.y][node.x] = "x"
        node = node.parent

    # print route data
    for y in range(len(map)):
        for x in range(len(map[0])):
            print(map[y][x], end="")
        print("")

def make_route(fin_node):
    
    r = 0
    node = fin_node

    while node.parent:
        r += 1
        node = node.parent

    return r



def checkio(data,start,goal):
    maze = data
    maze_nodes = []

    goal_pos_x,goal_pos_y = goal

    for y in range(len(maze)):
        row = []
        for x in range(len(maze[0])):
            node = MazeNode(x,y,maze[y][x],"none")
            node.calc_hs(goal_pos_x,goal_pos_y)
            row.append(node)
        maze_nodes.append(row)

    start_node = maze_nodes[start[0]][start[1]]
    start_node.set_cond("open")
    start_node.set_gs(0)
    start_node.fs = start_node.hs

    while True: # step12:repeat
        # step3,4
        target_node = get_min_fs_node(maze_nodes)
        if not target_node:
            # step3
            #print("search fail")
            return "fail"
        elif target_node.x == goal_pos_x and target_node.y == goal_pos_y:
            #step5_finish
            #print("search finish")
            #print_route(maze,target_node)
            return make_route(target_node) #step13
        else:
            # step5_continue
            target_node.set_cond("close")
            check_next_node(target_node,maze_nodes) #step6-11



    
ans = set()
goals = [(x,y) for y in range(H+2) for x in range(W + 2)]
starts = [(x,y) for y in range(H) for x in range(W)]
for s in starts:
    for g in goals:
        try:
            r = checkio(meiro,s,g)
            if not r == "fail":ans.add(r)
        except:pass
print(max(ans)-1)