#include <bits/stdc++.h>
const int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
const int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};
const int dr[4] = {-1, 0, 1, 0};
const int dc[4] = {0, 1, 0, -1};
const int INF = 1e9;
int gcd(int a, int b) {
  if (a % b == 0) {
    return b;
  } else {
    return (gcd(b, a % b));
  }
}
int lcm(int a, int b) {
  int x = gcd(a, b);
  return (a * b / x);
}
using namespace std;
int H, W;
string grid[21][21];
int bfs(int bx, int by, int mx, int my) {
  string grid2[21][21];
  for (int i = (int)(0); i < (int)(H + 2); ++i) {
    for (int j = (int)(0); j < (int)(W + 2); ++j) {
      grid2[i][j] = grid[i][j];
    }
  }
  int han[25][25];
  for (int i = (int)(0); i < (int)(21); ++i) {
    for (int j = (int)(0); j < (int)(21); ++j) {
      han[i][j] = INF;
    }
  }
  queue<int> Q;
  Q.push(bx);
  Q.push(by);
  han[by][bx] = 0;
  while (!Q.empty()) {
    int x = Q.front();
    Q.pop();
    int y = Q.front();
    Q.pop();
    for (int i = (int)(0); i < (int)(4); ++i) {
      int nx = x + dr[i];
      int ny = y + dc[i];
      if (grid2[ny][nx] == "." && han[ny][nx] == INF) {
        han[ny][nx] = han[y][x] + 1;
        Q.push(nx);
        Q.push(ny);
        if (nx == mx && ny == my) {
          return han[ny][nx];
        }
      }
    }
  }
}
int main() {
  cin >> H >> W;
  for (int i = (int)(0); i < (int)(H + 2); ++i) {
    for (int j = (int)(0); j < (int)(W + 2); ++j) {
      if (i == 0 || j == 0 || i == H + 1 || j == W + 1) {
        grid[i][j] = '!';
      } else {
        char a;
        cin >> a;
        grid[i][j] = a;
      }
    }
  }
  int ans = 0;
  for (int i = (int)(0); i < (int)(H + 2); ++i) {
    for (int j = (int)(0); j < (int)(W + 2); ++j) {
      if (grid[i][j] == ".") {
        for (int k = (int)(0); k < (int)(H + 2); ++k) {
          for (int l = (int)(0); l < (int)(W + 2); ++l) {
            if (k != i && l != j && grid[k][l] == ".") {
              ans = max(ans, bfs(j, i, l, k));
            }
          }
        }
      }
    }
  }
  cout << ans << endl;
}
