#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <functional>
#include <iomanip>

#include <queue>

using namespace std;
using ll = long long;
using pii = pair<int, int>;
using vi = vector<int>;
using vvi = vector<vi>;

// #define rep(i,n) for(int i=0;i<(n);++i)
#define all(a) (a).begin(),(a).end()
#define _overload3(_1,_2,_3,name,...) name
#define _rep(i,n) for(int i=0;i<(n);++i)
#define repi(i,a,b) for(int i=(a);i<(b);++i)
#define rep(...) _overload3(__VA_ARGS__,repi,_rep,)(__VA_ARGS__)
#define _fromto2(i,n) for(int i=0;i<=(n);++i)
#define _fromto3(i,a,b) for(int i=(a);i<=(b);++i)
#define fromto(...) _overload3(__VA_ARGS__,_fromto3,_fromto2,)(__VA_ARGS__)

#define rrep(i,n) for(int i=(n);i>=0;--i)
#define iter(it,v) for(auto it=v.begin();it!=v.end();++it)
const int MOD = 1e9+7;
const int INF = 1e9;
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; }

// debug
template<class T>ostream& operator<<(ostream& os, vector<T>& vec){os<<"{";for(int i=0;i<vec.size();++i)os<<(i?", ":"")<<vec[i];os<<"}";return os;}
template<class T1,class T2>ostream& operator<<(ostream& out,const pair<T1,T2>& rhs){out<<"("<<rhs.first<<", "<<rhs.second<<")";return out;}
#include<type_traits>
template<typename T,size_t SIZE,enable_if_t<!is_same<remove_cv_t<T>,char>::value,nullptr_t> = nullptr>ostream& operator<<(ostream& os,T(&arr)[SIZE]){os<<"{";for(size_t i=0;i<SIZE;++i)os<<(i?", ":"")<<arr[i];os<<"}";return os;}
#ifdef LOCAL
#define debug(v) cerr<<v<<"\n"
#else
#define debug(...) 42
#endif

int di[4] = {0, 1, 0, -1}, dj[4] = {1, 0, -1, 0};

int main() {
  int H, W; cin >> H >> W;

  char S[H][W];
  pii start;
  int distance[H][W];
  rep(i, H) {
    rep(j, W) {
      cin >> S[i][j];
      if (S[i][j] == '.')
        start = pii(i, j);
      distance[i][j] = INF;
    }
  }
  queue<pii> q;
  q.push(start);
  distance[start.first][start.second] = 0;
  int max_i = start.first, max_j = start.second;
  while (!q.empty()) {
    int i = q.front().first,
        j = q.front().second;
    q.pop();
    if (distance[max_i][max_j] < distance[i][j])
      max_i = i, max_j = j;
    rep(d, 4) {
      if (!(0 <= i + di[d] && i + di[d] < H &&
            0 <= j + dj[d] && j + dj[d] < W))
        continue;
      if (S[i+di[d]][j+dj[d]] == '.' && distance[i+di[d]][j+dj[d]] == INF) {
        distance[i+di[d]][j+dj[d]] = distance[i][j] + 1;
        q.emplace(i+di[d], j+dj[d]);
      }
    }
  }

  rep(i, H) rep(j, W) distance[i][j] = INF;

  q.push(pii(max_i, max_j));
  distance[max_i][max_j] = 0;
  while (!q.empty()) {
    int i = q.front().first,
        j = q.front().second;
    q.pop();
    if (distance[max_i][max_j] < distance[i][j])
      max_i = i, max_j = j;
    rep(d, 4) {
      if (!(0 <= i + di[d] && i + di[d] < H &&
            0 <= j + dj[d] && j + dj[d] < W))
        continue;
      if (S[i+di[d]][j+dj[d]] == '.' && distance[i+di[d]][j+dj[d]] == INF) {
        distance[i+di[d]][j+dj[d]] = distance[i][j] + 1;
        q.emplace(i+di[d], j+dj[d]);
      }
    }
  }
  cout << distance[max_i][max_j] << endl;

  return 0;
}
