#include <bits/stdc++.h>
using namespace std;
using pii=pair<int,int>;
using ll=long long;

#define fi first
#define se second
#define pb push_back
#define rep(i,n) for(int i=0; i<(int)(n); i++)

template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return 1; } return 0; }

int bfstable[20][20];
bool visited[20][20];
int h,w;
queue<pii> q;
pii start, goal;
int x[4] = {-1,1,0,0};
int y[4] = {0,0,-1,1};

int bfs(vector<string> s) {
	while(!q.empty()) {
		pii current = q.front(); q.pop();

		rep(i,4) {
			pii next;
			next.fi = current.fi + x[i];
			next.se = current.se + y[i];
			if (next.fi < h && next.fi >= 0 && next.se < w && next.se >= 0 && visited[next.fi][next.se] == false && s[next.fi][next.se] == '.') {
				//cout << "in " << next.fi << " " << next.se << endl;
				visited[next.fi][next.se] = true;
				chmin(bfstable[next.fi][next.se], bfstable[current.fi][current.se] + 1);
				q.push(next);
			}
		}
		if (q.empty()) {
			//cout << "endpoint: " << current.fi << current.se << endl;
			return bfstable[current.fi][current.se];
		}
	}
}

		/*pii next1(current.fi+1, current.se);
		if (next1.fi < h && visited[next1.fi][next1.se] == false) {
			chmin(bfstable[next1.fi][next1.se], bfstable[current.fi][current.se] + 1);
			q.push(next1);
		}
		pii next2(current.fi, current.se+1);
		if (next2.se < w) {
			chmin(bfstable[next2.fi][next2.se], bfstable[current.fi][current.se] + 1);
			q.push(next2);
		}
		pii next3(current.fi-1, current.se);
		if (next3.se >= 0) {
			chmin(bfstable[next3.fi][next3.se], bfstable[current.fi][current.se] + 1);
			q.push(next3);
		}
		pii next4(current.fi, current.se-1);
		if (next4.se >= 0) {
			chmin(bfstable[next4.fi][next4.se], bfstable[current.fi][current.se] + 1);
			q.push(next4);
		}
		*/
	
/*int dfs (vector<string> map, pii current, pii goal) {
	cout << "current: " << current.fi << current.se << endl;
	if(current.fi == goal.fi && current.se == goal.se){
		cout << "goal! currenttablevalue:" << dfstable[goal.fi][goal.se]<< endl;
		return dfstable[goal.fi][goal.se];
	}
	else {
		cout << "!else in!" << endl;
		pii next1(current.fi+1, current.se);
		pii next2(current.fi, current.se+1);
		if (next1.fi < h) {
			if (map[next1.fi][next1.se] == '.' && next1.fi <= goal.fi) {
				cout << "next1" << endl;
				chmin(dfstable[next1.fi][next1.se], dfstable[current.fi][current.se]+1);
				dfs(map, next1, goal);
			}
		}
		if (next2.se < w) {
			if (map[next2.fi][next2.se] == '.' && next2.se <= goal.se) {
				cout << "next2" << endl;
				cout << dfstable[next2.fi][next2.se] << " currenttablevalue: " << dfstable[current.fi][current.se] << endl;
				
				chmin(dfstable[next2.fi][next2.se], dfstable[current.fi][current.se]+1);
				dfs(map, next2, goal);
			}
		}
	}
}
*/
int main() {
	cin >> h >> w;
	vector<string> s(h);
	rep(i,h) cin >> s[i];
	int max = -1e9;
	rep(i,h) rep(j,w) {
		queue<pii> empty;
		swap(q,empty);
		start.fi = i;
		start.se = j;
		//goal.fi = k;
		//goal.se = l;
		q.push(start);
		//cout << "i: " << i << " j:" << j << endl;
		//cout << start.fi << " " << start.se << endl;
		//cout << s[start.fi][start.se] << endl;
		if (s[start.fi][start.se] == '.') {
			//cout << "in!" << endl;
			rep(i,20) rep(j,20) {
				bfstable[i][j] = 1e9;
				visited[i][j] = false;
			}
			bfstable[start.fi][start.se] = 0;
			visited[start.fi][start.se] = true;
			chmax(max, bfs(s));
		}
	}
	cout << max << endl;

  return 0;
}


Measured memory_bytes: 256