use std::io::{self, BufRead};

fn main() {
  let stdin = io::stdin();
  let mut lines = stdin.lock().lines();
  let xs: Vec<usize> = lines.next().unwrap().unwrap().split(' ').map(|x| x.parse().unwrap()).collect();
  let (h, w) = (xs[0], xs[1]);
  let n = h * w;
  let mut cells: Vec<Vec<char>> = Vec::new();
  for _ in 0..h {
    let cs = lines.next().unwrap().unwrap().chars().collect();
    cells.push(cs);
  }
  let mut es: Vec<Vec<usize>> = vec![Vec::new(); n];
  for i in 0..h {
    for j in 0..w {
      if cells[i][j] == '#' {
        continue;
      }
      let k = i * w + j;
      if i > 0 && cells[i-1][j] == '.' {
        es[k].push((i - 1) * w + j);
      }
      if i < h - 1 && cells[i+1][j] == '.' {
        es[k].push((i + 1) * w + j);
      }
      if j > 0 && cells[i][j-1] == '.' {
        es[k].push(i * w + j - 1);
      }
      if j < w - 1 && cells[i][j+1] == '.' {
        es[k].push(i * w + j + 1);
      }
    }
  }
  let mut ds: Vec<Vec<usize>> = vec![vec![usize::max_value(); n]; n];
  for i in 0..n {
    ds[i][i] = 0;
    for j in &es[i] {
      ds[i][*j] = 1;
    }
  }
  for k in 0..n {
    for i in 0..n {
      for j in 0..n {
        let d = if ds[i][k] < usize::max_value() && ds[k][j] < usize::max_value() { ds[i][k] + ds[k][j] } else { usize::max_value() };
        if ds[i][j] > d {
          ds[i][j] = d;
        }
      }
    }
  }
  let ans = ds.iter().flatten().filter(|d| **d < usize::max_value()).max().unwrap();
  println!("{}", ans);
}