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

template<class T> T read() {
	T t;
	cin >> t;
	return t;
}

template<class T> vector<T> read_vector(sint const n) {
	vector<T> vs;
	for (sint i = 0; i < n; ++i) {
		vs.push_back(read<T>());
	}
	return vs;
}

inline void write() {
}

template<class T> void write(T const& t) {
	cout << t;
}

template<class T> void write(vector<T> const& ts) {
	if (ts.size() > 0) {
		cout << ts[0];
	}
	for (size_t i = 1; i < ts.size(); ++i) {
		cout << ' ' << ts[i];
	}
}

template<class T, class... Args> void write(T const& t, Args const&... args) {
	cout << t << ' ';
	write(args...);
}

template<class... Args> void writeln(Args const&... args) {
	write(args...);
	cout << '\n';
}

inline sint gcd(sint y, sint x) {
	while (x != 0) {
		sint const t = y % x;
		y = x;
		x = t;
	}
	return y;
}

inline sint pow_mod(sint const a, sint const n, sint const p) {
	if (n == 0) {
		return 1;
	}
	sint const h = pow_mod(a, n / 2, p);
	sint const f = (h * h) % p;
	if (n % 2 == 1) {
		return (a * f) % p;
	}
	else {
		return f;
	}
}

inline sint rcp_mod(sint const a, sint const p) {
	assert(a % p != 0);
	return pow_mod(a, p - 2, p);
}

int main() {
	ios_base::sync_with_stdio(false);
	cin .exceptions(ios_base::badbit | ios_base::failbit);
	cout.exceptions(ios_base::badbit | ios_base::failbit);
	cin .tie(nullptr);
	cout.tie(nullptr);
	cout.precision(16);
	void run();
	run();
	return 0;
}

struct Node {
	sint x, y;
	sint distance;
};

bool operator<(Node const& lhs, Node const& rhs) {
	return lhs.distance < rhs.distance;
}

void writeln(vector<vector<sint>> const& d) {
	for (sint i = 0; i < sint(d.size()); ++i) {
		for (sint j = 0; j < sint(d.size()); ++j) {
			cout << ' ' << d[i][j];
		}
		cout << endl;
	}
}

void solve(vector<vector<bool>> const& maze, vector<vector<sint>>& distance, sint si, sint sj) {
	priority_queue<Node> q;
	q.push({si, sj, 0});
	distance[si][sj] = 0;

	while(!q.empty()) {
		Node n = q.top();
		q.pop();
		sint d = 1 + distance[n.x][n.y];
		if (maze[n.x - 1][n.y]) {
			if (distance[n.x - 1][n.y] > d) {
				distance[n.x - 1][n.y] = d;
				q.push({n.x - 1, n.y, d});
			}
		}
		if (maze[n.x + 1][n.y]) {
			if (distance[n.x + 1][n.y] > d) {
				distance[n.x + 1][n.y] = d;
				q.push({n.x + 1, n.y, d});
			}
		}
		if (maze[n.x][n.y - 1]) {
			if (distance[n.x][n.y - 1] > d) {
				distance[n.x][n.y - 1] = d;
				q.push({n.x, n.y - 1, d});
			}
		}
		if (maze[n.x][n.y + 1]) {
			if (distance[n.x][n.y + 1] > d) {
				distance[n.x][n.y + 1] = d;
				q.push({n.x, n.y + 1, d});
			}
		}
	}
}

sint max_distance(vector<vector<bool>> const& maze, vector<vector<sint>> const& distance, sint H, sint W) {
	sint d_max = 0;
	for (sint i = 1; i < H + 1; ++i) {
		for (sint j = 1; j < W + 1; ++j) {
			if (maze[i][j]) {
				d_max = max(d_max, distance[i][j]);
			}
		}
	}
	return d_max;
}

void run() {
	auto const H = read<sint>();
	auto const W = read<sint>();
	vector<vector<bool>> maze(H + 2, vector<bool>(W + 2, false));
	for (sint i = 1; i < H + 1; ++i) {
		for (sint j = 1; j < W + 1; ++j) {
			maze[i][j] = read<char>() == '.';
		}
	}

	sint d_max = -1;
	for (sint i = 1; i < H + 1; ++i) {
		for (sint j = 1; j < W + 1; ++j) {
			if (!maze[i][j]) {
				continue;
			}
			vector<vector<sint>> distance(H + 2, vector<sint>(W + 2, 500 * 500));
			solve(maze, distance, i, j);
			d_max = max(d_max, max_distance(maze, distance, H, W));
		}
	}
	writeln(d_max);
}

Measured memory_bytes: 256