import Control.Arrow
import Control.Monad
import Data.List
import qualified Data.ByteString.Char8 as B
import qualified Data.Vector.Mutable as M
import qualified Data.Vector as V 
import Control.Monad.ST

main :: IO ()
main = readLine >>= main'
    where
        main' [h, w] = replicateM h getLine >>= print . solve h w 

solve :: Int -> Int -> [String] -> Int
solve h w as = V.maximum $ V.create (initialize >>= stAction)
    where
        initialize :: ST s (M.STVector s Int)
        initialize = M.replicate ((h + 2) * (w + 2)) 0 >>= next
            where
                next vs = vs <$ mapM_ (\(i, j, k) -> wf vs (i, j) k) bs

        stAction vs = vs <$ mapM_ (bfs0 vs) [(i, j) | i <- [1..h], j <- [1..w]]
        
        bfs0 vs idx = rf vs idx >>= check
            where
                check n 
                    | n > 0 = return ()
                    | otherwise = bfs vs 1 idx
                    
        bfs vs n (i, j) = mapM_ check [(i + 1, j), (i - 1, j), (i, j + 1), (i, j - 1)]
            where
                check idx = rf vs idx >>= cmpf idx
                cmpf idx m
                    | n < m = wf vs idx n >> bfs vs (n + 1) idx
                    | otherwise = return () 

        rf vs (i, j) = M.unsafeRead vs $ i * (h + 2) + j
        wf vs (i, j) = M.unsafeWrite vs (i * (h + 2) + j)

        bs = concatMap (\(i, xs) -> map (\(j, x) -> (i, j, x)) $ zip [1..] xs) . zip [1..] $ map (map cf) as
            where
                cf '#' = 0
                cf _ = 10 ^ 6

readLine :: IO [Int]
readLine = unfoldr (fmap (second (maybe B.empty snd . B.uncons)) . B.readInt) <$> B.getLine

readContents :: Int -> IO [[Int]]
readContents = flip replicateM readLine