#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using Vi = vector<int>;
using Vl = vector<ll>;
using Pii = pair<int, int>;
using Pll = pair<ll, ll>;
constexpr int I_INF = (1 << 30);
constexpr ll L_INF = (1ll << 60);
template <typename _Ty>
struct Edge {
  int src, to;
  _Ty cost;
  constexpr Edge(int _to, _Ty _cost) noexcept : src(-1), to(_to), cost(_cost) {}
  constexpr Edge(int _src, int _to, _Ty _cost) noexcept
      : src(_src), to(_to), cost(_cost) {}
};
template <typename _Ty>
using WeightedGraph = std::vector<std::vector<Edge<_Ty>>>;
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  int H, W;
  cin >> H >> W;
  vector<vector<int>> S(H, vector<int>(W));
  for (int i = 0; i < H; ++i) {
    for (int j = 0; j < W; ++j) {
      char mas;
      cin >> mas;
      S[i][j] = (mas == '.') ? 1 : 0;
    }
  }
  vector<Vl> d(H * W, Vl(H * W, L_INF));
  for (int i = 0; i < H; ++i) {
    for (int j = 0; j < W; ++j) {
      int idx = i * W + j;
      if (S[i][j] != 1) {
        continue;
      }
      if (i - 1 >= 0 && S[i - 1][j] == 1) {
        d[idx][(i - 1) * W + j] = 1;
      }
      if (i + 1 < H && S[i + 1][j] == 1) {
        d[idx][(i + 1) * W + j] = 1;
      }
      if (j - 1 >= 0 && S[i][j - 1] == 1) {
        d[idx][i * W + j - 1] = 1;
      }
      if (j + 1 < W && S[i][j + 1] == 1) {
        d[idx][i * W + j + 1] = 1;
      }
    }
  }
  int len = H * W;
  for (int k = 0; k < len; ++k) {
    for (int i = 0; i < len; ++i) {
      for (int j = 0; j < len; ++j) {
        d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
      }
    }
  }
  ll ans = 0;
  for (int i = 0; i < len; ++i) {
    for (int j = 0; j < len; ++j) {
      if (d[i][j] == L_INF) {
        continue;
      }
      ans = max(ans, d[i][j]);
    }
  }
  cout << ans << endl;
  return 0;
}
