#include <bits/stdc++.h>
#pragma GCC optimize("O2")
using namespace std;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
inline long long add(long long a, long long b, long long m) {
  return (((a % m + b % m) % m + m) % m);
}
inline long long mul(long long a, long long b, long long m) {
  return (((a % m * b % m) % m + m) % m);
}
const double EPS = 1e-6;
const long long MOD = 1e9 + 7;
template <typename T, typename U>
ostream &operator<<(ostream &out, const pair<T, U> &p) {
  out << '[' << p.first << ", " << p.second << ']';
  return out;
}
template <template <typename, typename...> class ContainerType,
          typename ValueType, typename... Args>
void print_container(const ContainerType<ValueType, Args...> &c) {
  cout << "{ ";
  for (const auto &v : c) cout << v << ' ';
  cout << '}' << '\n';
}
const int N = 21;
string s[N];
map<pair<int, int>, int> vertex;
vector<vector<int>> g(N, vector<int>());
int cnt = 1, h, w;
bool in_bound(int i, int j) {
  return (i >= 0 && i < h && j >= 0 && j < w && s[i][j] == '.');
}
void make_edges(int i, int j) {
  int x = i - 1, y = j;
  if (in_bound(x, y)) g[vertex[{i, j}]].push_back(vertex[{x, y}]);
  x = i + 1, y = j;
  if (in_bound(x, y)) g[vertex[{i, j}]].push_back(vertex[{x, y}]);
  x = i, y = j + 1;
  if (in_bound(x, y)) g[vertex[{i, j}]].push_back(vertex[{x, y}]);
  x = i, y = j - 1;
  if (in_bound(x, y)) g[vertex[{i, j}]].push_back(vertex[{x, y}]);
  return;
}
pair<int, pair<int, int>> f(int src) {
  pair<int, pair<int, int>> ans;
  ans.first = 0;
  ans.second.first = src;
  ans.second.second = -1;
  vector<int> dist(cnt + 1, 1e9), visited(cnt + 1, 0);
  priority_queue<pair<int, int>, vector<pair<int, int>>,
                 greater<pair<int, int>>>
      Q;
  dist[src] = 0;
  Q.push({0, src});
  while ((long long)(Q).size()) {
    auto itr = Q.top();
    Q.pop();
    int ii = itr.second;
    visited[ii] = 1;
    int l = itr.first;
    for (auto jj : g[ii]) {
      if (!visited[jj] && l + 1 < dist[jj]) {
        dist[jj] = l + 1;
        Q.push({dist[jj], jj});
      }
    }
  }
  int mx = -1, v = -1;
  for (int i = 1; i < cnt; i++) {
    if (i != src && dist[i] > mx) {
      mx = dist[i];
      v = i;
    }
  }
  ans.first = mx;
  ans.second.second = v;
  return ans;
}
void solve() {
  cin >> h >> w;
  for (int i = 0; i < h; i++) cin >> s[i];
  for (int i = 0; i < h; i++)
    for (int j = 0; j < w; j++)
      if (s[i][j] == '.') vertex[{i, j}] = cnt++;
  for (int i = 0; i < h; i++)
    for (int j = 0; j < w; j++)
      if (s[i][j] == '.') make_edges(i, j);
  int ans = 0;
  for (int i = 0; i < h; i++) {
    for (int j = 0; j < w; j++) {
      if (s[i][j] == '.') {
        auto itr = f(vertex[{i, j}]);
        ans = max(ans, itr.first);
      }
    }
  }
  cout << ans << '\n';
  return;
}
int main() {
  ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  clock_t start, stop;
  int t = 1;
  for (int tc = 1; tc < t + 1; tc++) solve();
  return 0;
}
