using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BFS2
{
    class Program
    {
        public class DoneTile
        {
            public DoneTile(int[] thisPos,DoneTile from,int order)
            {
                ThisPos = thisPos;
                From = from;
                Order = order;
            }

            public int[] ThisPos { get; }
            public DoneTile From { get; }
            public int Order;
        }


        static void Main(string[] args)
        {
            int H = 0;
            int W = 0;
            char[][] map = null;
            int[] startPos = { 0, 0, 0 };
            int[] goalPos = { 2, 2 };

            map = ReadMap(out H,out W);

            List<int[]> startPoses = new List<int[]>();
            List<int[]> goalPoses = new List<int[]>();

            for (int i = 0; i < H; i++)
            {
                for (int j = 0; j < W; j++)
                {
                    if (map[i][j] == '.')
                    {
                        startPoses.Add(new int[2] { i, j });
                        goalPoses.Add(new int[2] { i, j });
                    }
                }
            }

            int[][] deltas = { new int[2] { 0, 1 }, new int[2] { 1, 0 }, new int[2] { 0, -1 }, new int[2] { -1, 0 } };

            DoneTile currentTile = null;


            int maxCount = 0;

            for (int i = 0; i < startPoses.Count-1; i++)
            {
                List<DoneTile> withExperience = new List<DoneTile>();

                for (int j = i+1; j < startPoses.Count; j++)
                {
                    if (!withExperience.Any(r => r.ThisPos[0] == startPoses[i][0] && r.ThisPos[1] == startPoses[i][1]))
                    {
                        startPos = new int[3] { startPoses[i][0], startPoses[i][1], 0 };
                        goalPos = startPoses[j];
                        Queue<DoneTile> queue = new Queue<DoneTile>();
                        DoneTile startDoneTile = new DoneTile(startPos, null, 0);
                        queue.Enqueue(startDoneTile);
                        List<DoneTile> done = new List<DoneTile>();
                        done.Add(startDoneTile);
                        while (true)
                        {
                            currentTile = queue.Dequeue();

                            //ゴールなら
                            if (currentTile.ThisPos[0] == goalPos[0] && currentTile.ThisPos[1] == goalPos[1])
                            {
                                DoneTile returnTile = currentTile;
                                while (returnTile != startDoneTile)
                                {
                                    withExperience.Add(returnTile);
                                    returnTile = returnTile.From;
                                }
                                break;
                            }

                            //通れるなら
                            if (map[currentTile.ThisPos[0]][currentTile.ThisPos[1]] == '.')
                            {
                                foreach (var delta in deltas)
                                {
                                    int[] aroundPos = new int[] { currentTile.ThisPos[0] + delta[0], currentTile.ThisPos[1] + delta[1] };
                                    if (aroundPos[0] >= 0 && aroundPos[0] < H && aroundPos[1] >= 0 && aroundPos[1] < W)
                                    {
                                        if (!done.Any(pos => pos.ThisPos[0] == aroundPos[0] && pos.ThisPos[1] == aroundPos[1]))
                                        {
                                            DoneTile next = new DoneTile(aroundPos, currentTile, currentTile.Order + 1);
                                            queue.Enqueue(next);
                                            done.Add(next);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    maxCount = Math.Max(maxCount, currentTile.Order);

                }

            }



            Console.WriteLine(maxCount);
            Console.ReadLine();
        }

        static private char[][] ReadMap(out int H,out int W)
        {
            string[] HW = Console.ReadLine().Split(' ');
            H = int.Parse(HW[0]);
            W = int.Parse(HW[1]);

            char[][] map = new char[H][];
            for (int i = 0; i < H; i++)
            {
                map[i] = Console.ReadLine().ToArray();
            }
            return map;
        }
    }
}
