package main

import "fmt"

type point struct {
	x, y int
}

type container struct {
	data []point
}

func (c *container) isEmpty() bool {
	return len(c.data) == 0
}
func (c *container) queue(v point) {
	c.data = append(c.data, v)
}
func (c *container) dequeue(v *point) bool {
	if !c.isEmpty() {
		*v = c.data[0]
		c.data = c.data[1:]
		return true
	}
	return false
}

func main() {
	var H, W int
	fmt.Scan(&H, &W)
	maze := make([]string, H)
	for i := range maze {
		fmt.Scan(&maze[i])
	}
	var dx = [4]int{1, -1, 0, 0}
	var dy = [4]int{0, 0, -1, 1}

	ans := 0
	for i := 0; i < H; i++ {
		for j := 0; j < W; j++ {
			// (i,j)を開始地点としてBFSする
			d := make([][]int, H)
			for k := 0; k < H; k++ {
				d[k] = make([]int, W)
				for l := 0; l < W; l++ {
					d[k][l] = -1
				}
			}
			var q container
			d[i][j] = 0
			q.queue(point{j, i})
			for !q.isEmpty() {
				var p point
				q.dequeue(&p)
				for k := 0; k < 4; k++ {
					nx := p.x + dx[k]
					ny := p.y + dy[k]
					if 0 <= nx && nx < W && 0 <= ny && ny < H && d[ny][nx] == -1 && maze[ny][nx] == '.' {
						d[ny][nx] = d[p.y][p.x] + 1
						ans = max(ans, d[ny][nx])
						q.queue(point{nx, ny})
					}
				}
			}
		}
	}
	fmt.Println(ans)
}
func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}
