#include <bits/stdc++.h>
using namespace std;
const double PI = 3.141592653589793;
const long long MOD = 1e9 + 7;
const long long LLMAX = numeric_limits<long long>::max();
void No() { cout << "No" << endl; }
void Yes() { cout << "Yes" << endl; }
long long id(char c) { return c - 'a'; }
bool isOK(vector<long long>& a, long long k, long long index) {
  return a[index] < k * (index + 1);
}
long long binary_search(vector<long long>& a, long long k) {
  long long left = -1;
  long long right = (long long)a.size();
  while (right - left > 1) {
    long long mid = left + (right - left) / 2;
    if (isOK(a, k, mid))
      right = mid;
    else
      left = mid;
  }
  return right;
}
template <class t, class u>
ostream& operator<<(ostream& os, const pair<t, u>& p) {
  return os << "{" << p.first << "," << p.second << "}";
}
template <class t>
ostream& operator<<(ostream& os, const vector<t>& v) {
  os << "{";
  for (auto e : v) os << e << ",";
  return os << "}";
}
bool eq(vector<long long> P, vector<long long> Q) {
  for (long long i = 0; i < P.size(); i++) {
    if (P[i] != Q[i]) {
      return false;
    }
  }
  return true;
}
long long gcd(long long a, long long b) {
  if (a % b == 0) {
    return (b);
  } else {
    return (gcd(b, a % b));
  }
}
long long lcm(long long a, long long b) { return a * b / gcd(a, b); }
long long modinv(long long a, long long m) {
  long long b = m, u = 1, v = 0;
  while (b) {
    long long t = a / b;
    a -= t * b;
    swap(a, b);
    u -= t * v;
    swap(u, v);
  }
  u %= m;
  if (u < 0) u += m;
  return u;
}
long long H, W;
bool inrange(long long h, long long w) {
  if (h < 0 || h >= H || w < 0 || w >= W) {
    return false;
  }
  return true;
}
long long toS(long long h, long long w) { return h * W + w; }
int main() {
  cin >> H >> W;
  long long S = H * W;
  vector<long long> F(S, false);
  for (long long h = 0; h < H; h++)
    for (long long w = 0; w < W; w++) {
      char c;
      cin >> c;
      bool f = c == '.';
      F[toS(h, w)] = f;
    }
  vector<vector<long long> > graph(S, vector<long long>(0));
  for (long long h = 0; h < H; h++)
    for (long long w = 0; w < W; w++) {
      long long dh = 0, dw = 0;
      long long s = toS(h, w);
      if (!F[s]) continue;
      for (dh = 0, dw = -1; dw <= 1; dw += 2) {
        if (!F[toS(h + dh, w + dw)]) continue;
        if (!inrange(h + dh, w + dw)) continue;
        graph[s].push_back(toS(h + dh, w + dw));
        graph[toS(h + dh, w + dw)].push_back(s);
      }
      for (dh = -1, dw = 0; dh <= 1; dh += 2) {
        if (!F[toS(h + dh, w + dw)]) continue;
        if (!inrange(h + dh, w + dw)) continue;
        graph[s].push_back(toS(h + dh, w + dw));
        graph[toS(h + dh, w + dw)].push_back(s);
      }
    }
  long long ans = 0;
  for (long long s = 0; s < S; s++) {
    if (!F[s]) continue;
    queue<long long> que;
    que.push(s);
    vector<long long> D(S, LLMAX);
    D[s] = 0;
    while (!que.empty()) {
      long long v = que.front();
      que.pop();
      for (auto nv : graph[v]) {
        if (D[nv] >= D[v] + 1) {
          D[nv] = D[v] + 1;
          que.push(nv);
        }
      }
    }
    for (long long i = 0; i < S; i++) {
      if (D[i] < LLMAX / 2) {
        if (ans < D[i]) {
          ans = D[i];
        }
      }
    }
  }
  cout << ans << endl;
  return 0;
}
