#include <bits/stdc++.h>
 
using namespace std;

#define M 1000000007
#define pb emplace_back
#define f first
#define s second
#define rep(i, st, ed) for(ll i=st; i<ed; ++i)
#define repn(i, st, ed) for(ll i=st; i<=ed; ++i)
#define repb(i, ed, st) for(ll i=ed; i>=st; --i)
#define all(v) v.begin(),v.end()
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );

typedef long long ll;
typedef unsigned long long int llt;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef vector<ll> vec;
typedef vector<pll> vecp;
typedef map<ll, ll> mpll;

const long double PI  = 3.141592653589793238463;
const int N = 2e5 + 10;
const ll INF = 1LL << 60;

template<class T> void chmax(T &a,T b) { if (a<b) a=b;}
template<class T> void chmin(T &a,T b) { if (a>b) a=b;}

template <typename A, typename B>
string to_string(pair<A, B> p);
 
template <typename A, typename B, typename C>
string to_string(tuple<A, B, C> p);
 
template <typename A, typename B, typename C, typename D>
string to_string(tuple<A, B, C, D> p);
 
string to_string(const string& s) {
  return '"' + s + '"';
}
 
string to_string(const char* s) {
  return to_string((string) s);
}
 
string to_string(bool b) {
  return (b ? "true" : "false");
}
 
string to_string(vector<bool> v) {
  bool first = true;
  string res = "{";
  for (int i = 0; i < static_cast<int>(v.size()); i++) {
    if (!first) {
      res += ", ";
    }
    first = false;
    res += to_string(v[i]);
  }
  res += "}";
  return res;
}
 
template <size_t N>
string to_string(bitset<N> v) {
  string res = "";
  for (size_t i = 0; i < N; i++) {
    res += static_cast<char>('0' + v[i]);
  }
  return res;
}
 
template <typename A>
string to_string(A v) {
  bool first = true;
  string res = "{";
  for (const auto &x : v) {
    if (!first) {
      res += ", ";
    }
    first = false;
    res += to_string(x);
  }
  res += "}";
  return res;
}
 
template <typename A, typename B>
string to_string(pair<A, B> p) {
  return "(" + to_string(p.first) + ", " + to_string(p.second) + ")";
}
 
template <typename A, typename B, typename C>
string to_string(tuple<A, B, C> p) {
  return "(" + to_string(get<0>(p)) + ", " + to_string(get<1>(p)) + ", " + to_string(get<2>(p)) + ")";
}
 
template <typename A, typename B, typename C, typename D>
string to_string(tuple<A, B, C, D> p) {
  return "(" + to_string(get<0>(p)) + ", " + to_string(get<1>(p)) + ", " + to_string(get<2>(p)) + ", " + to_string(get<3>(p)) + ")";
}
 
void debug_out() { cerr << endl; }
 
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
  cerr << to_string(H) << endl;
  debug_out(T...);
}
#define LOCAL 3
#ifdef LOCAL
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:" << endl, debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

ll arr[405][405];
char ch[25][25];
int mx[4] = {0, 0, -1, 1};
int my[4] = {-1, 1, 0, 0};
void solve()
{
	int h, w;
	cin>>h>>w;
	repn(i, 1, h)repn(j, 1, w) cin>>ch[i][j];
	repn(i, 0, w) ch[0][i] = ch[h+1][i] = '#';
	repn(i, 0, h) ch[i][0] = ch[i][w+1] = '#';
	ll mm = h*w + 1;
	repn(i, 0, mm)
		repn(j, 0, mm)
			arr[i][j] = INT_MAX;
	repn(i, 1, h)
	{
		repn(j, 1, w)
		{
			if(ch[i][j] != '#')
			{
				int curr = (i-1)*w + j;
				arr[curr][curr] = 0;
				rep(k, 0, 4)
				{
					int nx = i + mx[k];
					int ny = j + my[k];
					if(ch[nx][ny] != '#')
					{
						int next = (nx - 1)*w + ny;
						arr[curr][next] = 1;
						arr[next][curr] = 1;
					}
				}
			}
		}
	}
	repn(k, 1, mm)
	{
		repn(i, 1, mm)
		{
			
			repn(j, 1, mm)
			{
				ll curri  = ((i-1) / w) + 1;
				ll currj = ((i-1) % w) + 1 ;
				if(curri <= 0 || curri > h || currj <= 0 || currj > w) continue;
				if(ch[curri][currj] == '#') {continue;}
				if(arr[i][j] > (arr[i][k] + arr[k][j]))
					arr[i][j] = arr[i][k] + arr[k][j];
			}
		}
	}
	ll ans = 0;
	repn(i, 0, 401)
		repn(j, 0, 401)
			if(arr[i][j] != INT_MAX)
				chmax(ans, arr[i][j]);
	cout<<ans<<endl;
}


int main()
{
	ll Tests = 1;
    //cin>>Tests;
    while(Tests--)
    {
    	solve();
    }
    return 0;
}

Measured memory_bytes: 1536