#include <bits/stdc++.h>
#include <boost/range/algorithm.hpp>
#include <boost/range/numeric.hpp>
#include <boost/range/irange.hpp>
#include <boost/range/adaptor/indexed.hpp>

using namespace std;
using namespace boost::adaptors;
using namespace std::string_literals;
using ll = int64_t;
using vecint = vector<int>;
using vecll = vector<ll>;
using boost::irange;

int main()
{
  int h,w;
  cin>>h>>w;
  vector<string> t(h);
  for(auto&& l:t) cin>>l;
  int n=h*w;
  constexpr int INF = 1000000000;
  vector<vecint> m(n, vecint(n, INF));
  for(auto&& i:irange(0,h-1)) {
    for(auto&& j:irange(0,w)) {
      if (t[i][j] == '.' && t[i+1][j] == '.') {
        m[i*w+j][(i+1)*w+j] = 1;
        m[(i+1)*w+j][i*w+j] = 1;
      }
    }
  }
  for(auto&& i:irange(0,h)) {
    for(auto&& j:irange(0,w-1)) {
      if (t[i][j] == '.' && t[i][j+1] == '.') {
        m[i*w+j][i*w+j+1] = 1;
        m[i*w+j+1][i*w+j] = 1;
      }
    }
  }
  for(auto&& k:irange(0,n)) {
    for(auto&& i:irange(0,n)) {
      for(auto&& j:irange(0,n)) {
        m[i][j] = min(m[i][j], m[i][k] + m[k][j]);
      }
    }
  }
  int mx = 0;
  for(auto&& i:irange(0,n)) {
    for(auto&& j:irange(0,n)) {
      if (m[i][j] < INF) mx = max(mx, m[i][j]);
    }
  }
  cout<<mx<<endl;
  return 0;
}
