3 5
...#.
.#.#.
.#...#include <bits/stdc++.h>
#define Int long long
#define pb push_back
using namespace std;


Int N,M,K;
Int X,Y,Z,D;
const int MAXN=105;
Int B,C;


struct DisJointSet{
    vector<int> SZ;
    vector<int> ID;
    int n;

    DisJointSet(int n){
        SZ.resize(n);
        ID.resize(n);
        this->n=n;
        
        for(int i=0;i<n;++i){
            ID[i]=i;
            SZ[i]=1;
        }
    }
    
    int find(int x){
        return (ID[x]==x ? x:find(ID[x]));
    }
    
    void Union_find(int x,int y){
        x=find(x);
        y=find(y);
        if(x==y) return;
        if(SZ[x]>SZ[y]){
            ID[y]=x;
            SZ[x]+=SZ[y];
        }
        else{
            ID[x]=y;
            SZ[y]+=SZ[x];
        }
        return;
    }
};
vector<pair<int,int>> dir{{-1,0},{0,-1},{0,1},{1,0}};
Int shortestPath(vector<vector<int>> grid,pair<int,int> start,pair<int,int> end){
    queue<pair<int,int>> q;
    q.push(start);
    int iter=0;
    while(!q.empty()){
        int tt=q.size();
        while(tt--){
            auto u=q.front();
            q.pop();
            if(u==end) return iter;
            for(auto itr:dir){
                int x=u.first+itr.first;
                int y=u.second+itr.second;
                if(x<0||y<0||x>=grid.size()||y>=grid[0].size()||!grid[x][y]) continue;
                grid[x][y]=0;
                q.push({x,y});
            }
            
        }
        ++iter;
    }
    
}

int main()
{
    cin>>N>>M;
    vector<vector<int>> grid(N,vector<int>(M,0));
    for(int i=0;i<N;++i){
        for(int j=0;j<M;++j){
            char x;cin>>x;
            grid[i][j]=(x=='.' ? 1:0);
        }
    }
    Int ans=-1e9;
    for(int i=0;i<N;++i){
        for(int j=0;j<M;++j){
            for(int x=0;x<N;++x){
                for(int y=0;y<M;++y){
                    if(!grid[i][j]||!grid[x][y]) continue;
                    ans=max(ans,shortestPath(grid,{i,j},{x,y}));
                }
            }
        }
    }
    cout<<ans<<"\n";
}