#include <bits/stdc++.h>
using namespace std;
template <class T>
inline bool checkMin(T& a, T b) {
  return (a > b ? a = b, 1 : 0);
}
template <class T>
inline bool checkMax(T& a, T b) {
  return (a < b ? a = b, 1 : 0);
}
class Scanner {
 private:
  istream& ist;

 public:
  Scanner(istream& in) : ist(in) {}
  string next() {
    string r;
    ist >> r;
    return r;
  }
  string nextLine() {
    string r;
    getline(ist, r);
    return r;
  }
  int nextInt() {
    int r;
    ist >> r;
    return r;
  }
  double nextDouble() {
    double r;
    ist >> r;
    return r;
  }
};
Scanner sc(cin);
const int INF = 0x3f3f3f3f;
const int N = 22;
char maze[N][N];
int n, m;
int d[N * N][N * N];
void init() {
  scanf("%d%d", &n, &m);
  for (int i = 0; i < n; i++) scanf("%s", maze[i]);
}
const int goes[4][2] = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};
void solve() {
  memset(d, INF, sizeof(d));
  for (int i = 0; i < n; i++)
    for (int j = 0; j < m; j++) {
      if (maze[i][j] == '#') continue;
      for (int r = 0; r < 4; r++) {
        int ux = i + goes[r][0];
        int uy = j + goes[r][1];
        if (ux < 0 || ux >= n || uy < 0 || uy >= m) continue;
        if (maze[ux][uy] == '#') continue;
        d[i * m + j][ux * m + uy] = d[ux * m + uy][i * m + j] = 1;
      }
    }
  for (int i = 0; i < n * m; i++)
    for (int j = 0; j < n * m; j++) {
      ;
      ;
      ;
    }
  for (int r = 0; r < N * N; r++)
    for (int u = 0; u < N * N; u++)
      for (int v = 0; v < N * N; v++) checkMin(d[u][v], d[u][r] + d[r][v]);
  for (int i = 0; i < n * m; i++)
    for (int j = 0; j < n * m; j++) {
      ;
      ;
      ;
    }
  int ans = 0;
  for (int i = 0; i < N * N; i++)
    for (int j = 0; j < N * N; j++)
      if (d[i][j] != INF) checkMax(ans, d[i][j]);
  printf("%d\n", ans);
}
int main() {
  init();
  solve();
  return 0;
}
