#include <bits/stdc++.h>
using namespace std;
long long modpow(long long a, long long n, long long mod) {
  long long res = 1;
  while (n > 0) {
    if (n & 1) res = res * a % mod;
    a = a * a % mod;
    n >>= 1;
  }
  return res;
}
const int MAX = 510000;
long long fac[MAX], finv[MAX], inv[MAX];
long long modinv(long long a, long long mod) {
  long long b = mod, u = 1, v = 0;
  while (b) {
    long long t = a / b;
    a -= t * b;
    swap(a, b);
    u -= t * v;
    swap(u, v);
  }
  u %= mod;
  if (u < 0) u += mod;
  return u;
}
void COMinit() {
  fac[0] = fac[1] = 1;
  finv[0] = finv[1] = 1;
  inv[1] = 1;
  for (int i = 2; i < MAX; i++) {
    fac[i] = fac[i - 1] * i % (1000000007);
    inv[i] = (1000000007) -
             inv[(1000000007) % i] * ((1000000007) / i) % (1000000007);
    finv[i] = finv[i - 1] * inv[i] % (1000000007);
  }
}
long long COM(long long n, long long k) {
  if (n < k) return 0;
  if (n < 0 || k < 0) return 0;
  return fac[n] * (finv[k] * finv[n - k] % (1000000007)) % (1000000007);
}
long long mod(long long val, long long m) {
  long long res = val % m;
  if (res < 0) res += m;
  return res;
}
void push_el(queue<tuple<int, int, int>> &q, vector<vector<char>> &v,
             vector<vector<int>> &seen, int next_h, int next_w, int next_dist,
             int h, int w) {
  if (next_h < 0 || next_h >= h || next_w < 0 || next_w >= w) return;
  if (seen[next_h][next_w] == true) return;
  if (v[next_h][next_w] != '.') return;
  q.push(make_tuple(next_h, next_w, next_dist));
}
int solve(vector<vector<char>> &v, int start_h, int start_w, int end_h,
          int end_w) {
  queue<tuple<int, int, int>> q;
  vector<vector<int>> seen(v.size(), vector<int>(v[0].size(), false));
  q.push(make_tuple(start_h, start_w, 0));
  while (q.size() >= 1) {
    tuple<int, int, int> t = q.front();
    q.pop();
    int curr_h = get<0>(t);
    int curr_w = get<1>(t);
    int curr_dist = get<2>(t);
    seen[curr_h][curr_w] = true;
    if (curr_h == end_h && curr_w == end_w) return curr_dist;
    push_el(q, v, seen, curr_h, curr_w + 1, curr_dist + 1, v.size(),
            v[0].size());
    push_el(q, v, seen, curr_h, curr_w - 1, curr_dist + 1, v.size(),
            v[0].size());
    push_el(q, v, seen, curr_h + 1, curr_w, curr_dist + 1, v.size(),
            v[0].size());
    push_el(q, v, seen, curr_h - 1, curr_w, curr_dist + 1, v.size(),
            v[0].size());
  }
  return -1;
}
int main() {
  int H, W;
  cin >> H >> W;
  vector<vector<char>> v(H, vector<char>(W));
  for (int j = 0; j < H; j++) {
    for (int i = 0; i < W; i++) {
      cin >> v[j][i];
    }
  }
  int max_dist = 0;
  for (int start_h = 0; start_h < H; start_h++) {
    for (int start_w = 0; start_w < W; start_w++) {
      for (int end_h = 0; end_h < H; end_h++) {
        for (int end_w = 0; end_w < W; end_w++) {
          max_dist = max(max_dist, solve(v, start_h, start_w, end_h, end_w));
        }
      }
    }
  }
  cout << max_dist << endl;
  return 0;
}
