#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <queue>
#include <climits>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int,int> pii;

#define INF INT_MAX/3
#define REP(i,n) for(int i=0;i<n;i++)

array<array<int,22>,22> kioku_field;
array<array<int,22>,22> real_field;

queue<pair<int,pii>> que;

int H,W;

int solve_maze(int i,int j){
	
//	for(auto& s: kioku_field){
//		fill(s.begin(),s.end(),0);
//	}
	kioku_field = real_field;
	//4houkou push
	int max_cost = 0;	
	que.emplace(0,pii{i,j});
	//cout<<"----"<<endl;
	int ccc = 0;
	while(!que.empty()){
		ccc++;
		if(ccc > 10000)break;
		auto now_point = que.front();que.pop();
		//cout<<"np : "<<now_point.first<<endl;	
		int now_i = now_point.second.first ;
		int now_j = now_point.second.second;
		//cout<<"i : "<<now_i<<"j : "<<now_j<<endl;
		kioku_field[now_i][now_j] = 1;

		if(max_cost <  now_point.first){
			max_cost = now_point.first;
		}

//		if(now_i - 1 >= 0 && field[now_i-1][now_j]!='#' && kioku_field[now_i-1][now_j] == 0)que.emplace(now_point.first+1,pii{now_i -1, now_j});
//		if(now_i + 1 < H && field[now_i+1][now_j]!='#'  && kioku_field[now_i+1][now_j] == 0)que.emplace(now_point.first+1,pii{now_i + 1, now_j});
//		if(now_j - 1 >= 0 && field[now_i][now_j-1]!='#'  && kioku_field[now_i][now_j-1] == 0)que.emplace(now_point.first+1,pii{now_i, now_j - 1});
//		if(now_j + 1 < W && field[now_i][now_j+1]!='#' && kioku_field[now_i][now_j+1] == 0)que.emplace(now_point.first+1,pii{now_i, now_j + 1});



		if(now_i - 1 >= 0 && kioku_field[now_i-1][now_j] == 0)que.emplace(now_point.first+1,pii{now_i -1, now_j});
		if(now_i + 1 < H && kioku_field[now_i+1][now_j] == 0)que.emplace(now_point.first+1,pii{now_i + 1, now_j});
		if(now_j - 1 >= 0 && kioku_field[now_i][now_j-1] == 0)que.emplace(now_point.first+1,pii{now_i, now_j - 1});
		if(now_j + 1 < W && kioku_field[now_i][now_j+1] == 0)que.emplace(now_point.first+1,pii{now_i, now_j + 1});


	}

	return max_cost;
}
int main(){

	

	cin>>H>>W;

	REP(i,H){
		REP(j,W){
			char c;
			cin>>c;

			if(c == '#'){
				real_field[i][j] = 1;
			}
			else{
				real_field[i][j] = 0;
			}
		}
	}

	int max_cost = 0;
	REP(i,H){
		REP(j,W){

			if(real_field[i][j] == 1)continue;

			//cout<<i<<" "<<j<<" "<<k<<" "<<l<<endl;

			auto ans = solve_maze(i,j);
			max_cost = max(ans,max_cost);
		}
	}
	cout<<max_cost<<endl;
	return 0;
}

