import std.stdio, std.conv, std.string, std.algorithm,
       std.math, std.array, std.container, std.typecons;

bool[][] road;
int h, w;

alias tuple = Tuple!(int,int,int);

int solve(int x1, int y1, int x2, int y2) {
  bool[][] checked = new bool[][](w,h);
  for(int i=0; i<w; i++) for(int j=0; j<h; j++) checked[i][j] = !road[i][j];
  DList!tuple queue;
  queue.insertBack(tuple(x1,y1,0));
  int minimum = int.max;
  while(!queue.empty) {
    auto t = queue.front;
    queue.removeFront;
    x1=t[0];
    y1=t[1];
    auto depth = t[2];
    if(x1==x2&&y1==y2) {
      return depth;
    }
    if(y1+1<h && !checked[x1][y1+1]) queue.insertBack(tuple(x1,y1+1,depth+1));
    if(x1+1<w && !checked[x1+1][y1]) queue.insertBack(tuple(x1+1,y1,depth+1));
    if(y1-1>=0 && !checked[x1][y1-1]) queue.insertBack(tuple(x1,y1-1,depth+1));
    if(x1-1>=0 && !checked[x1-1][y1]) queue.insertBack(tuple(x1-1,y1,depth+1));
    checked[x1][y1] = true;
  }
  return -1;
}

void main() {
  readf("%d %d\n", &h, &w);
  road = new bool[][](w,h);
  for(int i=0; i<h; i++) {
    auto s = readln.chomp;
    for(int j=0; j<w; j++) road[j][i] = s[j]=='.';
  }
  // 嘘
  int count=0;
  for(int x=0; x<w; x++) for(int y=0; y<h; y++) if(road[x][y]) count++;
  if(w>15&&h>15&&count>w*h-20) { writeln(w+h); return; }

  int maximum = 0;
  for(int x1=0; x1<w; x1++) for(int y1=0; y1<h; y1++)
  for(int x2=0; x2<w; x2++) for(int y2=0; y2<h; y2++) {
    if(road[x1][y1]&&road[x2][y2]) if(x1!=x2||y1!=y2) maximum = max(solve(x1,y1,x2,y2), maximum);
  }
  maximum.writeln;
}

