Alice has an empty grid with n rows and m columns. Some of the cells are marked, and no marked cells are adjacent to the edge of the grid. (Two squares are adjacent if they share a side.) 

Alice wants to fill each cell with a number such that the following statements are true: 

  * every unmarked cell contains either the number 1 or 4; 
  * every marked cell contains the sum of the numbers in all unmarked cells adjacent to it (if a marked cell is not adjacent to any unmarked cell, this sum is 0); 
  * every marked cell contains a multiple of 5. 

Alice couldn't figure it out, so she asks Bob to help her. Help Bob find any such grid, or state that no such grid exists.

Input

The first line of input contains two integers n and m (1 ≤ n, m ≤ 500) — the number of rows and the number of columns in the grid, respectively.

Then n lines follow, each containing m characters. Each of these characters is either '.' or 'X' — an unmarked and a marked cell, respectively. No marked cells are adjacent to the edge of the grid.

Output

Output "'NO" if no suitable grid exists. Otherwise, output "'YES"'. Then output n lines of m space-separated integers — the integers in the grid.

Examples

Input


5 5
.....
.XXX.
.X.X.
.XXX.
.....


Output


YES
4 1 4 4 1
4 5 5 5 1
4 5 1 5 4
1 5 5 5 4
1 4 4 1 4


Input


5 5
.....
.XXX.
.XXX.
.XXX.
.....


Output


NO


Input


3 2
..
..
..


Output


YES
4 1
4 1
1 4


Input


9 9
.........
.XXXXX.X.
.X...X...
.X.XXXXX.
.X.X.X.X.
.X.XXX.X.
.X.....X.
.XXXXXXX.
.........


Output


YES
4 4 4 1 4 1 4 1 4
1 5 5 5 5 5 4 10 1
4 5 1 4 1 5 4 4 4
4 5 1 5 5 0 5 5 1
4 5 1 5 4 5 1 5 4
4 5 1 5 5 5 4 5 1
1 5 4 4 1 1 4 5 1
4 5 5 5 5 5 5 5 4
1 1 1 1 4 4 1 1 4

Note

It can be shown that no such grid exists for the second test.
#include<bits/stdc++.h>
#define f_in(s) freopen(s,"r",stdin)
#define f_out(s) freopen(s,"w",stdout)
#define inf 0x3f3f3f3f
#define infl 0x3f3f3f3f3f3f3f3fll
#define rep(i,a,n) for(int i=(a),__##i=(n);i<=__##i;++i)
#define repe(i,a,n) for(int i=(a),__##i=(n);i<__##i;++i)
#define repv(i,n,a) for(int i=(n),__##i=(a);i>=__##i;--i)
#define repl(i,a,n) for(ll i=(a),__##i=(n);i<=__##i;++i)
#define lowbit(x) ((x)&-(x))
#define mset(x,v) memset(x,v,sizeof(x))
#define mcpy(x,y) memcpy(x,y,sizeof(x))
#define mkp make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pdd pair<db,db>
#define X first
#define Y second
#define LL __int128
#define ll long long
#define ull unsigned long long
#define db long double
using namespace std;
mt19937_64 rndGen(chrono::steady_clock::now().time_since_epoch().count());
#define rint(l,r) uniform_int_distribution<int>(l,r)(rndGen)
#define rreal(l,r) uniform_real_distribution<double>(l,r)(rndGen)

#define HDU
inline ll read(){
#ifdef HDU
    ll ret; scanf("%lld",&ret);
    return ret;
#else
    ll s=0,f=1; char c=getchar();
    while(c<'0'||c>'9') f*=c=='-'?-1:1,c=getchar();
    while(c>='0'&&c<='9') s=s*10+c-'0',c=getchar();
    return s*f;
#endif
}

namespace SAT {
    const int undef = -1;
    const double activityLimit = 1e100;
    const double varAcceleration = 1.05;

    struct Lit {
        int lit;
        explicit Lit(int lit = undef) : lit(lit) { }
        Lit(int var, int sign) : lit(var << 1 | sign) { }
        inline int Sign() const { return lit & 1; }
        inline int Var() const { return lit >> 1; }
        inline Lit Neg() const { return Lit(lit ^ 1); }
        inline bool operator ==(const Lit &r) const { return lit == r.lit; }
    };

    struct Data {
        int varCnt = 0, clsCnt = 0;
        vector<vector<Lit>> clauses;

        explicit Data(int nVar = 0) { Init(nVar); }
        inline void Init(int nVar = 0) {
            varCnt = nVar, clsCnt = 0;
            clauses.clear();
        }
        inline vector<Lit> &AddClause() {
            ++clsCnt, clauses.emplace_back();
            return clauses.back();
        }
        inline vector<Lit> &AddClause(const vector<Lit> &cls) {
            return AddClause() = cls;
        }
    };

    class Solver {
        struct Watcher { int cls; Lit lit; };

        int varCnt = 0;
        int clsCnt = 0;
        double varInc = 1;
        vector<int> initValue;
        vector<int> varLevel;
        vector<int> varReason;
        vector<int> varPolarity;
        vector<double> varActivity;
        set<pair<double, int>, greater<>> varOrder;

        vector<vector<Lit>> clauses;
        vector<vector<Watcher>> watchList;
        unsigned trailHead = 0;
        vector<Lit> trail;
        vector<int> trailCnt;

        inline void Init() {
            isSat = -1;
            varCnt = data->varCnt;
            varInc = 1;
            varLevel.assign(varCnt, 0);
            varReason.assign(varCnt, undef);
            varPolarity.assign(varCnt, 0);
            varActivity.assign(varCnt, 0);
            varOrder.clear();
            for (int i = 0; i < varCnt; ++i) {
                varOrder.insert({ varActivity[i], i });
            }
            trailHead = 0;
            trail.clear();
            trailCnt.clear();
            clsCnt = 0;
            clauses.clear();
            initValue.assign(varCnt, -1);
            value.assign(varCnt, undef);
            watchList.assign(varCnt << 1, vector<Watcher>());
            for (auto &cls : data->clauses) AddClause(cls);
        }

        inline int GetLevel() const { return trailCnt.size(); }
        inline void NewLevel() { trailCnt.emplace_back(trail.size()); }

        inline int GetValue(Lit p) const {
            if (value[p.Var()] == undef) return undef;
            return value[p.Var()] ^ p.Sign() ^ 1;
        }

        inline void Assign(Lit lit, int from = undef) {
            value[lit.Var()] = lit.Sign();
            varReason[lit.Var()] = from;
            varLevel[lit.Var()] = GetLevel();
            trail.emplace_back(lit);
        }

        inline void UpdateActivity(int var) {
            bool isExist = varOrder.erase({ varActivity[var], var });
            varActivity[var] += varInc;
            if (isExist) varOrder.insert({ varActivity[var], var });
            if (varActivity[var] > activityLimit) {
                double rescaleRatio = 1.0 / activityLimit;
                auto tmp(move(varOrder));
                for (auto &x : varActivity) x *= rescaleRatio;
                for (auto &x : tmp) varOrder.insert({ varActivity[x.second], x.second });
                varInc *= rescaleRatio;
            }
        }

        inline Lit GetNextLit() {
            int var = undef;
            while (var == undef || value[var] != undef) {
                if (varOrder.empty()) return Lit();
                var = varOrder.begin()->second, varOrder.erase(varOrder.begin());
            }
            return Lit(var, varPolarity[var]);
        }

        inline int AnalyzeConflict(int conf, vector<Lit> &learnt) {
            learnt.clear(), learnt.emplace_back();
            vector<bool> vis(varCnt);
            int var = undef;
            for (int i = (int)trail.size() - 1, cnt = 0;;) {
                vector<Lit> &cls = clauses[conf];
                for (unsigned j = var != undef, v; j < cls.size(); ++j) {
                    if (vis[v = cls[j].Var()]) continue;
                    vis[v] = true, UpdateActivity(v);
                    if (varLevel[v] == GetLevel()) ++cnt;
                    else learnt.emplace_back(cls[j]);
                }
                while (!vis[trail[i--].Var()]);
                conf = varReason[var = trail[i + 1].Var()];
                if (--cnt <= 0) break;
            }
            learnt[0] = Lit(var, value[var] ^ 1);
            return accumulate(learnt.begin() + 1, learnt.end(), 0, [&](int acc, Lit x) {
                return max(acc, varLevel[x.Var()]);
            });
        }

        inline void Backtrack(int level) {
            if (level >= GetLevel()) return;
            auto head = trail.rend() - (trailHead = trailCnt[level]);
            for (auto c = trail.rbegin(); c < head; ++c) {
                int var = c->Var();
                value[var] = undef;
                varPolarity[var] = c->Sign();
                varOrder.insert({ varActivity[var], var });
            }
            trail.resize(trailCnt[level]);
            trailCnt.resize(level);
        }

        inline int Propagate() {
            while (trailHead < trail.size()) {
                Lit cur = trail[trailHead++];
                vector<Watcher> &watches = watchList[cur.lit];
                int clsid;
                for (auto p = watches.begin(), newp = p, end = watches.end();; ++p) {
                    while (p != end && GetValue(p->lit) == 1) *newp++ = *p++;
                    if (p == end) {
                        watches.erase(newp, end);
                        break;
                    }
                    vector<Lit> &cls = clauses[clsid = p->cls];
                    if (cls[0] == cur.Neg()) swap(cls[0], cls[1]);

                    if (GetValue(cls[0]) == 1) {
                        *newp++ = { clsid, cls[0] };
                        continue;
                    }

                    bool isUnit = true;
                    for (unsigned k = 2; k < cls.size(); ++k) {
                        if (!GetValue(cls[k])) continue;
                        isUnit = false, swap(cls[1], cls[k]);
                        watchList[cls[1].Neg().lit].emplace_back(Watcher{ clsid, cls[0] });
                        break;
                    }
                    if (!isUnit) continue;

                    *newp++ = { clsid, cls[0] };
                    if (!GetValue(cls[0])) {
                        trailHead = trail.size();
                        while (++p != end) *newp++ = *p;
                        return watches.erase(newp, end), clsid;
                    } else Assign(cls[0], clsid);
                }
            }
            return undef;
        }

        inline int Search() {
            vector<Lit> learnt;
            while (true) {
                int conf = Propagate();
                if (conf != undef) {
                    if (!GetLevel()) return 0;
                    Backtrack(AnalyzeConflict(conf, learnt));
                    Assign(learnt[0], AddClause(learnt));
                    varInc *= varAcceleration;
                } else {
                    Lit next = GetNextLit();
                    if (next == Lit()) return 1;
                    NewLevel(), Assign(next);
                }
            }
        }

    public:
        const Data *data = nullptr;
        int isSat = -1;
        vector<int> value;

        explicit Solver(const Data *satData) { data = satData; }
        inline int AddClause(const vector<Lit> &cls) {
            if (cls.empty()) return undef;
            if (cls.size() == 1) {
                int var = cls[0].Var(), sign = cls[0].Sign();
                if (initValue[var] == !sign) return isSat = 0, undef;
                initValue[var] = sign;
                return Assign(cls[0]), undef;
            }
            watchList[cls[0].Neg().lit].push_back({ clsCnt, cls[1] });
            watchList[cls[1].Neg().lit].push_back({ clsCnt, cls[0] });
            return clauses.push_back(cls), clsCnt++;
        }

        inline int Solve() {
            Init();
            if (isSat) isSat = Search();
            return isSat;
        }
    };
}

const int di[]={1,0,-1,0};
const int dj[]={0,1,0,-1};
using namespace SAT;
int main(){
    int n=read(),m=read();
    Data data(n*m);
    Solver sat(&data);
    auto id=[&](int i,int j){
        if(i<0||i>n||j<0||j>m) return -1;
        return i*m+j;
    };
    vector<vector<char>> mp(n,vector<char>(m));
    vector<vector<char>> ans(n,vector<char>(m,-1));
    repe(i,0,n){
        string s; cin>>s;
        repe(j,0,m) mp[i][j]=s[j]=='X';
    }
    vector<vector<int>> G(n*m);
    repe(i,0,n) repe(j,0,m){
        if(!mp[i][j]) continue;
        int p=id(i,j);
        vector<int> nb;
        repe(d,0,4){
            int np=id(i+di[d],j+dj[d]);
            if(np<0||mp[i+di[d]][j+dj[d]]) continue;
            nb.push_back(np);
        }
        if(nb.size()&1) return puts("NO"),0;
        ans[i][j]=nb.size()/2*5;
        if(nb.size()==2){
            data.AddClause({Lit(nb[0],0),Lit(nb[1],0)});
            data.AddClause({Lit(nb[0],1),Lit(nb[1],1)});
        }else if(nb.size()==4){
            repe(t,0,4){
                vector<Lit> va,vb;
                repe(s,0,4){
                    va.emplace_back(nb[s],s==t);
                    vb.emplace_back(nb[s],s!=t);
                }
                data.AddClause(va),data.AddClause(vb);
            }
        }
    }
    if(!sat.Solve()) return puts("NO"),0;
    vector<int> C(sat.value);
    puts("YES");
    repe(i,0,n) repe(j,0,m){
        if(ans[i][j]==-1) ans[i][j]=C[id(i,j)]?1:4;
        cout<<int(ans[i][j])<<" \n"[j==m-1];
    }
    return 0;
}
