#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define fr first
#define sc second
#define pb push_back
#define maxheap priority_queue<int>
#define minheap priority_queue<int, vector<int>, greater<int> >
const int INF = 1e9+7;
const int MAXN = 5e5 + 200;
const  long double eps = 1e-16;
const long double pi = acos(-1.0);
using namespace std;
using namespace __gnu_pbds;
typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

string s[30];
long long dp[30][30];
long long mn;
void solve(){
    mn = 0;
    int n, m;
    cin >> n >> m;
    for (int i = 0; i < n; i++)
        cin >> s[i];

    for (int i = 0; i < n; i++){
        for (int j = 0; j < m; j++){
            if (s[i][j] == '#') continue;
            for (int q = 0 ; q < n; q++)
                for (int w = 0; w < m; w++)
                dp[q][w] = INF;

            int x = i;
            int y = j;

            deque <pair <int, int > > q;
            q.push_front({x, y});
            dp[x][y] = 0;
            while (! q.empty()){
                int x1 = q.back().fr;
                int y1 = q.back().sc;
                /*
               if (i == 0 && j == 0 && x1 == 2 && y1 == 2){
                    cout << dp[x1 + 1][y1] << endl;
                    cout << dp[x1 - 1][y1] << endl;
                    cout << dp[x1][y1 + 1] << endl;
                    cout << dp[x1][y1 - 1] << endl;

               }
               */
                //if (i == 0 && j == 0)
                 //   cout << x1 << " " << y1 << endl;
                //cout << x1 << " " << y1 << endl;





                if (x1 + 1 < n){
                    if (s[x1 + 1][y1] == '.'){
                    if (dp[x1 + 1][y1] == INF)
                        q.push_front({x1 + 1, y1});
                    dp[x1 + 1][y1] = min(dp[x1][y1] + 1, dp[x1 + 1][y1]);

                    }
                }
                if (y1 + 1 < m){
                    if (s[x1][y1 + 1] == '.'){

                    if (dp[x1][y1 + 1] == INF)
                        q.push_front({x1, y1 + 1});
                        dp[x1][y1 + 1] = min(dp[x1][y1] + 1, dp[x1][y1 + 1]);

                    }
                }
                if (x1 - 1 >= 0){
                    if (s[x1 - 1][y1] == '.'){
                    if (dp[x1 - 1][y1] == INF)
                        q.push_front({x1 - 1, y1});
                    dp[x1 - 1][y1] = min(dp[x1][y1] + 1, dp[x1 - 1][y1]);
                    }
                }
                if (y1 - 1 >= 0){
                    if (s[x1][y1 - 1] == '.'){
                    if (dp[x1][y1 - 1] == INF)
                             q.push_front({x1, y1 - 1});
                    dp[x1][y1 - 1] = min(dp[x1][y1] + 1, dp[x1][y1 - 1]);

                    }
                }
                q.pop_back();
            }

            long long  ans = 0;
            for (int q = 0; q < n; q++){
                for (int w = 0; w < m; w++){
                    if (dp[q][w] == INF) continue;
                    ans = max(ans, dp[q][w]);
                 }
            }

            mn = max(ans, mn);

        }
    }
    cout << mn << endl;

}

int main() {
ios::sync_with_stdio(NULL), cin.tie(0), cout.tie(0);
cout.setf(ios::fixed), cout.precision(10);
 //freopen("input.in", "r", stdin);
// freopen("output.out", "w", stdout);
 int step;
 step = 1;
  for (int i = 1; i <= step; i++){
         solve();
    }
}


Measured memory_bytes: 256