S=lambda:input()
I=lambda:int(input())
L=lambda:list(map(int,input().split()))
LS=lambda:list(map(str,input().split()))

def main():
    from collections import deque
    import copy
    h,w=L()
    grid=[S() for i in range(h)]
    dist=[[-1]*w for i in range(w)]
    start=deque()
    for i in range(h):
        for j in range(w):
            if grid[i][j]=='.':
                start.append((i,j))
                #(h,w):tuple, immutable
                
                dist[i][j]=-2
                
    def bfs(start,dist):
        ans=0
        d=0
        search=deque()
        #c=0
        while start:
            #print("#####################")
            #c+=1
            #print(c,ans)
            sty,stx=start.popleft()
            search.append((sty,stx))
            new_dist=copy.deepcopy(dist)
            new_dist[sty][stx]=0
            while search:
                tmph,tmpw=search.popleft()
                #print("$$$",end="")
                #print(tmph,tmpw,end="")
                #print("$$$")
                d=new_dist[tmph][tmpw]
                
                for dy,dx in ((1,0),(0,1),(-1,0),(0,-1)):
                    new_h=tmph+dy
                    new_w=tmpw+dx
                    if new_h<0 or h<=new_h or new_w<0 or w<=new_w: continue
                    if new_dist[new_h][new_w]==-2:
                        new_dist[new_h][new_w]=d+1
                        search.append((new_h,new_w))
                        ans=max(ans,d+1)
                
                #for i in range(h):
                #    print("".join([str(a) if a>=0 else '#' if a==-1 else '.' for a in new_dist[i]]))
                #print("###")
        return ans
                
    print(bfs(start,dist)) 
    
if __name__ == '__main__':
    main()

### FIXED CODE ###

S=lambda:input()
I=lambda:int(input())
L=lambda:list(map(int,input().split()))
LS=lambda:list(map(str,input().split()))

def main():
    from collections import deque
    import copy
    h,w=L()
    grid=[S() for i in range(h)]
    dist=[[-1]*w for i in range(h)]
    start=deque()
    for i in range(h):
        for j in range(w):
            if grid[i][j]=='.':
                start.append((i,j))
                #(h,w):tuple, immutable
                
                dist[i][j]=-2
                
    def bfs(start,dist):
        ans=0
        d=0
        search=deque()
        #c=0
        while start:
            #print("#####################")
            #c+=1
            #print(c,ans)
            sty,stx=start.popleft()
            search.append((sty,stx))
            new_dist=copy.deepcopy(dist)
            new_dist[sty][stx]=0
            while search:
                tmph,tmpw=search.popleft()
                #print("$$$",end="")
                #print(tmph,tmpw,end="")
                #print("$$$")
                d=new_dist[tmph][tmpw]
                
                for dy,dx in ((1,0),(0,1),(-1,0),(0,-1)):
                    new_h=tmph+dy
                    new_w=tmpw+dx
                    if new_h<0 or h<=new_h or new_w<0 or w<=new_w: continue
                    if new_dist[new_h][new_w]==-2:
                        new_dist[new_h][new_w]=d+1
                        search.append((new_h,new_w))
                        ans=max(ans,d+1)
                
                #for i in range(h):
                #    print("".join([str(a) if a>=0 else '#' if a==-1 else '.' for a in new_dist[i]]))
                #print("###")
        return ans
                
    print(bfs(start,dist)) 
    
if __name__ == '__main__':
    main()