#include <bits/stdc++.h>
using namespace::std;
#define int long long

#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define sax(x) cout << "!!!!!!!!!!! " << #x << " = " << x << '\n'
#define inf (sizeof(int) == 4 ? (int)1E9 : (int)1E18)
#define one(x) x.insert(x.begin(), 0);
#define TCT template <class T>
#define TCT12 template <class T1, class T2>

//#include <ext/pb_ds/assoc_container.hpp>
//using namespace __gnu_pbds;
//typedef tree<int,null_type,less_equal<int>,rb_tree_tag,
//tree_order_statistics_node_update> imsi;

TCT12 istream& operator>>(istream &I, pair<T1,T2>& p) {return I >> p.first >> p.second;}
TCT12 ostream& operator<<(ostream &O, const pair<T1,T2>& p) {return O << '(' << p.first << ' ' << p.second << ')';}
TCT istream& operator>>(istream &I, vector<T>& v) {for (T &e: v) I >> e; return I;}
TCT ostream& operator<<(ostream &O, const vector<T>& v) {for (const T &e: v) O << e << ' '; return O;}
TCT ostream& operator<<(ostream &O, const unordered_set<T>& v) {for (const T &e: v) O << e << ' '; return O;}
TCT ostream& operator<<(ostream &O, const set<T>& v) {for (const T &e: v) O << e << ' '; return O;}
TCT ostream& operator<<(ostream &O, const unordered_multiset<T>& v) {for (const T &e: v) O << e << ' '; return O;}
TCT ostream& operator<<(ostream &O, const multiset<T>& v) {for (const T &e: v) O << e << ' '; return O;}
TCT12 ostream& operator<<(ostream &O, const unordered_map<T1,T2>& v) {for (const auto &e: v) O << e << ' '; return O;}
TCT12 ostream& operator<<(ostream &O, const map<T1,T2>& v) {for (const auto &e: v) O << e << ' '; return O;}
TCT istream& operator>>(istream &I, deque<T>& v) {for (T &e: v) I >> e; return I;}
TCT ostream& operator<<(ostream &O, const deque<T>& v) {for (const T &e: v) O << e << ' '; return O;}
typedef pair<int,int> pii;
typedef vector<int> vi;





char grid[21][21];
const int dx[] {1,0,-1,0}, dy[]{0,1,0,-1};
int n, m;

int valid(int i, int N) {
        return i >= 0 && i < N;
}

int get(pii from) {
        queue<pii> q;
        q.emplace(from);
        map<pii, int> dist;
        dist[from] = 0;
        int ans = 0;
        while (q.size()) {
                auto now = q.front(); q.pop();
                for (int i = 0; i < 4; i++) {
                        int next_i = dx[i] + now.first;
                        int next_j = dy[i] + now.second;
                        if (dist.count({next_i, next_j}) || !valid(next_i, n) || !valid(next_j, m) || grid[next_i][next_j] == '#')
                                continue;

                        q.emplace(next_i, next_j);
                        dist[{next_i, next_j}] = dist[now] + 1;
                        ans = max(ans,dist[{next_i, next_j}]);
                }
        }

        return ans;
}



void _main() {
        cin >> n >> m;
        for (int i = 0; i < n; i++)
                for (int j = 0; j < m; j++)
                        cin >> grid[i][j];

        int ans = 0;
        for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                        if (grid[i][j] == '#') continue;
                        ans = max(ans, get(make_pair(i, j)));
                }
        }

        cout << ans;
}



signed main() {
        ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
        int _t = 1;
//        cin >> _t;
        while (_t--) _main();
        return 0;
}

Measured memory_bytes: 256