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[]>();

            List<int[]> startGoalPair = new List<int[]>();

            int[][][][] withExperience = new int[H][][][];

            for (int i = 0; i < H; i++)
            {
                withExperience[i] = new int[W][][];
                for (int j = 0; j < W; j++)
                {
                    withExperience[i][j] = new int[H][];
                    for (int k = 0; k < H; k++)
                    {
                        withExperience[i][j][k] = new int[W];
                    }
                    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++)
            {

                for (int j = i+1; j < startPoses.Count; j++)
                {
                    startPos = new int[3] { startPoses[i][0], startPoses[i][1], 0 };

                    goalPos = startPoses[j];
                    if (withExperience[startPos[0]][startPos[1]][goalPos[0]][goalPos[1]]==0)
                    {
                        Queue<DoneTile> queue = new Queue<DoneTile>();
                        DoneTile startDoneTile = new DoneTile(startPos, null, 0);
                        queue.Enqueue(startDoneTile);
                        int[][] done = new int[H][];
                        for (int k = 0; k < H; k++)
                        {
                            done[k] = new int[W];
                        }
                        done[startDoneTile.ThisPos[0]][startDoneTile.ThisPos[1]] = 1;
                        while (true)
                        {
                            currentTile = queue.Dequeue();

                            //ゴールなら
                            if (currentTile.ThisPos[0] == goalPos[0] && currentTile.ThisPos[1] == goalPos[1])
                            {
                                DoneTile returnTile = currentTile;
                                while (returnTile != startDoneTile)
                                {
                                    withExperience[startDoneTile.ThisPos[0]][startDoneTile.ThisPos[1]][returnTile.ThisPos[0]][returnTile.ThisPos[1]] = 1;
                                    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[aroundPos[0]][aroundPos[1]] == 0)
                                        {
                                            DoneTile next = new DoneTile(aroundPos, currentTile, currentTile.Order + 1);
                                            queue.Enqueue(next);
                                            done[aroundPos[0]][aroundPos[1]] = 1;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    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;
        }
    }
}


Measured memory_bytes: 27156