use std::vec::Vec;
use std::cmp::*;

fn read<T: std::str::FromStr>() -> T {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).ok();
    s.trim().parse().ok().unwrap()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>().split_whitespace().map(|e| e.parse().ok().unwrap()).collect()
}

fn read_touple<T: std::str::FromStr + Copy>() -> (T, T) {
  let v: Vec<T> = read_vec();
  assert_eq!(v.len(), 2);
  (v[0], v[1])
}

fn main() {
    let (h, w) = read_touple::<usize>();
    let mut grid: Vec<Vec<char>> = Vec::new();
    for _ in 0..h {
      let line: Vec<char> = read::<String>().chars().collect();
      grid.push(line);
    }

    let mut res: usize = 0;
    for i in 0..h {
      for j in 0..w {
        let weight = grid_bfs(&grid, (i, j), '#');
        res = max(res, weight);
      }
    }
    // for i in 0..h {
    //   println!("{:?}", grid[i]);
    // }
    println!("{}", res + 1);
}


use std::collections::VecDeque;
fn grid_bfs<T>(grid: &Vec<Vec<T>>, start: (usize, usize), skip: T) -> usize
where
    T: Eq,
{
    assert!(grid.len() > 0);
    assert!(grid[0].len() > 0);

    fn connect_vec(a: usize, b: usize, h: usize, w: usize) -> Vec<(usize, usize)> {
        let mut res = Vec::new();
        if a > 0 {
            res.push((a - 1, b));
        }
        if a < h - 1 {
            res.push((a + 1, b));
        }
        if b > 0 {
            res.push((a, b - 1));
        }

        if b < w - 1 {
            res.push((a, b + 1));
        }

        res
    }
    let h: usize = grid.len();
    let w: usize = grid[0].len();
    let mut q = VecDeque::new();
    let mut visit = vec![vec![false; w]; h];
    let mut res: Vec<Vec<usize>> = vec![vec![std::usize::MAX; w]; h];
    // init
    let (x, y) = start;
    visit[x][y] = true;
    q.push_back(start);

    while let Some(now) = q.pop_front() {
        let (a, b) = now;
        for (x, y) in connect_vec(now.0, now.1, h, w) {
            if grid[x][y] == skip {
                continue;
            }

            if !visit[x][y] {
                visit[x][y] = true;
                res[x][y] = min(res[x][y], res[a][b] + 1);
                q.push_back((x, y));
            }
        }
    }
    let mut ans: usize = 0;
    for i in 0..h {
      for j in 0..w {
        if res[i][j] == std::usize::MAX {
          continue
        }
        ans = max(ans, res[i][j]);
      }
    }
    return ans;
}