#include <bits/stdc++.h>
using namespace std;
long long MOD = 1000000007;
const long long INF = (1ll << 60);
template <class T>
bool umax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}
template <class T>
bool umin(T &a, const T &b) {
  if (b < a) {
    a = b;
    return true;
  }
  return false;
}
template <typename T>
T gcd(T a, T b) {
  if (a == 0) return b;
  return gcd(b % a, a);
}
int findGCD(vector<int> arr) {
  int result = arr[0];
  for (auto a : arr) {
    result = gcd(a, result);
  }
  return result;
}
template <typename T>
T lcm(T m, T n) {
  if ((0 == m) || (0 == n)) return 0;
  return ((m / gcd(m, n)) * n);
}
template <typename A, size_t N, typename T>
void Fill(A (&array)[N], const T &val) {
  fill((T *)array, (T *)(array + N), val);
}
long long euler_phi(long long n) {
  long long ret = n;
  for (long long i = 2; i * i <= n; i++) {
    if (n % i == 0) {
      ret -= ret / i;
      while (n % i == 0) n /= i;
    }
  }
  if (n > 1) ret -= ret / n;
  return ret;
}
string S[30];
int H, W;
int dx[5] = {1, 0, -1, 0};
int dy[5] = {0, 1, 0, -1};
int bfs(int startH, int startW) {
  int visited[21][21];
  int shortest_path[21][21];
  Fill(visited, false);
  Fill(shortest_path, (1 << 30));
  shortest_path[startH][startW] = 0;
  queue<pair<int, int>> q;
  q.push(pair<int, int>(startH, startW));
  shortest_path[startH][startW] = 0;
  visited[startH][startW] = true;
  while (!q.empty()) {
    int nowh = q.front().first;
    int noww = q.front().second;
    q.pop();
    for (int i = 0; i < 4; i++) {
      if (nowh + dx[i] >= H || nowh + dx[i] < 0 || noww + dy[i] >= W ||
          dy[i] + noww < 0) {
        continue;
      }
      if (S[nowh + dx[i]][noww + dy[i]] == '#') {
        continue;
      }
      if (S[nowh + dx[i]][noww + dy[i]] == '.' &&
          !visited[nowh + dx[i]][noww + dy[i]]) {
        shortest_path[nowh + dx[i]][noww + dy[i]] =
            shortest_path[nowh][noww] + 1;
        q.push(pair<int, int>(nowh + dx[i], noww + dy[i]));
        visited[nowh + dx[i]][noww + dy[i]] = true;
      }
    }
  }
  int maximum = 0;
  for (int i = 0; i < H; i++) {
    for (int j = 0; j < W; j++) {
      if (S[i][j] == '.') {
        maximum = max(maximum, shortest_path[i][j]);
      }
    }
  }
  return maximum;
}
int main() {
  cin >> H >> W;
  for (int i = 0; i < (int)(H); i++) {
    cin >> S[i];
  }
  int maximum = 0;
  for (int i = 0; i < H; i++) {
    for (int j = 0; j < W; j++) {
      maximum = max(maximum, bfs(i, j));
    }
  }
  cout << maximum << endl;
  return 0;
}
