#include <bits/stdc++.h>
using namespace std;
template <typename T>
using V = vector<T>;
using VL = V<long long>;
using VVL = V<VL>;
template <typename T, typename U>
using P = pair<T, U>;
using PL = P<long long, long long>;
using VPL = V<PL>;
template <typename T>
inline bool chmax(T& a, T b);
template <typename T>
inline bool chmin(T& a, T b);
void print_ints(vector<long long> v);
template <typename T>
void drop(T a);
const long long INF = 1e18;
long long H, W;
V<string> mat;
VPL directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
long long get_max(long long h, long long w) {
  if (mat[h][w] == '#') return 0;
  VVL visited(H, VL(W));
  VPL q;
  q.push_back({h, w});
  visited[h][w] = 1;
  long long res = 0;
  while (q.size() > 0) {
    VPL nq(0);
    for (auto pa : q) {
      long long ph = pa.first;
      long long pw = pa.second;
      for (auto d : directions) {
        long long nh = ph + d.first;
        long long nw = pw + d.second;
        if (!(0 <= nh && nh < H && 0 <= nw && nw < W)) continue;
        if (!(mat[nh][nw] == '.')) continue;
        if (visited[nh][nw]) continue;
        visited[nh][nw] = 1;
        nq.push_back({nh, nw});
      }
    }
    res++;
    q = nq;
  }
  res--;
  return res;
}
void solve() {
  cin >> H >> W;
  mat = V<string>(H);
  for (long long i = 0; i < (H); ++i) {
    cin >> mat[i];
  }
  long long res = 0;
  for (long long h = 0; h < (H); ++h)
    for (long long w = 0; w < (W); ++w) chmax(res, get_max(h, w));
  cout << res << endl;
}
VL dx = {1, 0, -1, 0};
VL dy = {0, 1, 0, -1};
void solve2() {
  cin >> H >> W;
  mat = V<string>(H);
  for (long long i = 0; i < (H); ++i) {
    cin >> mat[i];
  }
  VVL edge_mat(H * W, VL(H * W));
  auto id = [&](long long h, long long w) { return h * W + w; };
  for (long long h = 0; h < (H); ++h)
    for (long long w = 0; w < (W); ++w) {
      if (mat[h][w] == '#') continue;
      for (long long i = 0; i < (4); ++i) {
        long long nh = h + dy[i];
        long long nw = w + dx[i];
        if (!(0 <= nh && nh < H && 0 <= nw && nw < W)) continue;
        if (!(mat[nh][nw] == '.')) continue;
        edge_mat[id(h, w)][id(nh, nw)] = 1;
      }
    }
  VVL ds(H * W, VL(H * W));
  for (long long i = 0; i < (H * W); ++i)
    for (long long j = 0; j < (H * W); ++j) {
      if (edge_mat[i][j]) {
        ds[i][j] = 1;
      } else {
        ds[i][j] = INF;
      }
    }
  for (long long k = 0; k < (H * W); ++k)
    for (long long i = 0; i < (H * W); ++i)
      for (long long j = 0; j < (H * W); ++j) {
        ds[i][j] = min(ds[i][j], ds[i][k] + ds[k][j]);
      }
  long long res = 0;
  for (long long i = 0; i < (H * W); ++i)
    for (long long j = 0; j < (H * W); ++j)
      if (ds[i][j] != INF) chmax(res, ds[i][j]);
  cout << res << endl;
}
struct exit_exception : public std::exception {
  const char* what() const throw() { return "Exited"; }
};
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  try {
    solve2();
  } catch (exit_exception& e) {
  }
  return 0;
}
template <typename T>
inline bool chmax(T& a, T b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
template <typename T>
inline bool chmin(T& a, T b) {
  if (a > b) {
    a = b;
    return 1;
  }
  return 0;
}
void print_ints(vector<long long> v) {
  for (long long i = 0; i < (v.size()); ++i) {
    if (i > 0) {
      cout << " ";
    }
    cout << v[i];
  }
  cout << endl;
}
template <typename T>
void drop(T res) {
  cout << res << endl;
  throw exit_exception();
}
