#include <bits/stdc++.h>
using namespace std;
const double PI = 3.141592653589793;
const long long MOD = 1e9 + 7;
const long long LLMAX = numeric_limits<long long>::max();
void No() { cout << "No" << endl; }
void Yes() { cout << "Yes" << endl; }
long long id(char c) { return c - 'a'; }
bool isOK(vector<long long>& a, long long k, long long index) {
  return a[index] < k * (index + 1);
}
long long binary_search(vector<long long>& a, long long k) {
  long long left = -1;
  long long right = (long long)a.size();
  while (right - left > 1) {
    long long mid = left + (right - left) / 2;
    if (isOK(a, k, mid))
      right = mid;
    else
      left = mid;
  }
  return right;
}
template <class t, class u>
ostream& operator<<(ostream& os, const pair<t, u>& p) {
  return os << "{" << p.first << "," << p.second << "}";
}
template <class t>
ostream& operator<<(ostream& os, const vector<t>& v) {
  os << "{";
  for (auto e : v) os << e << ",";
  return os << "}";
}
bool eq(vector<long long> P, vector<long long> Q) {
  for (long long i = 0; i < P.size(); i++) {
    if (P[i] != Q[i]) {
      return false;
    }
  }
  return true;
}
long long gcd(long long a, long long b) {
  if (a % b == 0) {
    return (b);
  } else {
    return (gcd(b, a % b));
  }
}
long long lcm(long long a, long long b) { return a * b / gcd(a, b); }
long long modinv(long long a, long long m) {
  long long b = m, u = 1, v = 0;
  while (b) {
    long long t = a / b;
    a -= t * b;
    swap(a, b);
    u -= t * v;
    swap(u, v);
  }
  u %= m;
  if (u < 0) u += m;
  return u;
}
long long H, W;
bool inrange(long long h, long long w) {
  if (h < 0 || h >= H || w < 0 || w >= W) {
    return false;
  }
  return true;
}
long long toS(long long h, long long w) { return h * W + w; }
void warshall_floyd(long long n, vector<vector<long long>>& d) {
  for (long long k = 0; k < n; k++)
    for (long long i = 0; i < n; i++)
      for (long long j = 0; j < n; j++) {
        d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
      }
}
int main() {
  cin >> H >> W;
  long long S = H * W;
  long long map[H][W];
  long long start;
  for (long long h = 0; h < H; h++) {
    for (long long w = 0; w < W; w++) {
      char c;
      cin >> c;
      map[h][w] = (c == '.');
      if (c == '.') {
        start = toS(h, w);
      }
    }
  }
  vector<vector<long long>> graph(S, vector<long long>(0));
  for (long long h = 0; h < H; h++) {
    for (long long w = 0; w < W; w++) {
      long long dh = 0;
      long long dw = 0;
      if (map[h][w] == false) {
        continue;
      }
      for (dw = 0, dh = -1; dh <= 1; dh += 2) {
        if (inrange(h + dh, w + dw) && map[h + dh][w + dw]) {
          graph[toS(h, w)].push_back(toS(h + dh, w + dw));
          graph[toS(h + dh, w + dw)].push_back(toS(h, w));
        }
      }
      for (dw = -1, dh = 0; dw <= 1; dw += 2) {
        if (inrange(h + dh, w + dw) && map[h + dh][w + dw]) {
          graph[toS(h, w)].push_back(toS(h + dh, w + dw));
          graph[toS(h + dh, w + dw)].push_back(toS(h, w));
        }
      }
    }
  }
  long long end;
  {
    vector<long long> D(S, LLMAX);
    D[start] = 0;
    priority_queue<pair<long long, long long>,
                   vector<pair<long long, long long>>,
                   greater<pair<long long, long long>>>
        que;
    que.push(make_pair(0, start));
    while (que.empty() == false) {
      auto p = que.top();
      que.pop();
      long long v = p.second;
      if (D[v] < p.first) {
        continue;
      }
      for (long long e : graph[v]) {
        if (D[e] > D[v] + 1) {
          D[e] = D[v] + 1;
          que.push(make_pair(D[e], e));
        }
      }
    }
    long long maxd = 0;
    for (long long i = 0; i < S; i++) {
      if (D[i] > maxd && D[i] < LLMAX / 2) {
        maxd = D[i];
        end = i;
      }
    }
  }
  start = end;
  {
    vector<long long> D(S, LLMAX);
    D[start] = 0;
    priority_queue<pair<long long, long long>,
                   vector<pair<long long, long long>>,
                   greater<pair<long long, long long>>>
        que;
    que.push(make_pair(0, start));
    while (que.empty() == false) {
      auto p = que.top();
      que.pop();
      long long v = p.second;
      if (D[v] < p.first) {
        continue;
      }
      for (long long e : graph[v]) {
        if (D[e] > D[v] + 1) {
          D[e] = D[v] + 1;
          que.push(make_pair(D[e], e));
        }
      }
    }
    long long maxd = 0;
    for (long long i = 0; i < S; i++) {
      if (D[i] > maxd && D[i] < LLMAX / 2) {
        maxd = D[i];
        end = i;
      }
    }
    cout << maxd << endl;
    return 0;
  }
  return 0;
}
