#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <cmath>
#include <algorithm>
#include <iomanip>
 
using namespace std;
#define LOCAL  1
#define UPLOAD 2
#define ll long long
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
template <class T = long long> T input(){T x;cin >> x;return x;}
template <class T> void output(T x){cout << x << endl;}
#define debug(x) cerr << #x<< ": " << x<< '\n';
#define debugBit(x,n) cerr << #x<< ": " << std::bitset<n>(x) << '\n';
 
struct Vec2{
  Vec2(int x, int y){
    this->x = x;
    this->y = y;
  }
  int x;
  int y;
  Vec2 operator +(Vec2 other){
    return Vec2(this->x + other.x, this->y+other.y);
  }
};
 
void showMaze(vector<vector<int>> course){
  for(auto iter:course){
    for(auto iter2:iter){
      cout << iter2 << "    ";
    }
    cout << endl;
  }
  cout << endl;
}
 
vector<vector<int>> course;
long saitankyori(Vec2 start){
  for(auto iter:{Vec2(-1,0),Vec2(1,0), Vec2(0,-1), Vec2(0,1)}){
    Vec2 targetVec = start + iter;
    if(targetVec.x >= 0 && targetVec.x < course.size() && targetVec.y >= 0 && targetVec.y < course[0].size()){
      course[targetVec.x][targetVec.y] = min(course[start.x][start.y] + 1, course[targetVec.x][targetVec.y]);
      if(course[targetVec.x][targetVec.y] > course[start.x][start.y] && course[targetVec.x][targetVec.y] > 0){
        saitankyori(targetVec);
      }
    }
  }
 
  return 0;
}
int getMax(vector<vector<int>> c){
  int ret = 0;
  for(auto iter:c){
    for(auto iter2:iter){
      ret = max(ret, iter2);
    }
  }
  return ret;
}
 
int main()
{
#if ENVIRONMENT == LOCAL
    std::ifstream in("input.txt");
    std::cin.rdbuf(in.rdbuf());
#endif
 
  int H = input(); 
  int W = input(); 
 
  vector<vector<int>> course_temp;
  for(int i=0;i<H;i++){
    vector<int> temp;
    string s = input<string>();
    for(int j=0;j<W;j++){
      if(s.substr(j,1) == "."){
        temp.push_back(100);
      }
      else{
        temp.push_back(-1);
      }
    } 
    course_temp.push_back(temp);
  }
 
  int answer = 0;
  for(int xs=0;xs<H;xs++){
    for(int ys=0;ys<W;ys++){  
      if(course_temp[xs][ys] == -1)continue;
 
      course = course_temp;
      course[xs][ys] = 0;
      saitankyori(Vec2(xs,ys));
 
      answer = max(answer, getMax(course));
    }
  }
 
  output(answer);
 
  return 0;
}z