use std::io::prelude::*;
fn main() {
    let field = read_field();
    for y in 0..field.h {
        for x in 0..field.w {
            print!("{}", field.show_at(x, y));
        }
        print!("\n");
    }
}

fn read_field() -> Field {
    let stdin = std::io::stdin();
    let mut input = stdin.lock();
    let mut l = String::new();
    let _ = input.read_line(&mut l);
    let hw: Vec<u32> = l
        .split_whitespace()
        .map(|n| n.parse().expect("readnumerror!"))
        .collect();
    let h = hw[0];
    let w = hw[1];
    let mut f: Vec<Cell> = Vec::with_capacity((h * w) as usize);
    for line in input.lines() {
        for c in line.expect("read line error").trim().chars() {
            match c {
                '.' => f.push(false),
                '#' => f.push(true),
                _ => panic!(format!("unexpected char {}", c)),
            }
        }
    }
    Field { h, w, field: f }
}

struct Field {
    h: u32,
    w: u32,
    field: Vec<Cell>,
}

impl Field {
    fn at(&self, x: i32, y: i32) -> Option<Cell> {
        if 0 <= x && x < self.w as i32 && 0 <= y && y < self.h as i32 {
            self.field
                .get(x as usize + y as usize * (self.w as usize))
                .copied()
        } else {
            None
        }
    }
    fn count_neighbour_incl_self(&self, x: u32, y: u32) -> u8 {
        let mut n: u8 = 0;
        for dx in &[-1, 0, 1] {
            for dy in &[-1, 0, 1] {
                n += self.at(x as i32 + dx, y as i32 + dy).unwrap_or(false) as u8;
            }
        }
        n
    }

    fn show_at(&self, x: u32, y: u32) -> String {
        if self.at(x as i32, y as i32).unwrap_or(false) {
            "#".to_string()
        } else {
            format!("{}", self.count_neighbour_incl_self(x, y))
        }
    }
}

type Cell = bool;
