#include <bits/stdc++.h>
using P = std::pair<int, int>;
int H, W;
const static int MAX_H = 20, MAX_W = 20;
bool maze[MAX_H][MAX_W];
int ans = 0;
int depth[MAX_H][MAX_W];
int x[4] = {-1, 0, 1, 0};
int y[4] = {0, -1, 0, 1};
bool has_been_visited[MAX_H][MAX_W];
bool is_inside_the_maze(int x, int y) {
  return x >= 0 && x < H && y >= 0 && y < W;
}
void Bfs(int start_x, int start_y) {
  for (int i = 0; i < H; ++i) {
    for (int j = 0; j < W; ++j) {
      has_been_visited[i][j] = false;
      depth[i][j] = 0;
    }
  }
  std::queue<P> next_vertex_to_visit;
  next_vertex_to_visit.push(std::make_pair(start_x, start_y));
  has_been_visited[start_x][start_y] = true;
  while (!next_vertex_to_visit.empty()) {
    P u = next_vertex_to_visit.front();
    next_vertex_to_visit.pop();
    for (int i = 0; i < 4; ++i) {
      int next_x = u.first + x[i], next_y = u.second + y[i];
      if (is_inside_the_maze(next_x, next_y) && maze[next_x][next_y] &&
          !has_been_visited[next_x][next_y]) {
        has_been_visited[next_x][next_y] = true;
        depth[next_x][next_y] = depth[u.first][u.second] + 1;
        if (depth[next_x][next_y] > ans) ans = depth[next_x][next_y];
        next_vertex_to_visit.push(std::make_pair(next_x, next_y));
      }
    }
  }
}
int main() {
  scanf("%d %d", &H, &W);
  for (int i = 0; i < H; ++i) {
    fflush(stdin);
    for (int j = 0; j < W; ++j) {
      char tmp;
      scanf("%c", &tmp);
      maze[i][j] = tmp == '.';
    }
  }
  for (int k = 0; k < H; ++k) {
    for (int l = 0; l < W; ++l) {
      if (maze[k][l]) Bfs(k, l);
    }
  }
  printf("%d\n", ans);
  return 0;
}
