#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define FOR(var, begin, end) for (int var = (begin); var <= (end); var++)
#define RFOR(var, begin, end) for (int var = (begin); var >= (end); var--)
#define REP(var, length) FOR(var, 0, length - 1)
#define RREP(var, length) RFOR(var, length - 1, 0)
#define EACH(value, var) for (auto value : var)
#define SORT(var) sort(var.begin(), var.end())
#define REVERSE(var) reverse(var.begin(), var.end())
#define RSORT(var) SORT(var); REVERSE(var)
#define OPTIMIZE_STDIO ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed
#define endl '\n'

const ll MOD = 1e9 + 7;
struct mint {
    ll x;
    mint() : x(0) {}
    mint(ll x) : x((x % MOD + MOD) % MOD) {}
    mint& operator+=(const mint& r) { if ((x += r.x) >= MOD) { x -= MOD; } return *this; }
    mint& operator-=(const mint& r) { if ((x -= r.x) < 0) { x += MOD; } return *this; }
    mint& operator*=(const mint& r) { if ((x *= r.x) > MOD) { x %= MOD; } return *this; }
    mint& operator++() { if ((++x) >= MOD) { x -= MOD; } return *this; }
    mint operator++(int) { mint ret = x; if ((++x) >= MOD) { x-= MOD; } return ret; }
    mint& operator--() { if ((--x) < 0) { x += MOD; } return *this; }
    mint operator--(int) { mint ret = x; if ((--x) < 0) { x += MOD; } return ret; }
    mint operator+(const mint& r) { mint ret; return ret = x + r.x; }
    mint operator-(const mint& r) { mint ret; return ret = x - r.x; }
    mint operator*(const mint& r) { mint ret; return ret = x * r.x; }
    mint operator-() { return mint() - *this; }
    bool operator<(const mint& a) { return x < a.x; }
    bool operator>(const mint& a) { return x > a.x; }
    bool operator<=(const mint& a) { return x <= a.x; }
    bool operator>=(const mint& a) { return x >= a.x; }
    bool operator==(const mint& a) { return x == a.x; }
    bool operator!=(const mint& a) { return x != a.x; }
};
ostream& operator<<(ostream& os, const mint& r) { os << r.x; return os; }
ostream& operator>>(ostream& os, const mint& r) { os >> r.x; return os; }
// left, up, right, down
const int di[4] = {-1,0,1,0};
const int dj[4] = {0,1,0,-1};

void solve(istream& cin, ostream& cout) {
  int H, W;
  cin >> H >> W;
  vector<string> s(H);
  int ans = 0;
  REP(i, H) cin >> s[i];
  REP(si, H) REP (sj, W) {
      if (s[si][sj] == '#') continue;
      vector<vector<int>> dist(H, vector<int>(W, MOD));
      queue<pair<int, int>> q;
      auto update = [&](int i, int j, int x) {
        if (dist[i][j] != MOD) return;
        dist[i][j] = x;
        q.push(pair<int, int>(i, j));
      };
      // start
      update(si, sj, 0);
      // BFS
      while (!q.empty()) {
        int i = q.front().first;
        int j = q.front().second;
        q.pop();
        REP(dir, 4) {
          int ni = i + di[dir];
          int nj = j + dj[dir];
          if (ni < 0 || ni >= H || nj < 0 || nj >= W) continue;
          if (s[ni][nj] == '#') continue;
          update(ni, nj, dist[i][j]+1);
        }
      }
      REP(i, H) REP(j, W) {
        if (dist[i][j] == MOD) continue;
        ans = max(ans, dist[i][j]);
      }
  }
  cout << ans << endl;
}

#ifndef TEST
int main() {
  OPTIMIZE_STDIO;
  solve(cin, cout);
}
#endif


Measured memory_bytes: 256