package main

import "fmt"

var H, W int

type Unit [3]int
type Stack struct {
	arr []Unit
	n   int
}

func (stack *Stack) push(s Unit) {
	stack.arr = append(stack.arr, s)
	stack.n++
}
func (stack *Stack) pop() Unit {
	s := stack.arr[stack.n-1]
	stack.arr = stack.arr[:stack.n-1]
	stack.n--
	return s
}

type Queue struct {
	arr []Unit
	n   int
}

func (queue *Queue) push(s Unit) {
	// fmt.Printf("%d %d %d\n", s[0], s[1], s[2])
	queue.arr = append(queue.arr, s)
	queue.n++
}
func (queue *Queue) pop() Unit {
	s := queue.arr[0]
	queue.arr = queue.arr[1:]
	queue.n--
	return s
}

func solve(S [][]bool, sx int, sy int) int {
	if S[sx][sy] {
		return 0
	}

	max_cost := 0
	D := make([][]bool, W)
	for x := 0; x < W; x++ {
		D[x] = make([]bool, H)
	}
	DXY := [4][2]int{
		{-1, 0},
		{1, 0},
		{0, -1},
		{0, 1},
	}
	D[sx][sy] = true
	queue := Queue{}
	queue.push(Unit{sx, sy, 0})
	for queue.n > 0 {
		p := queue.pop()
		px, py, pc := p[0], p[1], p[2]
		if max_cost < pc {
			max_cost = pc
		}
		for d := 0; d < 4; d++ {
			dx, dy := DXY[d][0], DXY[d][1]
			if px+dx < 0 || px+dx >= W || py+dy < 0 || py+dy >= H {
				continue
			}
			if !S[px+dx][py+dy] && !D[px+dx][py+dy] {
				D[px+dx][py+dy] = true
				queue.push(Unit{px + dx, py + dy, pc + 1})
			}
		}
	}

	return max_cost
}

func main() {
	fmt.Scanf("%d %d\n", &W, &H)
	S := make([][]bool, W)
	for x := 0; x < W; x++ {
		S[x] = make([]bool, H)
	}
	var buff string
	for y := 0; y < H; y++ {
		fmt.Scan(&buff)
		for x := 0; x < W; x++ {
			if buff[x] == '#' {
				S[x][y] = true
			}
		}
	}

	max_cost := 0
	for x := 0; x < W; x++ {
		for y := 0; y < H; y++ {
			c := solve(S, x, y)
			if c > max_cost {
				max_cost = c
			}
		}
	}
	fmt.Println(max_cost)
}
