public class Main {
  private static void solve() {
    int h = ni();
    int w = ni();

    char[][] map = new char[h][w];
    for (int i = 0; i < h ; i ++) {
      map[i] = ns();
    }

    int[][] dir = new int[][] {
      {-1, 0},{1, 0}, {0, 1}, {0, -1},
      {-1, -1}, {-1, 1}, {1, -1}, {1,1}
    };

    for (int i = 0; i < h; i ++) {
      for (int j = 0; j < w; j ++) {
        int count = 0;
        if (map[i][j] == '.') {
          for (int[] d : dir) {
            int ni = i + d[0];
            int nj = j + d[1];
            if (0 <= ni && ni < h && 0 <= nj && nj < w) {
              if (map[ni][nj] == '#') {
                count ++;
              }
            }
          }
          map[i][j] = (char)('0' + count);
        }
      }
    }

    for (char[] v : map) {
      System.out.println(v);
    }
  }

  public static void main(String[] args) {
    new Thread(null, new Runnable() {
      @Override
      public void run() {
        long start = System.currentTimeMillis();
        String debug = args.length > 0 ? args[0] : null;
        if (debug != null) {
          try {
            is = java.nio.file.Files.newInputStream(java.nio.file.Paths.get(debug));
          } catch (Exception e) {
            throw new RuntimeException(e);
          }
        }
        reader = new java.io.BufferedReader(new java.io.InputStreamReader(is), 32768);
        solve();
        out.flush();
        tr((System.currentTimeMillis() - start) + "ms");
      }
    }, "", 64000000).start();
  }

  private static java.io.InputStream is = System.in;
  private static java.io.PrintWriter out = new java.io.PrintWriter(System.out);
  private static java.util.StringTokenizer tokenizer = null;
  private static java.io.BufferedReader reader;

  public static String next() {
    while (tokenizer == null || !tokenizer.hasMoreTokens()) {
      try {
        tokenizer = new java.util.StringTokenizer(reader.readLine());
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }
    return tokenizer.nextToken();
  }

  private static double nd() {
    return Double.parseDouble(next());
  }

  private static long nl() {
    return Long.parseLong(next());
  }

  private static int[] na(int n) {
    int[] a = new int[n];
    for (int i = 0; i < n; i++)
      a[i] = ni();
    return a;
  }

  private static char[] ns() {
    return next().toCharArray();
  }

  private static long[] nal(int n) {
    long[] a = new long[n];
    for (int i = 0; i < n; i++)
      a[i] = nl();
    return a;
  }

  private static int[][] ntable(int n, int m) {
    int[][] table = new int[n][m];
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < m; j++) {
        table[i][j] = ni();
      }
    }
    return table;
  }

  private static int[][] nlist(int n, int m) {
    int[][] table = new int[m][n];
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < m; j++) {
        table[j][i] = ni();
      }
    }
    return table;
  }

  private static int ni() {
    return Integer.parseInt(next());
  }

  private static void tr(Object... o) {
    if (is != System.in)
      System.out.println(java.util.Arrays.deepToString(o));
  }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Pradyumn
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        FastReader in = new FastReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskB solver = new TaskB();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskB {
        public void solve(int testNumber, FastReader in, PrintWriter out) {
            int n = in.nextInt();
            int m = in.nextInt();
            char[][] map = in.nextCharacterMap(n, m);
            for (int i = 0; i < n; ++i) {
                for (int j = 0; j < m; ++j) {
                    if (map[i][j] == '#') continue;
                    int ct = 0;
                    for (int dr = -1; dr <= 1; ++dr) {
                        for (int dc = -1; dc <= 1; ++dc) {
                            int nr = i + dr;
                            int nc = j + dc;
                            if (MiscUtils.isValidCell(nr, nc, n, m) && map[nr][nc] == '#') {
                                ++ct;
                            }
                        }
                    }
                    map[i][j] = (char) (ct + '0');
                }
            }
            for (int i = 0; i < n; ++i) out.println(new String(map[i]));
        }

    }

    static class MiscUtils {
        public static boolean isValidCell(int row, int column, int rowCount, int columnCount) {
            return row >= 0 && row < rowCount && column >= 0 && column < columnCount;
        }

    }

    static class FastReader {
        private InputStream stream;
        private byte[] buf = new byte[8192];
        private int curChar;
        private int pnumChars;
        private FastReader.SpaceCharFilter filter;

        public FastReader(InputStream stream) {
            this.stream = stream;
        }

        private int pread() {
            if (pnumChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= pnumChars) {
                curChar = 0;
                try {
                    pnumChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (pnumChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int nextInt() {
            int c = pread();
            while (isSpaceChar(c))
                c = pread();
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = pread();
            }
            int res = 0;
            do {
                if (c == ',') {
                    c = pread();
                }
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = pread();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        private boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        private static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public char nextCharacter() {
            int c = pread();
            while (isSpaceChar(c))
                c = pread();
            return (char) c;
        }

        public char[] nextCharacterArray(int n) {
            char[] chars = new char[n];
            for (int i = 0; i < n; i++) {
                chars[i] = nextCharacter();
            }
            return chars;
        }

        public char[][] nextCharacterMap(int n, int m) {
            char[][] map = new char[n][];
            for (int i = 0; i < n; i++) {
                map[i] = nextCharacterArray(m);
            }
            return map;
        }

        private interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }
}


import java.util.*;
import java.io.*;

public class Main {
    BufferedReader br;
    PrintWriter out;
    StringTokenizer stok;

    String nextToken() throws IOException {
        while (stok == null || !stok.hasMoreTokens()) {
            String s = br.readLine();
            if (s == null) {
                return null;
            }
            stok = new StringTokenizer(s);
        }
        return stok.nextToken();
    }

    int nextInt() throws IOException {
        return Integer.parseInt(nextToken());
    }

    long nextLong() throws IOException {
        return Long.parseLong(nextToken());
    }

    double nextDouble() throws IOException {
        return Double.parseDouble(nextToken());
    }

    char nextChar() throws IOException {
        return (char) (br.read());
    }

    String nextLine() throws IOException {
        return br.readLine();
    }
    boolean inField(int x, int y, int n, int m) {
        return (x >= 0 && y >= 0 && x < n && y < m);
    }
    void solve() throws IOException {
        int n = nextInt();
        int m = nextInt();
        char[][] c = new char[n][m];
        for (int i = 0; i < n; i++) {
            c[i] = nextToken().toCharArray();
        }
        int[] dx = {-1,0,1,1,1,0,-1,-1};
        int[] dy = {1,1,1,0,-1,-1,-1,0};
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (c[i][j] == '#') continue;
                int ans = 0;
                for (int k = 0; k < 8; k++) {
                    int ni = i + dx[k];
                    int nj = j + dy[k];
                    if (inField(ni,nj,n,m) && c[ni][nj] =='#'){
                        ans++;
                    }
                }
                c[i][j] = (char)('0' + ans);
            }
        }

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                out.print(c[i][j]);
            }
            out.println();
        }
    }

    void run() throws IOException {
        // br = new BufferedReader(new FileReader("dragons.in"));
        //out = new PrintWriter("dragons.out");
        // br = new BufferedReader(new FileReader("input.txt"));
        // out = new PrintWriter("output.txt");
        br = new BufferedReader(new InputStreamReader(System.in));
        out = new PrintWriter(System.out);
        solve();
        br.close();
        out.close();
    }

    public static void main(String[] args) throws IOException {
        // Locale.setDefault(Locale.US);
        new Main().run();
    }
}


import java.util.*;
public class Main {
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
        int H = sc.nextInt();
        int W = sc.nextInt();
        char[][] S = new char[H][W];
        for(int i=0; i<H; i++){
            S[i] = sc.next().toCharArray();
        }
        //String S = sc.next();

        for(int i=0; i<H; i++){
            for(int j=0; j<W; j++){
                if(S[i][j]=='#'){
                    continue;
                }
                int count=0;
                if(i>0){
                    if(S[i-1][j]=='#'){
                        count++;
                    }
                    if(j>0 && S[i-1][j-1]=='#'){
                        count++;
                    }
                    if(j<W-1 && S[i-1][j+1]=='#'){
                        count++;
                    }
                }

                if(j>0 && S[i][j-1]=='#'){
                    count++;
                }
                if(j<W-1 && S[i][j+1]=='#'){
                    count++;
                }

                if(i<H-1){
                    if(S[i+1][j]=='#'){
                        count++;
                    }
                    if(j>0 && S[i+1][j-1]=='#'){
                        count++;
                    }
                    if(j<W-1 && S[i+1][j+1]=='#'){
                        count++;
                    }
                }

                System.out.print(count);
            }
            System.out.println();
        }

        }

        }


import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int H = sc.nextInt();//マス目の設定
        int W = sc.nextInt();
        String[][] map;
      	int[][] result;
      	map=new String [H][W];
      	result=new int[H][W];

      	for(int i=0;i<H;i++) {//データの打ち込み
          for(int j=0;j<W;j++){
			map[i][j]=sc.next();
          }
		}
     	for(int i=0;i<H;i++) {//データの打ち込み
          for(int j=0;j<W;j++){
			result[i][j]=-1;
          }
		}

      	for(int i=0;i<H;i++) {//変換
          for(int j=0;j<W;j++){
           	if(map[i][j]=="."){
              result[i][j]=0;

              if(map[i][j+1]=="#"){
				result[i][j]+=1;
              }
              if(map[i][j-1]=="#"){
				result[i][j]+=1;
              }
              if(map[i+1][j]=="#"){
				result[i][j]+=1;
              }
              if(map[i-1][j]=="#"){
				result[i][j]+=1;
              }
              if(map[i+1][j+1]=="#"){
				result[i][j]+=1;
              }
              if(map[i-1][j+1]=="#"){
				result[i][j]+=1;
              }
              if(map[i+1][j-1]=="#"){
				result[i][j]+=1;
              }
              if(map[i-1][j-1]=="#"){
				result[i][j]+=1;
              }

           	}
          }
		}

      for(int i=0;i<H;i++) {//データの書き出し
        for(int j=0;j<W-1;j++){
          if(result[i][j]==-1){
			System.out.print(map[i][j]);
          }else{
          	System.out.print(result[i][j]);
          }
        }

		if(result[i][W]==-1){
		  System.out.println(map[i][W]);
        }else{
          System.out.println(result[i][W]);
        }
      }

    }
}


import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int H = sc.nextInt();//マス目の設定
        int W = sc.nextInt();
        String[][] map;
      	int[][] result;
      	map=new String [H][W];
      	result=new int[H][W];

      	for(int i=0;i<H;i++) {//データの打ち込み
          for(int j=0;j<W;j++){
			map[i][j]=sc.next();
          }
		}
     	for(int i=0;i<H;i++) {//データの打ち込み
          for(int j=0;j<W;j++){
			result[i][j]=-1;
          }
		}

      	for(int i=0;i<H;i++) {//変換
          for(int j=0;j<W;j++){
           	if(map[i][j]=="."){
              result[H][W]=0;

              if(map[i][j+1]=="#"){
				result[i][j]+=1;
              }
              if(map[i][j-1]=="#"){
				result[i][j]+=1;
              }
              if(map[i+1][j]=="#"){
				result[i][j]+=1;
              }
              if(map[i-1][j]=="#"){
				result[i][j]+=1;
              }
              if(map[i+1][j+1]=="#"){
				result[i][j]+=1;
              }
              if(map[i-1][j+1]=="#"){
				result[i][j]+=1;
              }
              if(map[i+1][j-1]=="#"){
				result[i][j]+=1;
              }
              if(map[i-1][j-1]=="#"){
				result[i][j]+=1;
              }

           	}
          }
		}

      for(int i=0;i<H;i++) {//データの書き出し
        for(int j=0;j<W-1;j++){
          if(result[i][j]==-1){
			System.out.print(map[i][j]);
          }else{
          	System.out.print(result[i][j]);
          }
        }

		if(result[i][W]==-1){
		  System.out.println(map[i][W]);
        }else{
          System.out.println(result[i][W]);
        }
      }

    }
}


#include <bits/stdc++.h>
using namespace std;

bool is_sharp(vector<string> &s, int h, int w, int H, int W) {
  return 0 <= h && h < H && 0 <= w && w < W && s.at(h).at(w) == '#';
}

int count_sharp(vector<string>& s, int h, int w, int H, int W) {

  vector<vector<int> > coordinates = {
    {h - 1, w - 1},
    {h - 1, w    },
    {h - 1, w + 1},
    {h    , w + 1},
    {h + 1, w + 1},
    {h + 1, w    },
    {h + 1, w - 1},
    {h    , w - 1}
  };

  int count = 0;
  for (int i = 0; i < coordinates.size(); i++) {
    int h_i = coordinates.at(i).at(0);
    int w_i = coordinates.at(i).at(1);
    if (is_sharp(s, h_i, w_i, H, W)) {
      count++;
    }
  }

  return count;
}

void answer1() {
  cin.tie(0);
	ios_base::sync_with_stdio(false);
  int H, W;
  cin >> H >> W;
  vector<string> s(H);
  for (auto& s_i: s) {
    cin >> s_i;
  }
  for (int h = 0; h < H; h++) {
    for (int w = 0; w < W; w++) {
      if (! is_sharp(s, h, w, H, W)) {
        int count = count_sharp(s, h, w, H, W);
        //char c_count = (char)('0' + count);
        //s.at(h).at(w) = c_count;
        cout << count;
      } else {
        cout << '#';
      }
    }
    cout << endl;
  }
}

void answer2() {
  cin.tie(0);
	ios_base::sync_with_stdio(false);
  int H, W;
  cin >> H >> W;

  char s[52][52] = {};
  for (int i = 1; i <= H; i++) {
    for (int j = 1; j <= W; j++) {
      cin >> s[i][j];
    }
  }

  for (int i = 1; i <= H; i++) {
    for (int j = 1; j <= W; j++) {
      if (s[i][j] == '#') {
        cout << '#';
      } else {
        int count = 0;
        for (int h = i - 1; h <= i + 1; h++) {
          for (int w = j - 1; w <= j + 1; w++) {
            if (s[h][w] == '#') {
              // s[i][j] == '#'であることはないのでforループに含んでいる
              count++;
            }
          }
        }
        cout << (char)('0' + count);
      }
    }
    cout << endl;
  }

}

int main() {
  //answer1();
  answer2();
}


#include <bits/stdc++.h>
using namespace std;
#define double long double
#define REP(i,x,n) for(int i=x;i<(int)n;i++)
#define rep(i,n) REP(i,0,n)
#define sp(p) cout<<setprecision(16)<<fixed<<p<<endl;
#define all(a) a.begin(),a.end()
#define rall(a) a.rbegin(),a.rend()
#define SORT(a) sort(all(a))
#define RSORT(a) sort(rall(a))
#define UNIQ(a) unique(all(a))
#define vout(v) for(int i=0;i<(int)v.size()-1;i++){cout<<v[i]<<" ";}cout<<v[v.size()-1]<<"\n";
#define debg(a) cerr<<#a<<" "<<a<<endl;
#define show(a) for(cont &y:a){for(cont &x:y){cout<<x<<" ";}cout<<endl;}
template<class T>inline int out(const T &t){ print(t); putchar('\n'); return 0; }
template<class T>inline T gcd(T a,T b){if(b==0)return a; return(gcd(b,a%b));}
template<class T>inline T lcm(T a,T b){return a/gcd(a,b)*b;}
typedef long long ll;
typedef pair<ll,ll> P;
typedef vector<ll> V;
const long long MOD=1000000007;
const long long INF = 1e18;
vector <ll> dp;

void plus1(ll H, ll W, ll h, ll w, std::vector<std::string>& S){
    if (h<0 || w<0 || h>=H || w>=W) {return;}
    if (S[h][w]=='.') {
        S[h][w] = '1';
    } else if (S[h][w]!='#'){
        S[h][w] +=1;
    }
}

void solve(long long H, long long W, std::vector<std::string> S){
    for (ll i = 0; i < H; i++) {
        for (ll j = 0; j < W; j++) {
            if(S[i][j]=='.') { S[i][j]='0';}
            if(S[i][j]=='#') {
                plus1(H, W, i+1, j, S);
                plus1(H, W, i+1, j+1, S);
                plus1(H, W, i, j+1, S);
                plus1(H, W, i-1, j+1, S);
                plus1(H, W, i-1, j, S);
                plus1(H, W, i-1, j-1, S);
                plus1(H, W, i, j-1, S);
                plus1(H, W, i+1, j-1, S);
            }
        }
    }
    for (ll i = 0; i < H; i++) {
        cout << S[i] << "\n";
    }
}

int main(){
    long long H;
    scanf("%lld",&H);
    long long W;
    scanf("%lld",&W);
    std::vector<std::string> S(H);
    for(int i = 0 ; i < H ; i++){
        std::cin >> S[i];
    }
    solve(H, W, std::move(S));
    return 0;
}


#include <iostream>
#include <cstdlib>
#include <string>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <numeric>
#include <math.h>
#include <stdio.h>
#include <ctype.h>
#include <ios>
#include <iomanip>
using namespace std;

#define N_MAX   (100000)
#define LL_MAX_NUM (1LL<<60)
#define INF 1e7

typedef long long ll;
typedef long long int lli;

int main() {
	string s[52] = {}, yojo[52];
	int a, b, cnt = 0, yan;
	cin >> a >> b;
	for (int i = 1; i <= a; i++) {
		yojo[i] = "b";
		cin >> s[i];
		yojo[i] += s[i];
		yojo[i] += "b";
	}
	for (int i = 1; i <= a; i++) {
		for (int j = 1; j <= b; j++) {
			if (yojo[i][j] == '#') {
				cout << yojo[i][j];
			}
			else {
				if (yojo[i - 1][j - 1] == '#') {
					cnt++;
				}
				if (yojo[i - 1][j] == '#') {
					cnt++;
				}
				if (yojo[i - 1][j + 1] == '#') {
					cnt++;
				}
				if (yojo[i][j - 1] == '#') {
					cnt++;
				}
				if (yojo[i][j + 1] == '#') {
					cnt++;
				}
				if (yojo[i + 1][j - 1] == '#') {
					cnt++;
				}
				if (yojo[i + 1][j + 1] == '#') {
					cnt++;
				}
				if (yojo[i + 1][j] == '#') {
					cnt++;
				}
				cout << cnt;
			}
			cnt = 0;
		}
		cout << endl;
	}
	return 0;
}


#include <bits/stdc++.h>
using namespace std;

int main()
{
    int h,w;
    cin >> h >> w;
    char map[h][w];

    for(int i=0; i<h; i++)
    {
        for(int j=0; j<w; j++)
        {
            cin >> map[i][j];
        }
    }

    for(int i=0; i<h; i++)
    {
        for(int j=0; j<w; j++)
        {
            int count = 0;
            if(map[i][j]=='#')
            {
                cout << map[i][j];
                continue;
            }
            else if(i==0 && j==0)
            {
                if(map[i][j+1]=='#') count += 1;
                if(map[i+1][j]=='#') count += 1;
                if(map[i+1][j+1]=='#') count += 1;
            }
            else if(i==0 && j==w-1)
            {
                if(map[i][j-1]=='#') count += 1;
                if(map[i+1][j]=='#') count += 1;
                if(map[i+1][j-1]=='#') count += 1;
            }
            else if(j==0 && i==h-1)
            {
                if(map[i-1][j]=='#') count += 1;
                if(map[i][j+1]=='#') count += 1;
                if(map[i-1][j+1]=='#') count += 1;
            }
            else if(i==h-1 && j==w-1)
            {
                if(map[i][j-1]=='#') count += 1;
                if(map[i-1][j]=='#') count += 1;
                if(map[i-1][j-1]=='#') count += 1;
            }
            else if(i==0)
            {
                if(map[i][j-1]=='#') count += 1;
                if(map[i+1][j-1]=='#') count += 1;
                if(map[i+1][j]=='#') count += 1;
                if(map[i+1][j+1]=='#') count += 1;
                if(map[i][j+1]=='#') count += 1;
            }
            else if(j==0)
            {
                if(map[i-1][j]=='#') count += 1;
                if(map[i-1][j+1]=='#') count += 1;
                if(map[i][j+1]=='#') count += 1;
                if(map[i+1][j+1]=='#') count += 1;
                if(map[i+1][j]=='#') count += 1;
            }
            else if(i==h-1)
            {
                if(map[i][j-1]=='#') count += 1;
                if(map[i-1][j-1]=='#') count += 1;
                if(map[i-1][j]=='#') count += 1;
                if(map[i-1][j+1]=='#') count += 1;
                if(map[i][j+1]=='#') count += 1;
            }
            else if(j==w-1)
            {
                if(map[i-1][j]=='#') count += 1;
                if(map[i-1][j-1]=='#') count += 1;
                if(map[i][j-1]=='#') count += 1;
                if(map[i+1][j-1]=='#') count += 1;
                if(map[i+1][j]=='#') count += 1;
            }
            else
            {
                if(map[i-1][j-1]=='#') count += 1;
                if(map[i-1][j]=='#') count += 1;
                if(map[i-1][j+1]=='#') count += 1;
                if(map[i][j-1]=='#') count += 1;
                if(map[i][j+1]=='#') count += 1;
                if(map[i+1][j-1]=='#') count += 1;
                if(map[i+1][j]=='#') count += 1;
                if(map[i+1][j+1]=='#') count += 1;
            }

            cout << count;
        }
        cout << endl;
    }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

int main(){
    int m, n;
    cin >> m >> n;
    char arr[m][n];
    for(int i=0; i<m; i++){
        for(int j=0; j<n; j++){
            cin >> arr[i][j];
        }
    }
    int val{0};
    for(int i=0; i<m; i++){
        for(int j=0; j<n; j++){
            val = 0;
            if(arr[i][j] == '.'){
                if(j>0){
                if(arr[i][j-1]=='#'){
                        val++;
                }
                }
                if(j<(m-1)){
                if(arr[i][j+1]=='#'){
                        val++;
                }
                }
                if(i>0){
                    if(arr[i-1][j]=='#'){
                        val++;
                    }
                    if(j>0){
                        if(arr[i-1][j-1]=='#'){
                        val++;
                        }

                    }
                    if(j<(n-1)){
                        if(arr[i-1][j+1]=='#'){
                        val++;
                        }

                    }
                }
                if(i<(m-1)){
                    if(arr[i+1][j]=='#'){
                        val++;
                    }
                    if(j>0){
                        if(arr[i+1][j-1]=='#'){
                        val++;
                        }

                    }
                    if(j<(n-1)){
                        if(arr[i+1][j+1]=='#'){
                        val++;
                        }
                    }
                }
                val+=48;
                arr[i][j] = val;
            }
        }
    }
    for(int i=0; i<m; i++){
        for(int j=0; j<n; j++){
            cout << arr[i][j];
        }
        cout << endl;
    }
}


#include <bits/stdc++.h>
using namespace std;

int main(){
    int m, n;
    cin >> m >> n;
    char arr[m][n];
    for(int i=0; i<m; i++){
        for(int j=0; j<n; j++){
            cin >> arr[i][j];
        }
    }
    int val{0};
    for(int i=0; i<m; i++){
        for(int j=0; j<n; j++){
            val = 0;
            if(arr[i][j] == '.'){
                if(i>0){
                    if(arr[i-1][j]=='#'){
                        val++;
                    }
                    if(j>0){
                        if(arr[i-1][j-1]=='#'){
                        val++;
                        }
                        if(arr[i][j-1]=='#'){
                        val++;
                        }

                    }
                    if(j<(n-1)){
                        if(arr[i-1][j+1]=='#'){
                        val++;
                        }
                        if(arr[i][j+1]=='#'){
                        val++;
                        }
                    }
                }
                if(i<(m-1)){
                    if(arr[i+1][j]=='#'){
                        val++;
                    }
                    if(j>0){
                        if(arr[i+1][j-1]=='#'){
                        val++;
                        }

                    }
                    if(j<(n-1)){
                        if(arr[i+1][j+1]=='#'){
                        val++;
                        }
                    }
                }
                val+=48;
                arr[i][j] = val;
            }
        }
    }
    for(int i=0; i<m; i++){
        for(int j=0; j<n; j++){
            cout << arr[i][j];
        }
        cout << endl;
    }
}


#include <stdio.h>

int main(void) {
	int H, W;
	scanf("%d%d", &H, &W);
	char S[H][W];
	for (int i = 0; i < H; i++) {
		scanf("%s", S[i]);
	}

	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			if (S[i][j] == '#') {
				putchar('#');
			} else {
				int n = 0;
				for (int dy = -1; dy <= 1; dy++) {
					int y = i + dy;
					for (int dx = -1; dx <= 1; dx++) {
						int x = j + dx;
						if (y < 0 || y >= H || x < 0 || x >= W) {
							continue;
						}
						if (S[y][x] == '#') {
							n++;
						}
					}
				}
				putchar('0' + n);
			}
		}
		putchar('\n');
	}
	return 0;
}


#include<stdio.h>
int main(void)
{
  int h,w;
  char s[100][100];
  int result[100][100];

  scanf("%d %d\n",&h,&w);
  for(int i=0;i<h;i++){
    scanf("%s",s[i]);
  }

  for(int i=0;i<h;i++){
    for(int j=0;j<w;j++){
      result[i][j]=0;
    }
  }
  for(int i=0;i<h;i++){
    for(int j=0;j<w;j++){
      if(s[i][j]=='#'){
        result[i][j-1]++;
        result[i][j+1]++;
        result[i-1][j-1]++;
        result[i-1][j]++;
        result[i-1][j+1]++;
        result[i+1][j-1]++;
        result[i+1][j]++;
        result[i+1][j+1]++;
      }
    }
  }

  for(int i=0;i<h;i++){
    for(int j=0;j<w;j++){
      if(s[i][j]=='#'){
        printf("#");
      }else{
        printf("%d",result[i][j]);
      }
    }
    puts(" ");
  }
  return 0;
}


#include <stdio.h>

int main()
{
	int i, H, W;
	char S[52][52] = {};
	scanf("%d %d", &H, &W);
	for (i = 1; i <= H; i++) scanf("%s", &(S[i][1]));

	int j, k, l, count[52][52] = {};
	for (i = 1; i <= H; i++) {
		for (j = 1; j <= W; j++) {
			if (S[i][j] == '#') {
				for (k = -1; k <= 1; k++) {
					for (l = -1; l <= 1; l++) {
						if (S[i+k][j+l] == '.') count[i+k][j+l]++;
					}
				}
			}
		}
	}

	for (i = 1; i <= H; i++) {
		for (j = 1; j <= W; j++) {
			if (S[i][j] == '.') printf("%d", count[i][j]);
			else printf("#");
		}
		printf("\n");
	}
	fflush(stdout);
	return 0;
}


#include <stdio.h>
int main () {
  int h, w, i, j, k, l, temp;
  char s[50][50];
  char t[50][50];
  scanf ("%d%d", &h, &w);
  for (i = 0; i < h; ++i) {
    scanf ("%s", s[i]);
  }
  for (i = 0; i < h; ++i) {
    for (j = 0; j < w; ++j) {
      if (s[i][j] == '#') {
        t[i][j] = s[i][j];
      } else {
        temp = 0;
        for (k = i-1; k < i+2; ++k) {
          if (k == -1 || k == h) {
            continue;
          } else {
            for (l = j-1; l < j+2; ++l) {
              if (l == -1 || l == w) {
                continue;
              } else {
                if (s[k][l] == '#') {
                  temp += 1;
                }
              }
            }
          }
        }
        t[i][j] = '0' + temp;
      }
    }
  }
  for (i = 0; i < h; ++i) {
    t[i][w] = '\0';
    printf ("%s\n", t[i]);
  }
  return 0;
}


#include <bits/stdc++.h>
#define rep(i,n) for (int i = 0; i < (int)(n); ++i)
using namespace std;
using ll = long long;
using P = pair<int, int>;

int main(){
    int H, W;
    int count;

    cin >> H;
    cin >> W;

    char S[H][W];

    rep(i, H)
    {
        cin >> S[i];
    }

    rep(i, H)
    {
        rep(j, W){
            if (S[i][j] == '.'){
                count = 0;
                for (int k = -1; k < 2; k++)
                {
                    if((i + k > 0) && (i + k < H - 1)){
                        for (int l = -1; l < 2; l++)
                        {
                            if((j + l > 0) && (j + l < W - 1)){
                                if((k == 0) && (l == 0)){
                                }else{
                                    if(S[i + k][j + l] == '#') count++;
                                }
                            }
                        }
                    }
                }

                cout << count;
            }else{
                cout << '#';
            }
        }
        cout << endl;
    }

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int NumMine(vector<string> &data,int i,int j){
    int num = 0;
    if (i>0){
        if(j>0){
            if(data[i-1].at(j-1)=='#'){
                num++;
            }
        }
        if(data[i-1].at(j)=='#'){
            num++;
        }
        if(j<(data[i-1].length()-1)){
            if(data[i-1].at(j+1)=='#'){
                num++;
            }
        }
    }
    if(j>0){
        if(data[i].at(j-1)=='#'){
            num++;
        }
    }
    if(j<(data[i].length()-1)){
        if(data[i].at(j+1)=='#'){
            num++;
        }
    }

    if (i<(data.size()-1)){
        if(j>0){
            if(data[i+1].at(j-1)=='#'){
                num++;
            }
        }
        if(data[i+1].at(j)=='#'){
            num++;
        }
        if(j<(data[i+1].length()-1)){
            if(data[i+1].at(j+1)=='#'){
                num++;
            }
        }
    }
    return num;
}

int main(){
    int H, W;
    cin >> H >> W;

    vector<string> data(H);

    for (int i = 0; i < H;i++){
        cin >> data[i];
    }

    for (int i = 0; i < H;i++){
        for (int j = 0; j < W;j++){
            if(data[i].at(j)!='.'){
                continue;
            }else{
                data[i][j] = '0'+NumMine(data, i, j);
            }
        }
    }

    for (int i = 0; i < H;i++){
        cout << data[i] << endl;
    }
}


'use strict'
function Main(input){
  input = input.trim().split('\n');
  const hw = input.shift().split(' ').map((str)=> Number(str));
  const H  = hw[0], W = hw[1];
  const data = input.map(ls => ls.split(''));

  const hy = [-1, -1, -1, 0, 0, 1, 1, 1];
  const wx = [-1, 0, 1, -1, 1, -1, 0, 1];

  for(let i = 0; i < H; i++){
    for(let j = 0; j < W; j++){

      if(data[i][j] === '#') continue;

      let count = 0;
      for(let k = 0; k < 8; k++){
        const y = i + hy[k] , x = j + wx[k];
        if(y < 0 || H <= y) continue;
        if(x < 0 || W <= x) continue;

        if(data[y][x] === '#') {
          count += 1;
        }
      }
      data[i][j] = count;
    }
  }
  const result = data.map(ls => ls.join('')).join('\n');
  console.log(result);
}

//固定
Main(require("fs").readFileSync("/dev/stdin", "utf8"));


'use strict'

function main(s) {

  s = s.split('\n');
  const H = Number(s[0].split(' ')[0]);
  const W = Number(s[0].split(' ')[1]);
  const table = s.slice(1, -1).map(line => line.split(''));

  for (let h = 0; h < H; h++) {
    for (let w = 0; w < W; w++) {
      if (table[h][w] === '#') continue;

      let count = 0;

      // 上の行
      if (h >= 1) {

        // 左上
        if (w >= 1) {
          if (table[h - 1][w - 1] === '#') count += 1;
        }

        // 真上
        if (table[h - 1][w] === '#') count += 1;

        // 右上
        if (w < W - 1) {
          if (table[h - 1][w + 1] === '#') count += 1;
        }
      }

      // 該当行
      // 左
      if (w >= 1) {
        if (table[h][w - 1] === '#') count += 1;
      }

      // 右
      if (w < W - 1) {
        if (table[h][w + 1] === '#') count += 1;
      }

      // 下の行
      if (h < H - 1) {

        // 左下
        if (w >= 1) {
          if (table[h + 1][w - 1] === '#') count += 1;
        }

        // 真下
        if (table[h + 1][w] === '#') count += 1;

        // 右下
        if (w < W - 1) {
          if (table[h + 1][w + 1] === '#') count += 1;
        }
      }

      table[h][w] = count;
    }
  }

  const ans = table.map(line => line.join('')).join('\n');
  console.log(ans);
}

main(require("fs").readFileSync("/dev/stdin", "utf8"));


function getLineByParam( param ){
  var ret;
  for ( var i=0; i<param[0].length; i++ ) {
    if ( "\n" == param[0].charAt( i ) ) {
      ret = param[0].slice( 0, i );
      param[0] = param[0].slice( ret.length+1 );
      return ret;
    }
  }
  ret = param[0];
  param[0]="";
  return ret;
}

function countBomb( S, i, j ){
  if ( '#' === S[i][j] ) return '#';
  var cnt = 0;
  if ( 0 < i ) {
    if ( 0 < j && '#' === S[i-1][j-1] ) cnt++;
    if ( '#' === S[i-1][j] ) cnt++;
    if ( S[i].length - 1 > j && '#' === S[i-1][j+1] ) cnt++;
  }
  if ( 0 < j && '#' === S[i][j-1] ) cnt++;
  if ( S[i].length - 1 > j && '#' === S[i][j+1] ) cnt++;
  if ( S.length - 1 > i ) {
    if ( 0 < j && '#' === S[i+1][j-1] ) cnt++;
    if ( '#' === S[i+1][j] ) cnt++;
    if ( S[i].length - 1 > j && '#' === S[i+1][j+1] ) cnt++;
  }
  return cnt;
}

function Main(input) {
  input = [input];
  var tmp = getLineByParam(input).split(" ");
  var H = parseInt( tmp[0] );
  var W = parseInt( tmp[1] );
  var S = [];
  for ( var i=0; i<H; i++ ) {
    S[i] = [];
    tmp = getLineByParam(input).split("");
    for ( var j=0; j<W; j++ ) {
      S[i][j] = tmp[j];
    }
  }

  for ( var i=0; i<H; i++ ) {
    for ( var j=0; j<W; j++ ) {
      S[i][j] = countBomb( S, i, j );
    }
    console.log( S[i].join("") );
  }
}
Main(require("fs").readFileSync("/dev/stdin", "utf8"));


function*stdinIter(){const t=require("fs").readFileSync("/dev/stdin","utf-8").trim().split(/\n|\s/);yield*t}function readMany(t,e){const i=e||this.iter||(this.iter=stdinIter()),n=[];for(let e=0;e<t;e+=1)n.push(i.next().value);return n};

(() => {
    const [ h, w ] = readMany(2).map(it => parseInt(it))
    const s = []
    const map = []

    for (let i = 0; i < h; i += 1) {
        const tmp = readMany(1)[0].split('')
        s.push(tmp)
        map.push([])
    }

    const get = (arr, i, j) => {
        const tmp = arr[i]
        if (tmp) {
            return tmp[j]
        } else {
            return void 0
        }
    }

    for (let i = 0; i < h; i += 1) {
        for (let j = 0; j < w; j += 1) {
            if (s[i][j] == '#') {
                map[i][j] = '#'
                continue
            }

            let boms = 0
            if (get(s, i - 1, j) == '#') boms += 1
            if (get(s, i - 1, j + 1) == '#') boms += 1
            if (get(s, i - 1, j - 1) == '#') boms += 1
            if (get(s, i, j) == '#') boms += 1
            if (get(s, i, j + 1) == '#') boms += 1
            if (get(s, i, j - 1) == '#') boms += 1
            if (get(s, i + 1, j) == '#') boms += 1
            if (get(s, i + 1, j + 1) == '#') boms += 1
            if (get(s, i + 1, j - 1) == '#') boms += 1

            map[i][j] = boms
        }
    }

    console.log(map)
})()


/*
-------関数一覧--------
arr1dto2d(Array) 一次元配列を二次元配列にします
pf(N)素因数分解した結果をオブジェクトで返します
gcd(a,b)最大公約数を返します
lcm(a,b)最小公倍数を返します
num(a,b)a-bを返します。ソート用です
isPrime(n)素数かどうか真偽値で返します
isNumber(n)数かどうか真偽値で返します
arrsum(arr)配列の合計値を返します
nibu(arr,n)n以下で最も大きい数の添字を返します(nを含みます)
br(input)入力を改行で区切ります
*/
const debugMode = false;
const inf = Number.MAX_SAFE_INTEGER;
const mod = 1000000007;
function Main(input){
    input = input.split("\n");
    var mem = input[0].split(" ").map(Number);
    input.shift();
    input = arr1dto2d(input);
    for(var i=0;i<input.length;i++){
        input[i].push("^");
        input[i].unshift("^");
    }
    var p = new Array(mem[1]+2).fill("^");
    input.push(p);
    input.unshift(p);
    for(i=0;i<input[0].length;i++){
        for(var j=0;j<input.length;j++){
            if(input[i][j]=="."){
                var sum = 0;
                for(var k=-1;k<2;k++){
                    for(var l=-1;l<2;l++){
                        if(input[i+k][j+l]=="#")sum++;
                    }
                }
                input[i][j] = sum;
            }
        }
    }
    input.pop();
    input.shift();
    for(i=0;i<input.length;i++){
        input[i].pop();
        input[i].shift();
        input[i] = input[i].join("");
    }
    console.log(input.join("\n"));
}Main(require("fs").readFileSync("/dev/stdin", "utf8").trim());
function zisyozyunn(a){
  var arr = [];
  for(var i=0;i<input[0];i++){
    arr.push(i+1);
  }
  var sum = 0;
  for(var i=0;i<a.length;i++){
    var f = arr.findIndex(val => val==a[i]);
    sum += factorialize(a.length-1-i)*f;
    arr.splice(f,1);
  }
  return sum;
}
function arrsum(arr){
  var sum = 0;
  for (var i=0,len=arr.length; i<len; ++i) {
      sum += arr[i]-0;
  };
  return sum;
}
function debug(val){
  if(debugMode==true){
    console.log(val)
  }
}
function arrMaxPoint(arr){
	var max = Number.MIN_SAFE_INTEGER;
	var point = -1;
	for(var i=0;i<arr.length;i++){
		if(max<arr[i]){
			max = arr[i];
			point = i;
		}
	}
	return point;
}
function arrMinPoint(arr){
	var min = Number.MAX_SAFE_INTEGER;
	var point = -1;
	for(var i=0;i<arr.length;i++){
		if(min>arr[i]){
			min = arr[i];
			point = i;
		}
	}
	return point;
}
function arr1dto2d (arr){
	for(var i=0;i<arr.length;i++){
		arr[i]=arr[i].split("");
		}
	return arr;
}
function isPrime(n){
    if(false===Number.isInteger(n)){
        return false;
    }
    if(n<=1){
        return false;
    }
    if(2===n){
        return true;
    }
    if(0===n%2){
        return false;
    }
    var square_root = Math.floor(Math.sqrt(n));
    for(var i=3; i<=square_root; i+=2){
        if(0===n%i){
            return false;
        }
    }
    return true;
}
function isNumber(val){
	const pat = /^([1-9]\d*|0)$/;
	return pat.test(val);
}
function factorialize(num) {
  if (num === 0) { return 1; }
  return num * factorialize(num-1);
}
function rotate(array) {
  const ROW = array.length;
  const COL = array[0].length;
  const row = ROW-1;
  var a = new Array(COL);
  for (var c=0; c<COL; c++) {
    a[c] = new Array(ROW);
    for (var r=0; r<ROW; r++) {
      a[c][r] = array[row-r][c];
    }
  }
  return a;
}
function part_in(base,push,st){
	for(var i=st,p=0;p<push.length;i++,p++){
		base[i] = push[p];
	}
	return base;
}
function part_reverse(arr,s,g){
	var push = arr.slice(s-1,g);
  push.reverse();
	arr = part_in(arr,push,s-1);
	return arr;
}
function zeroPadding(num,length){
    return (num + '000000000000000000000000000000000').slice(0,length);
}
function arrsum(arr){
    var sum = 0;
    for (var i=0,len=arr.length; i<len; ++i) {
        sum += arr[i]-0;
    };
    return sum;
}
function pf(n) {
    var result = {};

    if (n === 1) {
        return {"1":1}
    }

    var init = 2;

    while (n !== 1) {
        var i = init;
        while (i < Number.MAX_SAFE_INTEGER) {
            if (n % i === 0) {
                n /= i;
                if (!(result[i] > 0)) {
                    result[i] = 0;
                }
                result[i]++;
                break;
            }
            i++;
        }
        init = i;
    }
    return result;
}
function gcd(a, b) {
    if (b === 0){
        return a
    }
    return gcd(b, a % b)
}
function lcm(a,b) {
    var g = (n, m) => m ? g(m, n % m) : n
    return a * b / g(a, b)
}
function num(a, b) {
  return a - b;
}
function nibu(a,searchValue){
	var index = -1;

//調べる左端を表す添字(index)
var left = 0;

//調べる右端を表す添字(index)
var right = a.length-1;

//左端と右端にデータがある間は処理を繰り返す
while(left <= right){

    //左右の真ん中を表す添字(index)
    middle =Math.floor((left +right)/2);

    //真ん中の値と探す値を比較する
    if(a[middle]==searchValue){
        //一致した場合、変数に入れて処理終了
        index = middle;
        break;
    }else if(a[middle]<searchValue){
        //探す値より小さい場合、左側にはもっと小さい値しかないので左端の値を真ん中の値の右に移動する
        left = middle +1;
    }else{
        //探す値より大きい場合、右側にはもっと大きい値しかないので右端の値を真ん中の値の左に移動する
        right = middle -1;
    }
}
if(index!=-1) return index;
else return left;
}
function br(input){
  return input.split("\n");
}
function is_sortred(arr){
  var flag = true;
  for(var i=1;i<arr.length;i++){
    if(arr[i-1]>arr[i]){
      flag = false;
      break;
    }
  }
  return flag;
}
function primeFactorization(n) {

	// 平方根を保存
	var s = Math.floor(Math.sqrt(n));

	var r = 0;

	var result = {};

	// 2から平方根までの素因数を求める
	for (var i = 2;i <= s;i++) {

		if ((n % i) == 0) {

			r = 0; // 指数カウンタクリア

			do {

				r++; // 指数カウンタプラス

				n = n / i;

			} while ((n % i) == 0);

			// 素因数iを指数とともに保存
			result[i]=r;

		}

	}

	// 残った素数を追加
	if (n > s) {
		result[n] = 1;
	}

	return result;

}


"use strict"

function Main(input) {
  input = input.trim().split('\n');
  const H = input[0].trim().split(' ').map(Number)[0];
  const W = input[0].trim().split(' ').map(Number)[1];
  const S = input.slice(1, W+1).map(val => val.trim().split(''));

  for(let h=0; h<H; h++){
    for(let w=0; w<W; w++){
      let tmp = S[h][w];
      if(tmp === '#'){
        if (h > 0) {
          if(w > 0) S[h-1][w-1] = S[h-1][w-1] === '.' ? 1 : S[h-1][w-1] === '#' ? '#' : S[h-1][w-1] + 1;
          S[h-1][w]   = S[h-1][w] === '.' ? 1 : S[h-1][w] === '#' ? '#' : S[h-1][w] + 1;
          if(w < W - 1) S[h-1][w+1] = S[h-1][w+1] === '.' ? 1 : S[h-1][w+1] === '#' ? '#' : S[h-1][w+1] + 1;
        }

        if (w > 0) {
          S[h][w-1]   = S[h][w-1] === '.' ? 1 : S[h][w-1] === '#' ? '#' : S[h][w-1] + 1;
        }

        if (w < W - 1) {
          S[h][w+1]   = S[h][w+1] === '.' ? 1 : S[h][w+1] === '#' ? '#' : S[h][w+1] + 1;
        }

        if (h < H - 1) {
          if(w > 0) S[h+1][w-1] = S[h+1][w-1] === '.' ? 1 : S[h+1][w-1] === '#' ? '#' : S[h+1][w-1] + 1;
          S[h+1][w]   = S[h+1][w] === '.' ? 1 : S[h+1][w] === '#' ? '#' : S[h+1][w] + 1;
          if(w < W - 1) S[h+1][w+1] = S[h+1][w+1] === '.' ? 1 : S[h+1][w+1] === '#' ? '#' : S[h+1][w+1] + 1;
        }
      }
    };
  };

  console.log(S.join('\n').replace(/,/g, '').replace(/\./g, '0'));
}
Main(require("fs").readFileSync("/dev/stdin", "utf8"));


package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"strconv"
)

var DEBUG = true

func main() {
	defer Flush()
	H := readi()
	W := readi()
	S := make([][]byte, H)
	for i := range S {
		S[i] = readb()
	}

	dy := []int{-1, -1, -1, 0, 0, 1, 1, 1}
	dx := []int{-1, 0, 1, -1, 1, -1, 0, 1}

	for i := range S {
		for j := range S[i] {
			if S[i][j] == '#' {
				continue
			}
			var t int
			for k := range dy {
				y := dy[k] + i
				x := dx[k] + j
				if y < 0 || H <= y || x < 0 || W <= x {
					continue
				}
				if S[y][x] == '#' {
					t++
				}
			}
			S[i][j] = '0' + byte(t)
		}
	}

	for i := range S {
		println(string(S[i]))
	}
}

// -----------------------------------------------------------------------------

// IO helper functions

// Returns next token from input.  It must be initialized by SetInput()
// before the first call.
var nextToken func() ([]byte, error)
var nextLine func() ([]byte, error)

// Holds a buffer for output.  It must be initialized by SetOutput().
// All IO fucntions (read*() and [e]print*()) should write to OutputWriter
// instead of this.
var OutputBuffer *bufio.Writer

// Holds an io.Writer.  It must be initialized by SetOutput()
var OutputWriter io.Writer

// Set IO functions for interactive input/output.
func SetInteractive(w io.Writer, r io.Reader) {
	SetUnbefferedInput(r)
	OutputBuffer = nil
	OutputWriter = w
}

// Setup OutputBuffer and OutputWriter.
func SetOutput(w io.Writer) {
	OutputBuffer = bufio.NewWriter(w)
	OutputWriter = OutputBuffer
}

// Flushes OutputBuffer
func Flush() {
	if OutputBuffer != nil {
		OutputBuffer.Flush()
	}
}

// Returns true if c is a white space
func IsSpace(c byte) bool {
	switch c {
	case '\t', '\n', '\v', '\f', '\r', ' ':
		return true
	}
	return false
}

func IsNewLine(c byte) bool {
	switch c {
	case '\n', '\r':
		return true
	}
	return false
}

// Setup nextToken with input buffer.
func SetInput(r io.Reader) {
	buf := new(bytes.Buffer)
	var b []byte

	var i int
	rest := func() ([]byte, error) {
		for i < len(b) && IsSpace(b[i]) {
			i++
		}
		if i == len(b) {
			return nil, io.ErrUnexpectedEOF
		}
		j := i
		for i < len(b) && !IsSpace(b[i]) {
			i++
		}
		return b[j:i], nil
	}
	initial := func() ([]byte, error) {
		io.Copy(buf, r)
		b = buf.Bytes()
		nextToken = rest
		return rest()
	}
	nextToken = initial

	restLn := func() ([]byte, error) {
		for i < len(b) && IsNewLine(b[i]) {
			i++
		}
		if i == len(b) {
			return nil, io.ErrUnexpectedEOF
		}
		j := i
		for i < len(b) && !IsNewLine(b[i]) {
			i++
		}
		return b[j:i], nil
	}

	initialLn := func() ([]byte, error) {
		io.Copy(buf, r)
		b = buf.Bytes()
		nextLine = restLn
		return restLn()
	}
	nextLine = initialLn
}

// Setup nextToken without input buffer.
func SetUnbefferedInput(r io.Reader) {
	buf := bufio.NewReader(r)
	var b []byte

	var i int
	nextToken = func() ([]byte, error) {
		var err error
		if i == len(b) {
			b, err = buf.ReadBytes('\n')
			if err != nil {
				return nil, err
			}
			i = 0
			j := len(b) - 1
			for 0 <= j && IsSpace(b[j]) {
				j--
			}
			b = b[0 : j+1]
		}
		for i < len(b) && IsSpace(b[i]) {
			i++
		}
		j := i
		for i < len(b) && !IsSpace(b[i]) {
			i++
		}
		if i == j {
			return nil, io.ErrUnexpectedEOF
		}
		return b[j:i], nil
	}
}

// -----------------------------------------------------------------------------

// IO functions

// Reads next token and return it as []byte
func readb() []byte {
	b, err := nextToken()
	if err != nil {
		panic(err)
	}
	return b[:len(b):len(b)]
}

// Reads next token and return it as string
func reads() string {
	return string(readb())
}

// Read next line as []byte.  Trailing '\n' will not be included.
// See also comments on readb()
func readbln() []byte {
	b, err := nextLine()
	if err != nil {
		panic(err)
	}
	return b[:len(b):len(b)]
}

// Read next line as string
func readsln() string {
	return string(readbln())
}

// Reads next token and return it as int64
func readll() int64 {
	i, err := strconv.ParseInt(reads(), 10, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

// Reads next token and return it as int
func readi() int {
	return int(readll())
}

// Reads next token and return it as float64
func readf() float64 {
	f, err := strconv.ParseFloat(reads(), 64)
	if err != nil {
		panic(err.Error())
	}
	return f
}

// Write args to OutputWriter with the format f
func printf(f string, args ...interface{}) (int, error) {
	return fmt.Fprintf(OutputWriter, f, args...)
}

// Write args to OutputWriter without format
func println(args ...interface{}) (int, error) {
	return fmt.Fprintln(OutputWriter, args...)
}

// Write args to stderr with the format f
func eprintf(f string, args ...interface{}) (int, error) {
	return fmt.Fprintf(os.Stderr, f, args...)
}

// Write args to stderr without format
func eprintln(args ...interface{}) (int, error) {
	return fmt.Fprintln(os.Stderr, args...)
}

func dbgf(f string, args ...interface{}) {
	if !DEBUG {
		return
	}
	fmt.Fprintf(os.Stderr, f, args...)
}

func dbg(args ...interface{}) {
	if !DEBUG {
		return
	}
	fmt.Fprintln(os.Stderr, args...)
}

// -----------------------------------------------------------------------------

// Utilities

func sumSlice(a []int) int {
	var res int
	for _, v := range a {
		res += v
	}
	return res
}

func sumSlicell(a []int64) int64 {
	var res int64
	for _, v := range a {
		res += v
	}
	return res
}

func readInts(N int) (int, []int) {
	if N == 0 {
		N = readi()
	}
	a := make([]int, N)
	for i := range a {
		a[i] = readi()
	}
	return N, a
}

func readIntsll(N int) (int, []int64) {
	if N == 0 {
		N = readi()
	}
	a := make([]int64, N)
	for i := range a {
		a[i] = readll()
	}
	return N, a
}

// -----------------------------------------------------------------------------

// Simple math functions

const (
	// big prime
	INF  = 1000000007
	INF2 = 1000000009
	INF3 = 998244353
)

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func minll(a, b int64) int64 {
	if a < b {
		return a
	}
	return b
}

func minf(a, b float64) float64 {
	if a < b {
		return a
	}
	return b
}

func max(a, b int) int {
	if a < b {
		return b
	}
	return a
}

func maxll(a, b int64) int64 {
	if a < b {
		return b
	}
	return a
}

func maxf(a, b float64) float64 {
	if a < b {
		return b
	}
	return a
}

func abs(a int) int {
	if a < 0 {
		return -a
	}
	return a
}

func absll(a int64) int64 {
	if a < 0 {
		return -a
	}
	return a
}

func absf(a float64) float64 {
	if a < 0 {
		return -a
	}
	return a
}

// egcd(a, b) returns d, x, y:
//   d is gcd(a,b)
//   x, y are  integers that satisfy ax + by = d
func egcd(a, b int) (int, int, int) {
	if b == 0 {
		return a, 1, 0
	}
	d, x, y := egcd(b, a%b)
	return d, y, x - a/b*y
}

func egcdll(a, b int64) (int64, int64, int64) {
	if b == 0 {
		return a, 1, 0
	}
	d, x, y := egcdll(b, a%b)
	return d, y, x - a/b*y
}

func gcd(a, b int) int {
	d, _, _ := egcd(a, b)
	return d
}

func gcdll(a, b int64) int64 {
	d, _, _ := egcdll(a, b)
	return d
}

// set up IO functions
func init() {
	// for non-interactive
	SetInput(os.Stdin)
	SetOutput(os.Stdout)

	// Enable below when interactive.  Its ok to leave above intact.
	// SetInteractive(os.Stdout, os.Stdin)
}


package main

import (
	"bufio"
	"os"
	"strconv"
)

var sc = bufio.NewScanner(os.Stdin)

func readInt() int {
	iv, _ := strconv.Atoi(readStr())
	return iv
}

func readStr() string {
	sc.Scan()
	return sc.Text()
}

func init() {
	sc.Split(bufio.ScanWords)
}

func main() {
	h, w := readInt(), readInt()
	s := make([]string, h)
	for i := range s {
		s[i] = readStr()
	}

	var wr = bufio.NewWriter(os.Stdout)
	mvx := []int{-1, 0, 1, -1, 1, -1, 0, 1}
	mvy := []int{1, 1, 1, 0, 0, -1, -1, -1}
	for i := range s {
		for j := range s[i] {
			if s[i][j] == '#' {
				wr.WriteString("#")
				continue
			}

			cnt := 0
			for k := 0; k < 8; k++ {
				if x, y := j+mvx[k], i+mvy[k]; x >= 0 && x < w && y >= 0 && y < h && s[y][x] == '#' {
					cnt++
				}
			}
			wr.WriteString(strconv.Itoa(cnt))
		}
		wr.WriteString("\n")
	}
	wr.Flush()
}


package main

import (
	"fmt"
	"os"
	"bufio"
)

type Directions int
const (
	up = iota
	upRight
	right
	downRight
	down
	downLeft
	left
	upLeft
)

type Area rune
const (
	Bomb = '#'
	Space = '.'
)

func main() {
	var H,W int
	input := bufio.NewScanner(os.Stdin)

	fmt.Scan(&H)
	area := make([]string,H)
	sampleArea:= make([]string,H)

	fmt.Scan(&W)

	for i := 0;i < H;i++ {
		input.Scan()
		sampleArea[i] = input.Text()
	}

	for y,str := range sampleArea {
		runeArray := make([]rune,W)
		for x,char := range str {
			if Bomb == char {
				runeArray[x] = Bomb
				continue
			}
			runeArray[x] = rune(countBomb(sampleArea,W,H,x,y) + '0')
		}
		area[y] = string(runeArray)
	}

	for _,str := range area {
		fmt.Println(str)
	}
}

func countBomb(area []string,xMax int,yMax int,x int,y int) int {
	var count int
	for dir := up;dir <= upLeft;dir++ {
		if look(Directions(dir),area,x,y) {
			count++
		}
	}
	return count
}

func look(direction Directions,area []string,x int,y int) bool{
	switch direction {
	case up:
		if 0 == y || Space == area[y - 1][x]{
			return false
		}
	case upRight:
		if len(area[y]) - 1 == x || 0 == y || Space ==  area[y - 1][x + 1] {
			return false
		}
	case right:
		if len(area[y]) - 1 == x || Space == area[y][x + 1] {
			return false
		}
	case downRight:
		if len(area[y]) - 1  == x || len(area) - 1 == y || Space == area[y + 1][x + 1] {
			return false
		}
	case down:
		if len(area) - 1 == y || Space == area[y + 1][x]{
			return false
		}
	case downLeft:
		if len(area) - 1 == y || 0 == x || Space == area[y + 1][x - 1] {
			return false
		}
	case left:
		if 0 == x || Space == area[y][x - 1] {
			return false
		}
	case upLeft:
		if 0 == x || 0 == y || Space == area[y - 1][x - 1] {
			return false
		}
	}
	return true
}


package main

import (
  "fmt"
  "strconv"
)

func main() {
  var h, w int
  fmt.Scan(&h, &w)

  grid := make([]string, h)
  for i := 0; i < h; i++ {
    fmt.Scan(&grid[i])
  }
  var cnt [50][50]int
  for i := 0; i < h; i++ {
    for j := 0; j < w; j++ {
      if grid[i][j] == '.' {continue}
      for dy := -1; dy < 2; dy++ {
        for dx := -1; dx < 2; dx++ {
          y, x := i + dy, j + dx
          if y < 0 || x < 0 {continue}
          cnt[y][x]++
        }
      }
    }
  }
  for i := 0; i < h; i++ {
    for j := 0; j < w; j++ {
      if grid[i][j] == '#' {
        fmt.Print("#")
      } else {
        fmt.Print(strconv.Itoa(cnt[i][j]))
      }
    }
    fmt.Print("\n")
  }
}


package main

import (
	"fmt"
	"strconv"
	"strings"
)

func main() {
	var H, W int
	fmt.Scanf("%d %d", &H, &W)
	S := make([][]string, H)
	for i := 0; i < H; i++ {
		var s string
		fmt.Scanf("%s", &s)
		S[i] = strings.Split(s, "")

	}
	for i := 0; i < H; i++ {
		for j := 0; j < W; j++ {
			if S[i][j] != "#" {
				S[i][j] = calc(S, i, j)
			}
		}
	}
	for i := 0; i < H; i++ {
		fmt.Println(strings.Join(S[i], ""))
	}
}

func sharp(s [][]string, i, j int) int {
	if i < 0 || len(s[0]) <= i || j < 0 || len(s) <= j {
		return 0
	}
	if s[i][j] == "#" {
		return 1
	}
	return 0
}

func calc(s [][]string, i, j int) string {
	ret := sharp(s, i-1, j-1)
	ret += sharp(s, i-1, j)
	ret += sharp(s, i-1, j+1)
	ret += sharp(s, i, j-1)
	ret += sharp(s, i, j+1)
	ret += sharp(s, i+1, j-1)
	ret += sharp(s, i+1, j)
	ret += sharp(s, i+1, j+1)
	r := strconv.Itoa(ret)
	return r
}


package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
	"unsafe"
)

func main() {
	var num, input = mrLine(1)
	var Y [][]int = make([][]int, num[1]+2)
	Y[0] = make([]int, num[1]+2)
	Y[num[1]+1] = make([]int, num[0]+2)

	var ans [][]int = make([][]int, num[1])
	for i := 0; i < num[1]; i++ {
		Y[i+1] = make([]int, num[0]+2)
		ans[i] = make([]int, num[0])

		for j := 0; j < num[0]; j++ {
			switch getRuneAt(input[j][0], i) {
			case []rune(".")[0]:
				Y[i+1][j+1] = 0
			default:
				Y[i+1][j+1] = 1
			}
		}
	}

	for i := 0; i < num[1]; i++ {
		for j := 0; j < num[0]; j++ {
			ans[i][j] = Y[i+1][j] + Y[i+1][j+2] + Y[i+2][j] + Y[i+2][j+2] + Y[i][j] + Y[i][j+2] + Y[i][j+1] + Y[i+2][j+1]
		}
	}
	for j := 0; j < num[0]; j++ {
		for i := 0; i < num[1]; i++ {
			if Y[i+1][j+1] == 1 {
				fmt.Printf("#")
			} else {
				fmt.Printf("%d", ans[i][j])
			}
		}
		fmt.Printf("\n")
	}

}

func getRuneAt(s string, i int) rune {
	rs := []rune(s)
	return rs[i]
}

func Sum(a, b int) int {
	return (a + b) * (b - a + 1) / 2
}

func permutation(n int, k int) int {
	v := 1
	if 0 < k && k <= n {
		for i := 0; i < k; i++ {
			v *= (n - i)
		}
	} else if k > n {
		v = 0
	}
	return v
}

func factorial(n int) int {
	return permutation(n, n-1)
}

func combination(n int, k int) int {
	return permutation(n, k) / factorial(k)
}

func homogeneous(n int, k int) int {
	return combination(n+k-1, k)
}

//round returns rounded integer number
func round(x float64) int {
	if x < float64(int(x))+0.5 {
		return int(x)
	}
	return int(x) + 1
}

//minf returns min{a, b}(a, b: float64)
func minf(a, b float64) float64 {
	if a > b {
		return b
	}
	return a
}

//mini returns min{a, b} (a, b: int)
func mini(a, b int) int {
	if a > b {
		return b
	}
	return a
}

//minf returns max{a, b}(a, b: float64)
func maxf(a, b float64) float64 {
	if a > b {
		return a
	}
	return b
}

//maxi returns max{a, b} (a, b: int)
func maxi(a, b int) int {
	if a > b {
		return a
	}
	return b
}

//pawf paw returns f^num(f:float64)
func pawf(f float64, num int) float64 {
	var result float64 = 1
	for i := 0; num > i; i++ {
		result *= f
	}
	return result
}

//pawi paw returns f^num(f:int)
func pawi(f int, num int) int {
	var result int = 1
	for i := 0; num > i; i++ {
		result *= f
	}
	return result
}

//rLine Read all standard input data
func rLine(line int) [][]string {
	var rdr = bufio.NewReaderSize(os.Stdin, 1000000)
	var buf = make([]byte, 0, 1000000)
	var stringInput [][]string

	for i := 0; i < line; {
		l, p, e := rdr.ReadLine()
		if e != nil {
			panic(e)
		}
		buf = append(buf, l...)
		if !p {
			stringInput = append(stringInput, strings.Split(strings.TrimSpace(*conByte(buf)), " "))
			buf = []byte{}
			i++
		}
	}
	return stringInput
}

//irLine Read Standard input data and convert into integer
func irLine(i int) [][]int {
	return alatois(rLine(i))
}

//mrLine Read multi-line standard input data
// put the location of data of the number of lines in a first line
//ex:
// 3 5
// 1 2
// 2 3
// 3 5
// you have to put 1, where the number 3 put in the first line
func mrLine(line int) (first []int, other [][]string) {
	var rdr = bufio.NewReaderSize(os.Stdin, 1000000)
	var buf = make([]byte, 0, 1000000)
	var Input []string
	var stringInput [][]string

	{
		l, p, e := rdr.ReadLine()
		if e != nil {
			panic(e)
		}
		buf = append(buf, l...)
		if !p {
			Input = strings.Split(strings.TrimSpace((*conByte(buf))), " ")
			buf = []byte{}
		}
	}

	first = atois(Input)

	for i := 0; i < first[line-1]; {
		l, p, e := rdr.ReadLine()
		if e != nil {
			panic(e)
		}
		buf = append(buf, l...)
		if !p {
			stringInput = append(stringInput, strings.Split(strings.TrimSpace((*conByte(buf))), " "))
			buf = []byte{}
			i++
		}
	}
	return first, stringInput
}

//mirLine  Read multi-line standard input data and convert into integer data
// put the location of data of the number of lines in a first line
//ex:
// 3 5
// 1 2
// 2 3
// 3 5
// you have to put 1, where the number 3 put in the first line
func mirLine(line int) (first []int, other [][]int) {
	var f, o = mrLine(line)
	return f, alatois(o)
}

//itoa converts string to integer
func atoi(s string) int {
	var i, _ = strconv.Atoi(s)
	return i
}

//itoas converts string slice to integer slice
func atois(S []string) []int {
	var result = make([]int, len(S))
	for i, s := range S {
		result[i] = atoi(s)
	}
	return result
}

//alitoas converts string 2 dimention slice to intger one
func alatois(S [][]string) [][]int {
	var result = make([][]int, len(S))
	for i, s := range S {
		result[i] = atois(s)
	}
	return result
}

func gcd(a, b int) int {
	if b == 0 {
		return a
	}
	return gcd(b, a%b)
}

func gcd3(a, b, c int) int {
	return gcd(gcd(a, b), c)
}

//medi3 return median of 3 intger values
func medi3(x, y, z int) int {
	switch {
	case x < y:
		switch {
		case x > z:
			return x
		case z > y:
			return y
		default:
			return z
		}
	default:
		switch {
		case z < y:
			return y
		case x < z:
			return x
		default:
			return z
		}
	}
}

//meds3 return median of 3 stringer values
func meds3(x, y, z string) string {
	switch {
	case x < y:
		switch {
		case x > z:
			return x
		case z > y:
			return y
		default:
			return z
		}
	default:
		switch {
		case z < y:
			return y
		case x < z:
			return x
		default:
			return z
		}
	}
}

//iQuicksort sort integer slice by quick sort
func iQuicksort(a []int, left, right int) {
	if left < right {
		var i, j, tmp int = left, right, 0
		var pivot int = medi3(a[i], a[i+(j-i)/2], a[j])

		for {
			for ; a[i] < pivot; i++ {
			}
			for ; pivot < a[j]; j-- {
			}
			if i >= j {
				break
			}
			tmp = a[i]
			a[i] = a[j]
			a[j] = tmp /* a[i], a[j] を交換 */
			i++
			j--
		}
		iQuicksort(a, left, i-1)  /* 分割した左を再帰的にソート */
		iQuicksort(a, j+1, right) /* 分割した右を再帰的にソート */
	}
}

//sQuicksort sort integer slice by quick sort
func sQuicksort(a []string, left, right int) {
	if left < right {
		var i, j int = left, right
		var tmp string
		var pivot string = meds3(a[i], a[i+(j-i)/2], a[j])

		for {
			for ; a[i] < pivot; i++ {
			}
			for ; pivot < a[j]; j-- {
			}
			if i >= j {
				break
			}
			tmp = a[i]
			a[i] = a[j]
			a[j] = tmp /* a[i], a[j] を交換 */
			i++
			j--
		}
		sQuicksort(a, left, i-1)  /* 分割した左を再帰的にソート */
		sQuicksort(a, j+1, right) /* 分割した右を再帰的にソート */
	}
}

//qiSort sort integer slie by quick sort
func qiSort(a []int) {
	iQuicksort(a, 0, len(a)-1)
}

//qsSort sort stringer slie by quick sort
func qsSort(a []string) {
	sQuicksort(a, 0, len(a)-1)
}

//conStr convert string into []byte by unsafe pointer
func conStr(s *string) []byte {
	return *(*[]byte)(unsafe.Pointer(s))
}

//conByte convert []byte into string by unsafe pointer
func conByte(b []byte) *string {
	return (*string)(unsafe.Pointer(&b))
}

//absi returns absolute integer number
func absi(a int) int {
	if a > 0 {
		return a
	}
	return -a

}

//absf returns absolute integer number
func absf(a float64) float64 {
	if a > 0 {
		return a
	}
	return -a

}


h,w=gets.split.map(&:to_i)
w+=1
src=$<.read
s=src.tr("#.\n","10").to_i 16
mask=src.tr("#.\n","f0").to_i 16
tmp=s
res= (t = (tmp << 4) + tmp + (tmp >> 4))+ ( t << 4*w) + (t >> 4*w)
res &=~tmp
res |= mask

puts sprintf("%0#{w*(h+2)}x\n",res).to_s.scan(/.{#{w}}/)[2..-1].map{|x|x.chop.tr(?f,?#)}


h,w = gets.split.map(&:to_i)
s = [" " * w]
h.times {s << " " + gets.chomp! + " "}
s << " " * w

1.upto(h) do |i|
    1.upto(w) do |j|
        next if s[i][j] == '#'
        s[i][j] = (s[i-1][j-1,3] + s[i][j-1,3] + s[i+1][j-1,3]).count('#').to_s
    end
end

puts s[1..h].map(&:strip)


H, W = gets.split.map(&:to_i)
result = Array.new(H){Array.new(W,0)}
H.times do |h|
  s = gets
  s.each_char.with_index do |c, w|
    if c == "#"
      if h != 0
        result[h-1][w-1] += 1 if w != 0
        result[h-1][w] += 1
        result[h-1][w+1] += 1 if w != W-1
      end
      result[h][w-1] += 1 if w != 0
      result[h][w] = -10
      result[h][w+1] += 1 if w != W-1
      if h != H-1
        result[h+1][w-1] += 1 if w != 0
        result[h+1][w] += 1
        result[h+1][w+1] += 1 if w != W-1
      end
    end
  end
end
result.each do |row|
  row.each do |cell|
    print(cell < 0 ? "#" : cell)
  end
  print("\n")
end


h, w = gets.split.map(&:to_i)
ss = h.times.map { gets.chomp!.chars }

dy = [-1, 0, 1, -1, 1, -1, 0, 1]
dx = [1, 1, 1, 0, 0, -1, -1, -1]

0.upto(h-1) do |i|
  0.upto(w-1) do |j|
    next if ss[i][j] == '#'

    ans = 0
    0.upto(7) do |k|
      ci = i + dy[k]
      cj = j + dx[k]

      next if ci < 0 || ci >= h || cj < 0 || cj >= w
      ans += 1 if ss[ci][cj] == '#'

      ss[i][j] = ans.to_s
    end
  end
end

ss.each do |s|
  puts s.join
end


h, w = gets.chomp.split.map(&:to_i)
strs = h.times.map { gets.chomp.chars }
res = Array.new(h).map{Array.new(w, 0)}

h.times do |i|
  w.times do |j|
    if strs[i][j] == '#'
      res[i][j] = '#'
    else
      count = 0
      count += 1 if i!=0 &&  j!=0      && strs[i-1][j-1] == '#'
      count += 1 if i!=0               && strs[i-1][j]   == '#'
      count += 1 if i!=0 &&  j < w-1   && strs[i-1][j+1] == '#'
      count += 1 if          j!=0      && strs[i][j-1]   == '#'
      count += 1 if          j < w-1   && strs[i][j+1]   == '#'
      count += 1 if i < h-1 && j!= 0   && strs[i+1][j-1] == '#'
      count += 1 if i < h-1            && strs[i+1][j]   == '#'
      count += 1 if i < h-1 && j < w-1 && strs[i+1][j+1] == '#'
      res[i][j] = count
    end
  end
end

puts res.each{ |line| puts line.join }


H, W = gets.chomp.split(" ").map(&:to_i)
strs = H.times.map{gets.chomp.chars}
res = Array.new(H).map{Array.new(W, 0)}

H.times do |i|
  W.times do |j|
    if strs[i][j] == '#'
      res[i][j] = '#'
    else
      count = 0
      count += 1 if i > 0   && j > 0   && strs[i-1][j-1] == '#'
      count += 1 if i > 0              && strs[i-1][j]   == '#'
      count += 1 if i > 0   && j < W-1 && strs[i-1][j+1] == '#'
      count += 1 if            j > 0   && strs[i][j-1] == '#'
      count += 1 if            j < W-1 && strs[i][j+1] == '#'
      count += 1 if i < H-1 && j > 0   && strs[i+1][j-1] == '#'
      count += 1 if i < H-1 && j > 0   && strs[i+1][j] == '#'
      count += 1 if i < H-1 && j < W-1 && strs[i+1][j+1] == '#'
      res[i][j] = count
    end
  end
end

res.each { |line| puts line.join }


use std::io;

fn procon_read<T: std::str::FromStr>() ->  Vec<T> {
	let mut buf = String::new();
	io::stdin().read_line(&mut buf).expect("");
	let iter = buf.split_whitespace();
	let mut v: Vec<T> = Vec::new();
	for i in iter {
		v.push(i.parse().ok().unwrap());
	}
	v
}

fn main() {
	let v:Vec<i32> = procon_read();
	let h = v[0];
	let w = v[1];
	let mut s:Vec<Vec<char>> = Vec::new();
	let mut t:Vec<Vec<i32>> = Vec::new();
	for i in 0..h {
		let mut buf = String::new();
		io::stdin().read_line(&mut buf).expect("");
		let mut v1:Vec<char> = buf.trim().chars().collect();
		s.push(v1);
		t.push(Vec::new());
	}
	for i in 0..h {
		let mut cnt = 0;
		for j in 0..w {
			if s[i as usize][j as usize] == '.' {
				if j > 0 {
					// left
					if s[i as usize][(j-1) as usize] == '#' {
						cnt += 1;
					}
				}
				if i > 0 {
					// above
					if s[(i-1) as usize][j as usize] == '#' {
						cnt += 1;
					}
				}
				if i > 0 && j > 0 {
					// left and above
					if s[(i-1) as usize][(j - 1) as usize] == '#' {
						cnt += 1;
					}
				}
				if i < h-1 && j > 0 {
					// left and below
					if s[(i+1) as usize][(j-1) as usize] == '#' {
						cnt += 1;
					}
				}
				if j < w-1 {
					// right
					if s[i as usize][(j+1) as usize] == '#' {
						cnt += 1;
					}
				}
				if i < h-1 {
					// below
					if s[(i+1) as usize][j as usize] == '#' {
						cnt += 1;
					}
				}
				if i > 0 && j < w - 1 {
					// right and above
					if s[(i-1) as usize][(j + 1) as usize] == '#' {
						cnt += 1;
					}
				}
				if i < h-1 && j < w - 1 {
					// left and below
					if s[(i+1) as usize][(j+1) as usize] == '#' {
						cnt += 1;
					}
				}
				t[i as usize].push(cnt);
			}else{
				t[i as usize].push(-1);
			}
			cnt = 0;
		}
	}
	for i in 0..h {
		for j in 0..w {
			if t[i as usize][j as usize] == -1 {
				print!("#");
			}else{
				print!("{}", t[i as usize][j as usize]);
			}
		}
		println!("");
	}
}


macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
    ($($r:tt)*) => {
        let mut s = {
            use std::io::Read;
            let mut s = String::new();
            std::io::stdin().read_to_string(&mut s).unwrap();
            s
        };
        let mut iter = s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
}

macro_rules! input_inner {
    ($iter:expr) => {};
    ($iter:expr, ) => {};

    ($iter:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($iter, $t);
        input_inner!{$iter $($r)*}
    };
}

macro_rules! read_value {
    ($iter:expr, ( $($t:tt),* )) => {
        ( $(read_value!($iter, $t)),* )
    };

    ($iter:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($iter, $t)).collect::<Vec<_>>()
    };

    ($iter:expr, chars) => {
        read_value!($iter, String).chars().collect::<Vec<char>>()
    };

    ($iter:expr, usize1) => {
        read_value!($iter, usize) - 1
    };

    ($iter:expr, $t:ty) => {
        $iter.next().unwrap().parse::<$t>().expect("Parse error")
    };
}

fn main() {
    input!{
        h: usize,
        w: usize,
        ss: [String; h],
    };
    let s = ss.iter().map(|s| s.chars().collect::<Vec<_>>()).collect::<Vec<_>>();

    for i in 0..h{
        for j in 0..w{
            if s[i][j] == '.'{
                let sx = if j == 0{0}else{j-1};
                let ex = if j == w-1{w-1}else{j+1};
                let sy = if i == 0{0}else{i-1};
                let ey = if i == h-1{h-1}else{i+1};
                // println!("{},{},{},{},{},{}",i,j,sx,sy,ex,ey);
                let mut count = 0;
                for x in sx..ex+1{
                    for y in sy..ey+1{
                        if s[y][x] == '#'{
                            count += 1;
                        }
                    }
                }
                print!("{}", count);
            }
            else {
                print!("#" );
            }
        }
        println!("")
    }

}


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

fn main() {
    let (h, w) = {
        let mut buf = String::new();
        std::io::stdin().read_line(&mut buf).ok();
        let v = buf
            .trim()
            .split_whitespace()
            .map(|e| e.trim().parse().ok().unwrap())
            .collect::<Vec<usize>>();
        (v[0], v[1])
    };

    let mut s: Vec<Vec<char>> = (0..h).map(|_| read::<String>().chars().collect()).collect();

    let bom: char = "#".to_owned().chars().next().unwrap();
    for i in 0..h {
        for j in 0..w {
            if s[i][j] == bom {
                print!("{}", bom);
                continue;
            }
            let mut cnt = 0;
            if i > 0 {
                if j > 0 {
                    if s[i - 1][j - 1] == bom {
                        cnt += 1;
                    }
                }

                if s[i - 1][j] == bom {
                    cnt += 1;
                }

                if j < w - 1 {
                    if s[i - 1][j + 1] == bom {
                        cnt += 1;
                    }
                }
            }

            if j > 0 {
                if s[i][j - 1] == bom {
                    cnt += 1;
                }
            }

            if j < w - 1 {
                if s[i][j + 1] == bom {
                    cnt += 1;
                }
            }

            if i < h - 1 {
                if j > 0 {
                    if s[i + 1][j - 1] == bom {
                        cnt += 1;
                    }
                }

                if s[i + 1][j] == bom {
                    cnt += 1;
                }

                if j < w - 1 {
                    if s[i + 1][j + 1] == bom {
                        cnt += 1;
                    }
                }
            }
            print!("{}", cnt.to_string());
        }
        println!();
    }
}


use std::io;

fn main() {
    let (h, w) = input_hw();

    let field = input_field(h);
    let minesweeper_field = generate_minesweeper_field(h, w, &field);

    for line in minesweeper_field {
        for s in line {
            print!("{}", s);
        }
        println!();
    }

}

fn input() -> String {
    let mut s = String::new();
    io::stdin().read_line(&mut s).expect("panic input hw");
    s
}

fn parse_vec_i32(s: String) -> Vec<i32> {
     s.split_whitespace()
    .map(|s| s.parse().expect("panic parse"))
    .collect()
}

fn input_hw() -> (i32, i32) {
    let s = input();
    let hw = parse_vec_i32(s);

    (hw[0], hw[1])
}

fn input_field(h: i32) -> Vec<Vec<String>> {
    let mut field: Vec<Vec<String>> = Vec::new();

    for _ in 0..h {
        let line = input();
        let line = line.chars().map(|c| c.to_string()).collect();
        field.push(line);
    }

    field
}

fn generate_minesweeper_field(h: i32, w: i32, field: &Vec<Vec<String>>) -> Vec<Vec<String>>{
    let mut mineswepper_field: Vec<Vec<String>> = Vec::new();

    for i in 0..h {
        let mut line: Vec<String> = Vec::new();

        for j in 0..w {
            let trout = generate_trout(i as usize, j as usize, h, w, &field);
            line.push(trout);
       }

        mineswepper_field.push(line)
    }

    mineswepper_field
}

fn generate_trout(i: usize, j: usize, h: i32, w:i32, field: &Vec<Vec<String>>) -> String {
    let field_trout = &field[i][j];

    if is_bomb(field_trout) {
        return "#".to_string();
    }

    let top = i as i32 - 1;
    let right = j + 1;
    let bottom = i + 1;
    let left = j as i32 - 1;

    println!("{} {} {} {}", top, right, bottom, left);

    let top_safe = top >= 0;
    let right_safe = right < w as usize;
    let bottom_safe = bottom < h as usize;
    let left_safe = left >= 0;

    println!("{} {} {} {}", top_safe, right_safe, bottom_safe, left_safe);

    let mut around_bomb_count = 0;
    let mut increment = || around_bomb_count += 1;

    if top_safe {
        let top = top as usize;
        let left = left as usize;

        if is_bomb(&field[top][j]) {
            increment();
        }

        if left_safe && is_bomb(&field[top][left]) {
            increment();
        }

        if right_safe && is_bomb(&field[top][right]) {
            increment();
        }

    }

    if bottom_safe {
        let bottom = bottom as usize;
        let left = left as usize;

        if is_bomb(&field[bottom][j]) {
            increment();
        }

        if left_safe && is_bomb(&field[bottom][left]) {
            increment();
        }

        if right_safe && is_bomb(&field[bottom][right]) {
            increment();
        }
    }

    if right_safe {
        if is_bomb(&field[i][right]) {
            around_bomb_count += 1;
        }
    }

    if left_safe {
        let left = left as usize;

        if is_bomb(&field[i][left]) {
            around_bomb_count += 1;
        }
    }

    around_bomb_count.to_string()
}

fn is_bomb(s: &String) -> bool {
    s == "#"
}


use std::io;

fn main() {
    let (h, w) = input_hw();

    let field = input_field(h);
    let minesweeper_field = generate_minesweeper_field(h, w, &field);

    for line in minesweeper_field {
        for s in line {
            print!("{}", s);
        }
        println!();
    }

}

fn input() -> String {
    let mut s = String::new();
    io::stdin().read_line(&mut s).expect("panic input hw");
    s
}

fn parse_vec_i32(s: String) -> Vec<i32> {
     s.split_whitespace()
    .map(|s| s.parse().expect("panic parse"))
    .collect()
}

fn input_hw() -> (i32, i32) {
    let s = input();
    let hw = parse_vec_i32(s);

    (hw[0], hw[1])
}

fn input_field(h: i32) -> Vec<Vec<String>> {
    let mut field: Vec<Vec<String>> = Vec::new();

    for _ in 0..h {
        let line = input();
        let line = line.chars().map(|c| c.to_string()).collect();
        field.push(line);
    }

    field
}

fn generate_minesweeper_field(h: i32, w: i32, field: &Vec<Vec<String>>) -> Vec<Vec<String>>{
    let mut mineswepper_field: Vec<Vec<String>> = Vec::new();

    for i in 0..h {
        let mut line: Vec<String> = Vec::new();

        for j in 0..w {
            let trout = generate_trout(i as usize, j as usize, h, w, &field);
            line.push(trout);
       }

        mineswepper_field.push(line)
    }

    mineswepper_field
}

fn generate_trout(i: usize, j: usize, h: i32, w:i32, field: &Vec<Vec<String>>) -> String {
    let field_trout = &field[i][j];

    if is_bomb(field_trout) {
        return "#".to_string();
    }

    let top = i as i32 - 1;
    let right = j + 1;
    let bottom = i + 1;
    let left = j as i32 - 1;

    let top_safe = top >= 1;
    let right_safe = right < w as usize;
    let bottom_safe = bottom < h as usize;
    let left_safe = left >= 0;

    let mut around_bomb_count = 0;
    let mut increment = || around_bomb_count += 1;

    if top_safe {
        let top = top as usize;
        let left = left as usize;

        if is_bomb(&field[top][j]) {
            increment();
        }

        if left_safe && is_bomb(&field[top][left]) {
            increment();
        }

        if right_safe && is_bomb(&field[top][right]) {
            increment();
        }

    }

    if bottom_safe {
        let bottom = bottom as usize;
        let left = left as usize;

        if is_bomb(&field[bottom][j]) {
            increment();
        }

        if left_safe && is_bomb(&field[bottom][left]) {
            increment();
        }

        if right_safe && is_bomb(&field[bottom][right]) {
            increment();
        }
    }

    if right_safe {
        if is_bomb(&field[i][right]) {
            around_bomb_count += 1;
        }
    }

    if left_safe {
        let left = left as usize;

        if is_bomb(&field[i][left]) {
            around_bomb_count += 1;
        }
    }

    around_bomb_count.to_string()
}

fn is_bomb(s: &String) -> bool {
    s == "#"
}


import Foundation

#if swift(>=4.0)
extension String {
    func split(by separator: String) -> [String] {
        return self.components(separatedBy: separator)
    }
    func toArray() -> [String] {
        return self.map{String($0)}
    }
}
func exponentiate(_ lhs: Int, _ rhs: Int) -> Int {
    return (0..<rhs).reduce(1){i,_ in i*lhs}
}
#else
extension String {
    func split(by separator: String) -> [String] {
        return self.componentsSeparatedByString(separator)
    }
    var count: Int {
        return self.characters.count
    }
    func toArray() -> [String] {
        return self.characters.map{String($0)}
    }
    func uppercased() -> String {
        return self.uppercaseString
    }
    func lowercased() -> String {
        return self.lowercaseString
    }
}
//extension Array where Element == String {
//    func joined(separator separator: String) -> String {
//        return self.joinWithSeparator(separator)
//    }
//}
extension Array where Element: Comparable {
    func max() -> Element {
        return self.maxElement()!
    }
    func min() -> Element {
        return self.minElement()!
    }
    func sorted() -> Array {
        return self.sort()
    }
    func reversed() -> Array {
        return self.reverse()
    }
    mutating func sort() {
        self.sortInPlace()
    }
}
extension Array {
    init(repeating: Element, count: Int) {
        self.init(count: count, repeatedValue: repeating)
    }
}
func stride<T: Strideable>(from start: T, to end: T, by stride: T.Stride) -> StrideTo<T> {
    return start.stride(to: end, by: stride)
}
func exponentiate(lhs: Int, _ rhs: Int) -> Int {
    return (0..<rhs).reduce(1){i,_ in i*lhs}
}
#endif
func readInt() -> Int? {
    return Int(readLine()!)
}
func readStringSplit(by separator: String) -> [String] {
    return readLine()!.split(by: separator)
}
func readIntSplit(by separator: String) -> [Int] {
    return readLine()!.split(by: separator).map{Int($0)!}
}

/*************** テストスペース ***************/

//var min, min2, count: Int!
//for i in 1...10 {
//    let x = Int(readLine()!)!
//    if i == 1 {
//        min = x
//        count = 1
//    } else if x < min {
//        min2 = min
//        min = x
//        count = 1
//    } else if x == min && count == 1 {
//        min2 = x
//        count = 2
//    }
//}
//print(min2)

/*************** メインプログラム ***************/

let input = readIntSplit(by: " ")
let (H, W) = (input[0], input[1])
var map = [[String]]()
for _ in 0..<H {
    map += [readLine()!.toArray()]
}
for i in 0..<H {
    for j in 0..<W {
        if map[i][j] == "." {
            var bomb = 0
            for h in -1...1 {
                for w in -1...1 {
                    if i+h>=0 && i+h<H && j+w>=0 && j+w<W {
                        if map[i+h][j+w] == "#" {
                            bomb += 1
                        }
                    }
                }
            }
            map[i][j] = String(bomb)
        }
    }
}
for i in 0..<H {
    print(map[i].joinWithSeparator(""))
}


import Foundation
func toTuple<T>(_ args: [T]) -> (T, T) { (args[0], args[1]) }
func readInts() -> [Int] { readLine()!.split(separator: " ").map { Int($0)! } }

let (h, w) = toTuple(readInts())
var si: [[String]] = []
for _ in 0..<h {
  let s = readLine()!.map { String($0) }
  si.append(s)
}
var ans: [[String]] = []
for i in 0..<h {
  var row: [String] = []
  for j in 0..<w {
    guard si[i][j] != "#" else {
      row.append("#")
      continue
    }
    var count = 0
    if i - 1 >= 0 , j - 1 >= 0 , si[i-1][j-1] == "#" {
      count += 1
    }
    if i - 1 >= 0 , si[i-1][j] == "#" {
      count += 1
    }
    if i - 1 >= 0 , j + 1 < w , si[i-1][j+1] == "#" {
      count += 1
    }
    if j + 1 < w , si[i][j+1] == "#" {
      count += 1
    }
    if i + 1 < h , j + 1 < w , si[i+1][j+1] == "#" {
      count += 1
    }
    if i + 1 < h , si[i+1][j] == "#" {
      count += 1
    }
    if i + 1 < h , j - 1 >= 0 , si[i+1][j-1] == "#" {
      count += 1
    }
    if j - 1 >= 0 , si[i][j-1] == "#" {
      count += 1
    }
    row.append(String(count))
  }
  ans.append(row)
}
ans.forEach {
  print($0.joined())
}


import Foundation

#if swift(>=4.0)
extension String {
    func split(by separator: String) -> [String] {
        return self.components(separatedBy: separator)
    }
    func toArray() -> [String] {
        return self.map{String($0)}
    }
}
func exponentiate(_ lhs: Int, _ rhs: Int) -> Int {
    return (0..<rhs).reduce(1){i,_ in i*lhs}
}
#else
extension String {
    func split(by separator: String) -> [String] {
        return self.componentsSeparatedByString(separator)
    }
    var count: Int {
        return self.characters.count
    }
    func toArray() -> [String] {
        return self.characters.map{String($0)}
    }
    func uppercased() -> String {
        return self.uppercaseString
    }
    func lowercased() -> String {
        return self.lowercaseString
    }
}
//extension Array where Element == String {
//    func joined(separator separator: String) -> String {
//        return self.joinWithSeparator(separator)
//    }
//}
extension Array where Element: Comparable {
    func max() -> Element {
        return self.maxElement()!
    }
    func min() -> Element {
        return self.minElement()!
    }
    func sorted() -> Array {
        return self.sort()
    }
    func reversed() -> Array {
        return self.reverse()
    }
    mutating func sort() {
        self.sortInPlace()
    }
}
extension Array {
    init(repeating: Element, count: Int) {
        self.init(count: count, repeatedValue: repeating)
    }
}
func stride<T: Strideable>(from start: T, to end: T, by stride: T.Stride) -> StrideTo<T> {
    return start.stride(to: end, by: stride)
}
func exponentiate(lhs: Int, _ rhs: Int) -> Int {
    return (0..<rhs).reduce(1){i,_ in i*lhs}
}
#endif
func readInt() -> Int? {
    return Int(readLine()!)
}
func readStringSplit(by separator: String) -> [String] {
    return readLine()!.split(by: separator)
}
func readIntSplit(by separator: String) -> [Int] {
    return readLine()!.split(by: separator).map{Int($0)!}
}

/*************** テストスペース ***************/

//var min, min2, count: Int!
//for i in 1...10 {
//    let x = Int(readLine()!)!
//    if i == 1 {
//        min = x
//        count = 1
//    } else if x < min {
//        min2 = min
//        min = x
//        count = 1
//    } else if x == min && count == 1 {
//        min2 = x
//        count = 2
//    }
//}
//print(min2)

/*************** メインプログラム ***************/

let input = readIntSplit(by: " ")
let (H, W) = (input[0], input[1])
var map = [[String]]()
for _ in 0..<H {
    map += [readLine()!.toArray()]
}
for i in 0..<H {
    for j in 0..<W {
        if map[i][j] == "." {
            var bomb = 0
            for h in -1...1 {
                for w in -1...1 {
                    if i+h>=0 && i+h<H-1 && j+w>=0 && j+w<W-1 {
                        if map[i+h][j+w] == "#" {
                            bomb += 1
                        }
                    }
                }
            }
            map[i][j] = String(bomb)
        }
    }
}
for i in 0..<H {
    print(map[i].joinWithSeparator(""))
}


import Foundation

#if swift(>=4.0)
extension String {
    func split(by separator: String) -> [String] {
        return self.components(separatedBy: separator)
    }
    func toArray() -> [String] {
        return self.map{String($0)}
    }
}
func exponentiate(_ lhs: Int, _ rhs: Int) -> Int {
    return (0..<rhs).reduce(1){i,_ in i*lhs}
}
#else
extension String {
    func split(by separator: String) -> [String] {
        return self.componentsSeparatedByString(separator)
    }
    var count: Int {
        return self.characters.count
    }
    func toArray() -> [String] {
        return self.characters.map{String($0)}
    }
    func uppercased() -> String {
        return self.uppercaseString
    }
    func lowercased() -> String {
        return self.lowercaseString
    }
}
//extension Array where Element == String {
//    func joined(separator separator: String) -> String {
//        return self.joinWithSeparator(separator)
//    }
//}
extension Array where Element: Comparable {
    func max() -> Element {
        return self.maxElement()!
    }
    func min() -> Element {
        return self.minElement()!
    }
    func sorted() -> Array {
        return self.sort()
    }
    func reversed() -> Array {
        return self.reverse()
    }
    mutating func sort() {
        self.sortInPlace()
    }
}
extension Array {
    init(repeating: Element, count: Int) {
        self.init(count: count, repeatedValue: repeating)
    }
}
func stride<T: Strideable>(from start: T, to end: T, by stride: T.Stride) -> StrideTo<T> {
    return start.stride(to: end, by: stride)
}
func exponentiate(lhs: Int, _ rhs: Int) -> Int {
    return (0..<rhs).reduce(1){i,_ in i*lhs}
}
#endif
func readInt() -> Int? {
    return Int(readLine()!)
}
func readStringSplit(by separator: String) -> [String] {
    return readLine()!.split(by: separator)
}
func readIntSplit(by separator: String) -> [Int] {
    return readLine()!.split(by: separator).map{Int($0)!}
}

/*************** テストスペース ***************/

//var min, min2, count: Int!
//for i in 1...10 {
//    let x = Int(readLine()!)!
//    if i == 1 {
//        min = x
//        count = 1
//    } else if x < min {
//        min2 = min
//        min = x
//        count = 1
//    } else if x == min && count == 1 {
//        min2 = x
//        count = 2
//    }
//}
//print(min2)

/*************** メインプログラム ***************/

let input = readIntSplit(by: " ")
let (H, W) = (input[0], input[1])
var map = [[String]]()
for _ in 0..<H {
    map += [readLine()!.toArray()]
}
for i in 0..<H {
    for j in 0..<W {
        if map[i][j] == "." {
            var bomb = 0
            for h in -1...1 {
                for w in -1...1 {
                    if (i+h>0 || i+h<H-1) && (j+w>0 || j+w<W-1) {
                        if map[i+h][j+w] == "#" {
                            bomb += 1
                        }
                    }
                }
            }
            map[i][j] = String(bomb)
        }
    }
}
for i in 0..<H {
    print(map[i].joinWithSeparator(""))
}


import Foundation

#if swift(>=4.0)
extension String {
    func split(by separator: String) -> [String] {
        return self.components(separatedBy: separator)
    }
    func toArray() -> [String] {
        return self.map{String($0)}
    }
}
func exponentiate(_ lhs: Int, _ rhs: Int) -> Int {
    return (0..<rhs).reduce(1){i,_ in i*lhs}
}
#else
extension String {
    func split(by separator: String) -> [String] {
        return self.componentsSeparatedByString(separator)
    }
    var count: Int {
        return self.characters.count
    }
    func toArray() -> [String] {
        return self.characters.map{String($0)}
    }
    func uppercased() -> String {
        return self.uppercaseString
    }
    func lowercased() -> String {
        return self.lowercaseString
    }
}
//extension Array where Element == String {
//    func joined(separator separator: String) -> String {
//        return self.joinWithSeparator(separator)
//    }
//}
extension Array where Element: Comparable {
    func max() -> Element {
        return self.maxElement()!
    }
    func min() -> Element {
        return self.minElement()!
    }
    func sorted() -> Array {
        return self.sort()
    }
    func reversed() -> Array {
        return self.reverse()
    }
    mutating func sort() {
        self.sortInPlace()
    }
}
extension Array {
    init(repeating: Element, count: Int) {
        self.init(count: count, repeatedValue: repeating)
    }
}
func stride<T: Strideable>(from start: T, to end: T, by stride: T.Stride) -> StrideTo<T> {
    return start.stride(to: end, by: stride)
}
func exponentiate(lhs: Int, _ rhs: Int) -> Int {
    return (0..<rhs).reduce(1){i,_ in i*lhs}
}
#endif
func readInt() -> Int? {
    return Int(readLine()!)
}
func readStringSplit(by separator: String) -> [String] {
    return readLine()!.split(by: separator)
}
func readIntSplit(by separator: String) -> [Int] {
    return readLine()!.split(by: separator).map{Int($0)!}
}

/*************** テストスペース ***************/

//var min, min2, count: Int!
//for i in 1...10 {
//    let x = Int(readLine()!)!
//    if i == 1 {
//        min = x
//        count = 1
//    } else if x < min {
//        min2 = min
//        min = x
//        count = 1
//    } else if x == min && count == 1 {
//        min2 = x
//        count = 2
//    }
//}
//print(min2)

/*************** メインプログラム ***************/

let input = readIntSplit(by: " ")
let (H, W) = (input[0], input[1])
var map = [[String]]()
for _ in 0..<H {
    map += [readLine()!.toArray()]
}
for i in 0..<H {
    for j in 0..<W {
        if map[i][j] == "." {
            var bomb = 0
            for h in -1...1 {
                for w in -1...1 {
                    if i+h>0 && i+h<H-1 && j+w>0 && j+w<W-1 {
                        if map[i+h][j+w] == "#" {
                            bomb += 1
                        }
                    }
                }
            }
            map[i][j] = String(bomb)
        }
    }
}
for i in 0..<H {
    print(map[i].joinWithSeparator(""))
}


"use strict";

main(require("fs").readFileSync("/dev/stdin", "utf8"));

function main(input) {
  const [hw, ...s] = input.trim().split("\n");
  const [h, w] = hw.split(" ").map(Number);
  const S = s.map(e => e.split(""));

  const bomb = "#";

  let ans = "";
  for(let i = 0; i < h; i++) {
    for(let j = 0; j < w; j++) {
      let cnt = 0;
      if(S[i][j] === bomb) {
        ans += bomb;
        continue;
      }
      if(S[i][j + 1] === bomb) { cnt++; }
      if(S[i][j - 1] === bomb) { cnt++; }
      if(S[i - 1] && S[i - 1][j - 1] === bomb) { cnt++; }
      if(S[i - 1] && S[i - 1][j] === bomb) { cnt++; }
      if(S[i - 1] && S[i - 1][j + 1] === bomb) { cnt++; }
      if(S[i + 1] && S[i + 1][j - 1] === bomb) { cnt++; }
      if(S[i + 1] && S[i + 1][j] === bomb) { cnt++; }
      if(S[i + 1] && S[i + 1][j + 1] === bomb) { cnt++; }
      ans += cnt;
    }
    ans += "\n";
  }

  console.log(ans);
}


import * as fs from 'fs'

const getInput = (): string => {
  const input = (fs.readFileSync('/dev/stdin', 'utf8') as string).trim()
  return input
}

export const solveAbc075b = () => {
  const input = getInput()

  const arr = input.trim().split('\n').map(v => v.trim())
  // console.log(arr)

  const numbers = arr[0].trim().split(' ').map(Number)
  const H = numbers[0]
  const W = numbers[1]

  const grid = arr.slice(1).map(v => v.split(''))
  // console.log(grid)

  let extendedGrid = grid.slice()
  const dummy = [...Array(W)].map(_ => '.')
  extendedGrid = [dummy].concat(extendedGrid).concat([dummy])
  extendedGrid = extendedGrid.map(v => ['.'].concat(v).concat('.'))
  // console.log(extendedGrid)

  const result = []
  for (let i = 1; i <= H; i += 1) {
    const row = []
    for (let j = 1; j <= W; j += 1) {
      if (extendedGrid[i][j] === '#') {
        row.push('#')
        continue
      }

      let count = 0
      if (extendedGrid[i - 1][j - 1] === '#') count += 1
      if (extendedGrid[i - 1][j] === '#') count += 1
      if (extendedGrid[i - 1][j + 1] === '#') count += 1
      if (extendedGrid[i][j - 1] === '#') count += 1
      if (extendedGrid[i][j + 1] === '#') count += 1
      if (extendedGrid[i + 1][j - 1] === '#') count += 1
      if (extendedGrid[i + 1][j] === '#') count += 1
      if (extendedGrid[i + 1][j + 1] === '#') count += 1
      // console.log(count)
      row.push(count.toString())
    }
    result.push(row)
  }
  // console.log(result)
  const out = result.map(v => v.join('')).join('\n')
  console.log(out)
}

solveAbc075b()


const input=require('fs').readFileSync('/dev/stdin','utf8').split(/[\s]/);let input_i=-1;const tn=():number=>{input_i++;return Number(input[input_i])};const tnn=(n:number):number[]=>{const a=[];for(let i=0;i<n;i++){a.push(tn())}return a};const ts=():string=>{input_i++;return String(input[input_i])};const tss=(n:number):string[]=>{const a=[];for(let i=0;i<n;i++){a.push(ts())}return a};const to=(...arg)=>{console.log(...arg)};const abs=(a)=>{return Math.abs(a)};const min=(...a)=>{return Math.min(...a)};const max=(...a)=>{return Math.max(...a)};const floor=(a)=>{return Math.floor(a)};const asc=(ar:number[])=>{const t=[...ar];return ar.sort((a,b)=>{return a-b})};const desc=(ar:number[])=>{const t=[...ar];return t.sort((a,b)=>{return b-a})};const sw=(a,arr:any[],op:'=='|'>='|'>'|'<='|'<'='==')=>{for(let i=0;i<arr.length-1;i+=2){if(eval(a+op+arr[i])){return arr[i+1]}}return arr[arr.length-1]};const near=(n:number,arr:number[]):number=>{let ne=arr[0],ni=0;for(let i=1;i<arr.length;i++){if(Math.abs(n-ne)>Math.abs(n-arr[i])){ne=arr[i];ni=i}}return ni};const deduplicate=(a:any[]):any[]=>{return Array.from(new Set(a))}
const main=()=>{
  const dh=[1,1,1,-1,-1,-1,0,0]
  const dw=[1,-1,0,1,-1,0,1,-1]
  const [h,w]=tnn(2)
  const mp=tss(h)
  for(let i=0;i<h;i++){
    let tr=''
    for(let j=0;j<w;j++){
      if(mp[i][j]=='#'){
        tr+='#'
        continue
      }
      let cnt=0
      for(let k=0;k<8;k++){
        const [th,tw]=[i+dh[k],j+dw[k]]
        if(th<0||tw<0||th>=h||tw>=w)continue
        if(mp[th][tw]=='#')cnt++
      }
      tr+=cnt
    }
    to(tr)
  }
}
main()


function*stdinIter(){const t=require("fs").readFileSync("/dev/stdin","utf-8").trim().split(/\n|\s/);yield*t}function readMany(t,e){const i=e||this.iter||(this.iter=stdinIter()),n=[];for(let e=0;e<t;e+=1)n.push(i.next().value);return n};

(() => {
    const [ h, w ] = readMany(2).map(it => parseInt(it))
    const s = []
    const map = []

    for (let i = 0; i < h; i += 1) {
        const tmp = readMany(1)[0].split('')
        s.push(tmp)
        map.push([])
    }

    const get = (arr, i, j) => {
        const tmp = arr[i]
        if (tmp) {
            return tmp[j]
        } else {
            return void 0
        }
    }

    for (let i = 0; i < h; i += 1) {
        for (let j = 0; j < w; j += 1) {
            if (s[i][j] == '#') {
                map[i][j] = '#'
                continue
            }

            let boms = 0
            if (get(s, i - 1, j) == '#') boms += 1
            if (get(s, i - 1, j + 1) == '#') boms += 1
            if (get(s, i - 1, j - 1) == '#') boms += 1
            if (get(s, i, j) == '#') boms += 1
            if (get(s, i, j + 1) == '#') boms += 1
            if (get(s, i, j - 1) == '#') boms += 1
            if (get(s, i + 1, j) == '#') boms += 1
            if (get(s, i + 1, j + 1) == '#') boms += 1
            if (get(s, i + 1, j - 1) == '#') boms += 1

            map[i][j] = boms
        }
    }

    console.log(map)
})()


const input=require('fs').readFileSync('/dev/stdin','utf8').split(/[\s]/);let input_i=-1;const tn=():number=>{input_i++;return Number(input[input_i])};const tnn=(n:number):number[]=>{const a=[];for(let i=0;i<n;i++){a.push(tn())}return a};const ts=():string=>{input_i++;return String(input[input_i])};const tss=(n:number):string[]=>{const a=[];for(let i=0;i<n;i++){a.push(ts())}return a};const to=(...arg)=>{console.log(...arg)};const abs=(a)=>{return Math.abs(a)};const min=(...a)=>{return Math.min(...a)};const max=(...a)=>{return Math.max(...a)};const floor=(a)=>{return Math.floor(a)};const asc=(ar:number[])=>{const t=[...ar];return ar.sort((a,b)=>{return a-b})};const desc=(ar:number[])=>{const t=[...ar];return t.sort((a,b)=>{return b-a})};const sw=(a,arr:any[],op:'=='|'>='|'>'|'<='|'<'='==')=>{for(let i=0;i<arr.length-1;i+=2){if(eval(a+op+arr[i])){return arr[i+1]}}return arr[arr.length-1]};const near=(n:number,arr:number[]):number=>{let ne=arr[0],ni=0;for(let i=1;i<arr.length;i++){if(Math.abs(n-ne)>Math.abs(n-arr[i])){ne=arr[i];ni=i}}return ni};const deduplicate=(a:any[]):any[]=>{return Array.from(new Set(a))}
const main=()=>{
  const dh=[1,1,1,-1,-1,-1,0,0]
  const dw=[1,-1,0,1,-1,0,1,-1]
  const [h,w]=tnn(2)
  const mp=tss(h)
  to(mp)
  for(let i=0;i<h;i++){
    let tr=''
    for(let j=0;j<w;j++){
      if(mp[i][j]=='#'){
        tr+='#'
        continue
      }
      let cnt=0
      for(let k=0;k<8;k++){
        const [th,tw]=[i+dh[k],j+dw[k]]
        if(th<0||tw<0||th>=h||tw>=w)continue
        if(mp[th][tw]=='#')cnt++
      }
      tr+=cnt
    }
    to(tr)
  }
}
main()