#include <bits/stdc++.h>
using namespace std;
struct Point {
  int x;
  int y;
};
struct queueNode {
  Point pt;
  int dist;
};
bool isValid(int row, int col) {
  return (row >= 0) && (row < 20) && (col >= 0) && (col < 20);
}
int rowNum[] = {-1, 0, 0, 1};
int colNum[] = {0, -1, 1, 0};
int BFS(int mat[][20], Point src, Point dest) {
  if (!mat[src.x][src.y] || !mat[dest.x][dest.y]) return -1;
  bool visited[20][20];
  memset(visited, false, sizeof visited);
  visited[src.x][src.y] = true;
  queue<queueNode> q;
  queueNode s = {src, 0};
  q.push(s);
  while (!q.empty()) {
    queueNode curr = q.front();
    Point pt = curr.pt;
    if (pt.x == dest.x && pt.y == dest.y) return curr.dist;
    q.pop();
    for (int i = 0; i < 4; i++) {
      int row = pt.x + rowNum[i];
      int col = pt.y + colNum[i];
      if (isValid(row, col) && mat[row][col] && !visited[row][col]) {
        visited[row][col] = true;
        queueNode Adjcell = {{row, col}, curr.dist + 1};
        q.push(Adjcell);
      }
    }
  }
  return -1;
}
int main() {
  int mat[20][20];
  memset(mat, 0, sizeof(mat));
  int r, c;
  cin >> r >> c;
  char cc;
  for (int i = 0; i < r; ++i) {
    for (int j = 0; j < c; ++j) {
      cin >> cc;
      if (cc == '.') {
        mat[i][j] = 1;
      } else {
        mat[i][j] = 0;
      }
    }
  }
  int max_ans = 0;
  for (int i = 0; i < r; ++i) {
    for (int j = 0; j < c; ++j) {
      for (int k = 0; k < r; ++k) {
        for (int m = 0; m < c; ++m) {
          if (i != k && j != m && mat[i][j] == 1 && mat[k][m] == 1) {
            Point source = {i, j};
            Point dest = {k, m};
            int dist = BFS(mat, source, dest);
            if (dist != INT_MAX && dist > max_ans) max_ans = dist;
          }
        }
      }
    }
  }
  cout << max_ans << endl;
  return 0;
}
