#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#define int long long
#define mkp make_pair
#define pb push_back
#define ff first
#define ss second
#define debug1(a) cout<<a<<endl;
#define debug2(a,b) cout<<a<<' '<<b<<endl;
#define debug3(a,b,c) cout<<a<' '<<b<<' '<<c<<endl;
#define rep(i,n) for(int i=0;i<n;i++)
#define repre(i,a,b)for(int i=a;i<=b;i++)
#define clr1(arr) memset(arr,-1,sizeof(arr));
#define clr0(arr) memset(arr,0,sizeof(arr));
#define pi pair<int,int>
#define pii pair<int,pi>
#define aint(v) v.begin(),v.end()
#define fastio ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace __gnu_pbds;
using namespace std;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> orderedSet;
typedef tree<int,null_type,less_equal<int>,rb_tree_tag,tree_order_statistics_node_update> orderedMSet;
struct custom_hash {
static uint64_t splitmix64(uint64_t x) {
        // http://xorshift.di.unimi.it/splitmix64.c
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};
#define ump gp_hash_table<int,int,custom_hash>
//*p.find_by_order(index) return value at index
//p.order_of_key(key) return index
/*int **dp,in main function,int row,col;dp=new int*[n];rep(i,n)dp[i]=new int[m]*/
//**** Maths Section*******/
int power(int x,int y);
bool isPrime(int n);
int modInv(int a,int b);
int gcdExtended(int a,int b,int *x,int* y);
int mpower(int a,int b,int p);
/***************************/
string arr[25];
int n,m;
vector<pi >v;
int a,b;
int dp[30][30];
int visited[30][30];
bool isSafe(int x,int y)
{
  if(visited[x][y]==0 && x>=0 && x<n && y>=0 && y<m && arr[x][y]=='.')return true;
  return false;
}
int dfs(int x,int y)
{
  if(dp[x][y]!=-1){visited[x][y]=0;return dp[x][y];}
  visited[x][y]=1;
  if(x==v[b].ff && y==v[b].ss){visited[x][y]=0;return dp[x][y]=0;}
  int up=INT_MAX;
  int down=INT_MAX;
  int left=INT_MAX;
  int right=INT_MAX;
  if(isSafe(x-1,y))up=1+dfs(x-1,y);
  if(isSafe(x+1,y))down=1+dfs(x+1,y);
  if(isSafe(x,y-1))left=1+dfs(x,y-1);
  if(isSafe(x,y+1))right=1+dfs(x,y+1);
  visited[x][y]=0;
  return dp[x][y]= min(up,min(down,min(left,right)));
}
int solve()
{
  int x=v[a].ff;
  int y=v[a].ss;
  clr0(visited);
  clr1(dp);
  queue<pi> q;
  q.push({x,y});
  q.push({-1,-1});
  int dist=0;
  visited[x][y]=1;
  while(q.empty()==false)
  {
    pi temp=q.front();
    q.pop();
    if(temp.ff==-1)
    {
      dist++;
      if(q.empty())break;
      else
      {
        q.push({-1,-1});
      }
    }
    int x=temp.ff;
    int y=temp.ss;
  //  visited[x][y]=1;.
    if(isSafe(x+1,y)){q.push({x+1,y});visited[x+1][y]=1;}
    if(isSafe(x-1,y)){q.push({x-1,y});visited[x-1][y]=1;}
    if(isSafe(x,y-1)){q.push({x,y-1});visited[x][y-1]=1;}
    if(isSafe(x,y+1)){q.push({x,y+1});visited[x][y+1]=1;}
  }
  return dist-1;

  //if(x==0 && y==2)cout<<"A"<<endl;
  return dfs(x,y);
}
int32_t main()
{
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
  fastio
  cin>>n>>m;
  int maxe=0;
  rep(i,n)cin>>arr[i];
  rep(i,n)rep(j,m)if(arr[i][j]=='.')v.pb({i,j});
  rep(i,v.size())
  {
    for(int j=i+1;j<v.size();j++)
    {
      a=i;
      b=j;
      int ans=solve();
    //  cout<<v[i].ff<<" "<<v[i].ss<<" "<<v[j].ff<<" "<<v[j].ss<<" "<<ans<<endl;
      maxe=max(ans,maxe);
    }
  }
  cout<<maxe<<endl;

  return 0;
}

int modInv(int a, int m)
{
int x, y;
int g = gcdExtended(a, m, &x, &y);
int res = (x%m + m) % m;
return res;
}

int gcdExtended(int a, int b, int *x, int *y)
{
if (a == 0){
    *x = 0, *y = 1;
    return b;
  }
  int x1, y1;
  int gcd = gcdExtended(b%a, a, &x1, &y1);
  *x = y1 - (b/a) * x1;
  *y = x1;
  return gcd;
}

int mpower(int x, int y, int p)
{
int res = 1;
x = x % p;
while(y > 0){
    if(y & 1) res = (res*x) % p;
      y = y>>1;
      x = (x*x) % p;
    }
    return res;
}
int power(int x, int y)
{
int res = 1;
while (y > 0){
    if (y & 1) res = res*x;
      y = y>>1;
      x = x*x;
    }
    return res;
}

bool isPrime(int n)
{
if (n <= 1)  return false;
  if (n <= 3)  return true;
    if (n%2 == 0 || n%3 == 0) return false;
      int p=sqrt(n);
      for(int i=5;i<=p;i=i+6)
        if (n%i == 0 || n%(i+2) == 0)
          return false;
      return true;
}


Measured memory_bytes: 256