using System; 
using System.Text;
using System.Collections.Generic;
using System.Collections;
using System.Linq; 
using E = System.Linq.Enumerable; 


class Program {
    static int[,]   map;
    static int      H;
    static int      W;
    static string[] S;
    static void Main(string[] args) {
        
        var HW = Console.ReadLine().Split(' ').Select(x => int.Parse(x)).ToArray();
        H = HW[0];
        W = HW[1];
        
        S = new string[H];
       // Console.WriteLine(22);
        for(int i = 0;i < H;i++){
            S[i] = Console.ReadLine();
        }
        
        map = new int[H,W];
        IniMap();
        
        //0で初期化
        var ans = 0;
        for(int i = 0;i < H;i++){
             for(int j = 0;j < W;j++){
                 if(S[i][j] == '.'){
                     //幅優先で最長経路を探す
                     ans =Math.Max(bfs(i,j),ans);
                     //マップを初期化
                     IniMap();
                     //答えを更新
                 }
             }
        }
        Console.WriteLine(ans);
        
     }
     
     static int bfs(int i,int j){
         var q = new Queue<int[]>();
         var max = 0;
         //キューにスタートの値を入れる
         q.Enqueue(new int[]{i,j});
         map[i,j] = 0;
         while(q.Count() > 0){
             var now = q.Dequeue();
             var a = now[0];
             var b = now[1];
             
             //上に行けるか
             if(a > 0 && S[a-1][b] == '.' && map[a-1,b] == -1){
                 map[a-1,b] = map[a,b]+1;
                 q.Enqueue(new int[]{a-1,b});
                 max = Math.Max(max,map[a,b]+1);
             }
             
             //下に行けるか
             if(a+1 < H && S[a+1][b] == '.' && map[a+1,b] == -1){
                 map[a+1,b] = map[a,b]+1;
                 q.Enqueue(new int[]{a+1,b});
                 max = Math.Max(max,map[a,b]+1);
              }
              
              //右に行けるか
             if(b+1 < W && S[a][b+1] == '.' && map[a,b+1] == -1){
                 map[a,b+1] = map[a,b]+1;
                 q.Enqueue(new int[]{a,b+1});
                 max = Math.Max(max,map[a,b]+1);
              }
              
              //左に行けるか
             if(b > 0 && S[a][b-1] == '.' && map[a,b-1] == -1){
                 map[a,b-1] = map[a,b]+1;
                 q.Enqueue(new int[]{a,b-1});
                 max = Math.Max(max,map[a,b]+1);
             }
             
         }
         return max;
     }
     
     static void IniMap(){
         for(int i = 0;i < H;i++){
             for(int j = 0;j < W;j++){
                 map[i,j] = -1;
             }
         }
     }
}
     
     
                   
public class PriorityQueue<T> : IEnumerable<T> { private readonly List<T> _data = new List<T>(); private readonly IComparer<T> _comparer; private readonly bool _isDescending; public PriorityQueue(IComparer<T> comparer, bool isDescending = true) { _comparer = comparer; _isDescending = isDescending; } public PriorityQueue(Comparison<T> comparison, bool isDescending = true) : this(Comparer<T>.Create(comparison), isDescending) { } public PriorityQueue(bool isDescending = true) : this(Comparer<T>.Default, isDescending) { } public void Enqueue(T item) { _data.Add(item); var childIndex = _data.Count - 1; while (childIndex > 0) { var parentIndex = (childIndex - 1) / 2; if (Compare(_data[childIndex], _data[parentIndex]) >= 0) break; Swap(childIndex, parentIndex); childIndex = parentIndex; } } public T Dequeue() { var lastIndex = _data.Count - 1; var firstItem = _data[0]; _data[0] = _data[lastIndex]; _data.RemoveAt(lastIndex--); var parentIndex = 0; while (true) { var childIndex = parentIndex * 2 + 1; if (childIndex > lastIndex) break; var rightChild = childIndex + 1; if (rightChild <= lastIndex && Compare(_data[rightChild], _data[childIndex]) < 0) childIndex = rightChild; if (Compare(_data[parentIndex], _data[childIndex]) <= 0) break; Swap(parentIndex, childIndex); parentIndex = childIndex; } return firstItem; } public T Peek() { return _data[0]; } private void Swap(int a, int b) { var tmp = _data[a]; _data[a] = _data[b]; _data[b] = tmp; } private int Compare(T a, T b) { return _isDescending ? _comparer.Compare(b, a) : _comparer.Compare(a, b); } public int Count => _data.Count; public IEnumerator<T> GetEnumerator() { return _data.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); }


Measured memory_bytes: 17616