#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using P = pair<ll,ll>;
#define REP(i, n) for (ll i = 0; i < (int)(n); i++)
#define RREP(i, n) for (ll i = (int)(n)-1; i > -1 ; i--)
#define IN(T, x) T x;cin >> x;
#define AIN(T, a, n) vector<T> a(n);REP(i, n){cin >> a[i];}
#define A2IN(T1, a, T2, b, n) vector<T1> a(n);vector<T2> b(n);REP(i, n){cin >> a[i] >> b[i];}
#define ALL(a) (a).begin(),(a).end()
#define SORT(a) sort(ALL(a))
#define RSORT(a) SORT(a);reverse(ALL(a))
template<class T>bool chmax(T &a,const T &b){if(a<b){a=b;return 1;}return 0;}
template<class T>bool chmin(T &a,const T &b){if(b<a){a=b;return 1;}return 0;}
#define OUT(x) cout << x << endl
#define BOUT(b) if(b){OUT("Yes");}else{OUT("No");}
const ll MOD = 100000007;
const ll INF = 10e9;
vector<ll> dx = {1, 0, -1, 0};
vector<ll> dy = {0, 1, 0, -1};

int main() {
  IN(ll, H);
  IN(ll ,W);
  AIN(string, maze, H);
  ll ans = 0;
  vector<vector<ll>> d(H,vector<ll>(W,INF));
  queue<P> que;
  REP(i,H){
    REP(j, W){
      if(d.at(i).at(j) == INF)
        continue;
      vector<vector<ll>> d2= d
      que.push(P(i,j));
      d2.at(i).at(j) = 0;
      while(que.size()){
        P p = que.front();
        que.pop();
        REP(k,4){
          ll ny = p.first + dy.at(k);
          ll nx = p.second + dx.at(k);
          if(0 <= ny && ny < H && 0 <= nx && nx < W && maze.at(ny).at(nx) != '#' && d.at(ny).at(nx) == INF){
            que.push(P(ny,nx));
            d2.at(ny).at(nx) = d2.at(p.first).at(p.second) + 1;
            chmax(ans,d2.at(ny).at(nx));
          }
        }
      }
    }
  }
  OUT(ans);
}

