#include <iostream> // cin, cout, cerr
#include <algorithm> // minmax, sort, swap
#include <numeric> // iota
#include <cstdio> // printf, scanf
#include <string> // string, stoi, to_string
#include <vector> // vector
#include <queue> // queue, priority_queue
#include <deque> // deque
#include <map> // key-value pairs sorted by keys
#include <set> // set
#include <iomanip> // cout<<setprecision(n)
#include <functional> // function<void(int)>
#include <cmath>

#ifdef DEBUG
#include "debug.hpp"
#else
#define debug(...)
#endif

#define int long long // at least int64 > 9*10^18
#define ENDL '\n'
#define rep(i,n) for(int i = 0; i < (n); i++)
#define print(i) std::cout << (i) << '\n'
#define all(v) (v).begin(), (v).end()
/* libraries */

int convert(int i, int j, int w) {
	return i*w+j;
}

std::pair<int,int> deconv(int i, int w) {
	std::pair<int,int> ret;
	ret.first=i/w;
	ret.second=i%w;
	return ret;
}

signed main() {
	int h,w;
	std::cin >> h >> w;
	std::vector<std::string> g(h);
	rep(i,h) std::cin >> g[i];
	std::vector<std::vector<int> > dist(h*w,std::vector<int>(h*w,INF));
	int max = 0;

	rep(i,h) {
		rep(j,w) {
			if(g[i][j]=='.') {
				// bfs
				std::queue<std::pair<int,int> > que; // i, dist
				std::vector<int> went(h*w,false);
				que.emplace(convert(i,j,w),0);
				went[convert(i,j,w)]=true;
				while(!que.empty()) {
					auto tp = que.front(); que.pop();
					int xx = tp.first;
					int x = deconv(xx,w).first;
					int y = deconv(xx,w).second;
					int d = tp.second;
					max = std::max(d,max);
					for(int dx=-1;dx<=1;dx++) {
						for(int dy=-1;dy<=1;dy++) {
							if(dx*dy==0) {
								if(dx==0 && dy==0) continue;
								if(x+dx<0 || x+dx>=h) continue;
								if(y+dy<0 || y+dy>=w) continue;
								if(g[x+dx][y+dy]=='#') continue;
								if(went[convert(x+dx,y+dy,w)]) continue;
								went[convert(x+dx,y+dy,w)]=true;
								que.emplace(convert(x+dx,y+dy,w),d+1);
							}
						}
					}
				}
			}
		}
	}
	print(max);
	return 0;
}
