#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>
#include <array>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <forward_list>
#include <future>
#include <initializer_list>
#include <mutex>
#include <random>
#include <ratio>
#include <regex>
#include <scoped_allocator>
#include <system_error>
#include <thread>
#include <tuple>
#include <typeindex>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
using namespace std;
using ll = long long;
#define MAX_N 1000001
#define MAX_M 100010
const long long mod = 1e9 + 7;
#define vec vector<int>
#define vecll vector<ll>
#define vecllvec vector<vector<ll>>
#define vecb vector<bool>
#define vecBvec vector<vector<bool>>
#define vecst vector<string>
#define veche vector<char>
#define vecd vector<double>
#define vecvec vector<vector<int>>
#define vecDvec vector<vector<double>>
#define vecHvec vector<vector<char>>
#define all(x) (x).begin(),(x).end()
#define ent cout<<endl
#define printvec(vec) for(int aqw=0;aqw<vec.size();aqw++){cout<<vec[aqw]<<" ";}ent;
#define rep1(n) for(ll i = 0; i < (n); ++i)
#define rep2(i, n) for(ll i = 0; i < (n); ++i)
#define rep3(i, a, b) for(ll i = (a); i < (b); ++i)
#define rep4(i, a, b, c) for(ll i = (a); i < (b); i += (c))
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
#define INF 1e+9
#define print(x) cout<<x<<endl;
using P = pair<int, int>;
#define PLL pair<ll, ll>;
#define MAX_V 1000
#define PI 3.141592653589793
#define vecP vector<P>
// cout << setprecision(15) << std::fixed;


// 座標 corrdinate と深さを保持するための構造体
struct Corr {
    ll y;
    ll x;
    ll depth;
};

ll N, M;  // 迷路の縦，横
ll s_y, s_x, g_y, g_x;  // スタート，ゴールの座標
ll y, x, depth;  // キューから取り出した座標
vector<string> vect;  // 座標を受け取る配列
queue<Corr> q;

vector<ll> y_vec = { 0, 0, -1, +1 };  // 進む方向の簡便化，テクニックとして覚えておく．
vector<ll> x_vec = { -1, +1, 0, 0 };  // ループで回すことで上下左右に移動できるようになっている

ll bfs() {
    ll ret = 0;
    while (!q.empty()) {
        Corr now = q.front(); q.pop();  // キューの先頭を取り出す
        y = now.y, x = now.x, depth = now.depth;  // 行，列が y, x になっているので注意

        //// 停止条件：現在の座標がゴールなら深さを返す
        //if (y == g_y && x == g_x) return depth;
        chmax(ret, depth);
        // 上下左右 4 方向を探索．進むことができればキューに格納する．
        for (ll i = 0; i < 4; ++i) {
            Corr next = { y + y_vec[i], x + x_vec[i], depth + 1 };
            if (0 <= next.y && next.y <= N - 1 && 0 <= next.x && next.x <= M - 1 && vect[next.y][next.x] == '.') {
                vect[next.y][next.x] = 'x';  // 同じ場所を探索しないようにする
                q.push(next);
            }
        }
    }
    return ret;
}

int main() {
    // input
    cin >> N >> M;
    ll ans = 0;
    vector<string> vectcp;
    vectcp.resize(N); for (ll i = 0; i < N; ++i) cin >> vectcp[i];
    int cut = 0;
    // calculation
    for (int i = 0;i < N;i++) {
        for (int j = 0;j < M;j++) {
            if (vectcp[i][j] == '#') continue;
            cut++;
            vect = vectcp;
            s_y = i;
            s_x = j;
            Corr start = { s_y, s_x, 0 };  // 初期位置の深さ(depth)は 0
            q.emplace(start);  // 初期位置をキューに格納
            //cout << bfs() << endl;
            chmax(ans, bfs());
        }
    }
    if (cut == 2) {
        cout << 1 << endl;
    }
    else {
        cout << ans;

    }
    

    return 0;
}

Measured memory_bytes: 256