//includes
#include<iostream>
#include<vector>
#include<set>
#include<tuple>
#include<algorithm>
#include<cmath>
#include<string>
#include<stack>
#include<map>
#include<queue>
#include<iomanip>
#include<numeric>
#include<assert.h>
#include<cstring>
#include<unordered_map>
#include<bitset>

//macros and consts
#define REP(i, n) for(int i = 0; i < (int)(n); i++)
#define all(a) (a).begin(),(a).end()
#define FOR(i,a,b) for(int i = (a); i < (b); i++)
#define FORE(i,a) for(auto &i : a)
#define pb push_back
#define mp make_pair
#define eb emplace_back
#define accm accumulate
#define Fi first
#define Se second
#define INF 1e9
#define llINF (1LL<<60)
#define mINF -1e9
#define mllINF -(1LL<<60)
#define endl "\n"
#define CONT continue
#define BRK break
#define modulo(n, m) (((n)%(m)+(m))%m)

//shorter types
using namespace std;
using ll = long long;
using vi = std::vector<int>;
using vc = std::vector<char>;
using vll = std::vector<long long>;
using vs = std::vector<string>;
using Mi = map<int,int>;
using Mll = map<ll,ll>;
using UMi = unordered_map<int,int>;
using UMll = unordered_map<ll,ll>;
using Pi = pair<int,int>;
using Pll = pair<ll,ll>;
using vPi = vector<Pi>;
using vPll = vector<Pll>;
using vvi = vector<vector<int>>;
using vvll = vector<vector<ll>>;
using vvc = vector<vector<char>>;
using vvs = vector<vector<string>>;
using pqgi = priority_queue<int,vector<int>,greater<int>>;
using pqsi = priority_queue<int,vector<int>,less<int>>;
using pqgll = priority_queue<int,vector<int>,greater<int>>;
using pssll = priority_queue<int,vector<int>,less<int>>;
template<class T>
using vec = vector<T>;
#define int long long



vector<vector<char>> S;
int H,W;
int solve(int x,int y){
	vector<vector<int>> maze;
	maze.resize(H,vector<int>(W,-1));
	maze[x][y] = 0;
	queue<pair<int,int>> q;
	q.push(make_pair(x,y));
	while(!q.empty()){
		pair<int,int> p = q.front();
		q.pop();

		int x = p.first;
		int y = p.second;
		if(x + 1 < H){
			if(S[x + 1][y] == '.'){
				if(maze[x+1][y] == -1){
					maze[x+1][y] = maze[x][y] + 1;
					q.push(make_pair(x + 1,y));
				}
			}
		}

		if(y + 1 < W){
			if(S[x][y + 1] == '.'){
				if(maze[x][y + 1] == -1){
					maze[x][y + 1] = maze[x][y] + 1;
					q.push(make_pair(x,y + 1));
				}
			}
		}

		if(x - 1 >= 0 ){
			if(S[x - 1][y] == '.'){
				if(maze[x - 1][y] == -1){
					maze[x - 1][y] = maze[x][y] + 1;
					q.push(make_pair(x - 1,y));
				}
			}
		}

		if(y - 1 >= 0){
			if(S[x][y - 1] == '.'){
				if(maze[x][y - 1] == -1){
					maze[x][y - 1] = maze[x][y] + 1;
					q.push(make_pair(x,y - 1));
				}
			}
		}
	}
	int largest = -1;
	for(int h = 0 ; h < H ; h++){
		for(int w = 0 ; w < W ; w++){
			largest = max(largest,maze[h][w]);
		}
	}
	return largest;
}

//here begins your code
signed main(){
  std::ios::sync_with_stdio(false);
  std::cin.tie(0);

  cin >> H >> W;
  S.resize(H,vector<char>(W,' '));
  for(int h = 0 ; h < H; h++){
  	for(int w = 0 ; w < W ; w++){
  		cin >> S[h][w];
  	}
  }
  int ans = -1;
  for(int h = 0 ; h < H; h++){
  	for(int w = 0 ; w < W; w++){
  		if(S[h][w] == '.'){
	  		ans = max(ans,solve(h,w));
  		}
  	}
  }
  cout << ans << endl;
  //check types
  //do not eb if you resize
  //resize before you access by idx
  return 0;
} 

Measured memory_bytes: 256