Problem: You are given a binary matrix a of size n × m. A binary matrix is a matrix where each element is either 0 or 1.

You may perform some (possibly zero) operations with this matrix. During each operation you can inverse the row of this matrix or a column of this matrix. Formally, inverting a row is changing all values in this row to the opposite (0 to 1, 1 to 0). Inverting a column is changing all values in this column to the opposite.

Your task is to sort the initial matrix by some sequence of such operations. The matrix is considered sorted if the array [a_{1, 1}, a_{1, 2}, ..., a_{1, m}, a_{2, 1}, a_{2, 2}, ..., a_{2, m}, ..., a_{n, m - 1}, a_{n, m}] is sorted in non-descending order.

Input

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

The next n lines contain m integers each. The j-th element in the i-th line is a_{i, j} (0 ≤ a_{i, j} ≤ 1) — the element of a at position (i, j).

Output

If it is impossible to obtain a sorted matrix, print "NO" in the first line.

Otherwise print "YES" in the first line. In the second line print a string r of length n. The i-th character r_i of this string should be '1' if the i-th row of the matrix is inverted and '0' otherwise. In the third line print a string c of length m. The j-th character c_j of this string should be '1' if the j-th column of the matrix is inverted and '0' otherwise. If there are multiple answers, you can print any.

Examples

Input


2 2
1 1
0 1


Output


YES
00
10


Input


3 4
0 0 0 1
0 0 0 0
1 1 1 1


Output


YES
010
0000


Input


3 3
0 0 0
1 0 1
1 1 0


Output


NO

Solution (in CPP):

Solution:
#include <bits/stdc++.h>
using namespace std;
using ipair = pair<int, int>;
using int64 = int64_t;
using uint64 = uint64_t;
template <typename T>
void remin(T &a, const T &b) {
  if (b < a) {
    a = b;
  }
}
template <typename T>
void remax(T &a, const T &b) {
  if (b > a) {
    a = b;
  }
}
template <class T1, class T2>
inline istream &operator>>(istream &s, pair<T1, T2> &p) {
  return s >> p.first >> p.second;
}
template <class T1, class T2>
inline ostream &operator<<(ostream &s, const pair<T1, T2> &p) {
  return s << "(" << p.first << " " << p.second << ")";
}
template <class T1>
inline ostream &operator<<(ostream &s, const set<T1> &container) {
  for (const auto &x : container) {
    s << x << ' ';
  }
  return s;
}
template <class T1>
inline ostream &operator<<(ostream &s, const vector<T1> &container) {
  for (const auto &x : container) {
    s << x << ' ';
  }
  return s;
}
template <class T1>
inline istream &operator>>(istream &s, vector<T1> &container) {
  for (auto &x : container) {
    s >> x;
  }
  return s;
}
template <class T>
inline T euclide(T a, T b, T &x, T &y) {
  if (a < 0) {
    T d = euclide(-a, b, x, y);
    x = -x;
    return d;
  }
  if (b < 0) {
    T d = euclide(a, -b, x, y);
    y = -y;
    return d;
  }
  if (b == 0) {
    x = 1;
    y = 0;
    return a;
  } else {
    T d = euclide(b, a % b, x, y);
    T t = x;
    x = y;
    y = t - (a / b) * y;
    return d;
  }
}
template <class T>
inline vector<pair<T, int>> factorize(T n) {
  vector<pair<T, int>> R;
  for (T i = 2; n > 1;) {
    if (n % i == 0) {
      int C = 0;
      for (; n % i == 0; C++, n /= i)
        ;
      R.push_back(make_pair(i, C));
    }
    i++;
    if (i > n / i) i = n;
  }
  if (n > 1) R.push_back(make_pair(n, 1));
  return R;
}
template <class T>
inline bool isPrimeNumber(T n) {
  if (n <= 1) return false;
  for (T i = 2; i * i <= n; i++)
    if (n % i == 0) return false;
  return true;
}
vector<bool> gen_primes(int limit) {
  vector<bool> is_prime(limit + 1, true);
  is_prime[0] = false;
  is_prime[1] = false;
  for (int i = 2; i * i <= limit; i += 1) {
    if (is_prime[i]) {
      for (int j = i + i; j <= limit; j += i) {
        is_prime[j] = false;
      }
    }
  }
  return is_prime;
}
template <int64_t P>
struct TZp {
  static_assert(P > 1, "P should be > 1");
  static_assert(numeric_limits<int64_t>::max() / P >= P,
                "P * P should be less then 2^63");
  int64_t Value = 0;
  TZp(int64_t val = 0) : Value(val) {}
  TZp &operator+=(const TZp &other) {
    Value = (Value + other.Value) % P;
    return *this;
  }
  TZp &operator-=(const TZp &other) {
    Value = (Value - other.Value + P) % P;
    return *this;
  }
  TZp &operator*=(const TZp &other) {
    Value = (Value * other.Value) % P;
    return *this;
  }
  TZp Inverse() const {
    int64_t x, y;
    euclide(Value, P, x, y);
    return x;
  }
  TZp &operator/=(const TZp &other) {
    Value = (Value * other.Inverse().Value) % P;
    return *this;
  }
  TZp operator-() const { return TZp((P - Value) % P); }
  TZp operator+(const TZp &other) const {
    TZp result(Value);
    result += other;
    return result;
  }
  TZp operator-(const TZp &other) const {
    TZp result(Value);
    result -= other;
    return result;
  }
  TZp operator*(const TZp &other) const {
    TZp result(Value);
    result *= other;
    return result;
  }
  TZp operator/(const TZp &other) const {
    TZp result(Value);
    result /= other;
    return result;
  }
  int64_t ToInt() const { return Value; }
};
template <class T>
struct TPlus {
  using Type = T;
  const static T Neutral;
  T operator()(const T &x, const T &y) const { return x + y; }
};
template <class T>
const T TPlus<T>::Neutral = 0;
template <class T>
struct TMax {
  using Type = T;
  static const T Neutral;
  T operator()(const T &x, const T &y) const { return max(x, y); }
};
template <class T>
T const TMax<T>::Neutral = numeric_limits<T>::min();
template <class T>
struct TMin {
  using Type = T;
  static const T Neutral;
  T operator()(const T &x, const T &y) const { return min(x, y); }
};
template <class T>
T const TMin<T>::Neutral = numeric_limits<T>::max();
template <class TF>
struct TSegmentTree {
  using T = typename TF::Type;
  size_t N = 0;
  TF Func;
  vector<T> Data;
  TSegmentTree(size_t n, const TF &f = TF()) : N(n), Func(f) {
    size_t s = 1;
    while (s < n) {
      s *= 2;
    }
    Data.assign(s * 2 - 1, TF::Neutral);
  }
  void Set(size_t i, const T &x) {
    size_t index = i + Data.size() / 2;
    Data[index] = x;
    while (index) {
      index = (index - 1) / 2;
      Data[index] = Func(Data[index * 2 + 1], Data[index * 2 + 2]);
    }
  }
  T Get(size_t left, size_t right, size_t l = 0, size_t r = -1,
        size_t v = 0) const {
    if (left >= right) {
      return TF::Neutral;
    }
    if (r == -1) {
      r = Data.size() / 2 + 1;
    }
    if (l == left && r == right) {
      return Data[v];
    }
    size_t m = l + (r - l) / 2;
    while (m < left || m > right) {
      if (m < left) {
        v = v * 2 + 2;
        l = m;
      } else {
        v = v * 2 + 1;
        r = m;
      }
      m = l + (r - l) / 2;
    }
    return Func(Get(left, min(m, right), l, m, v * 2 + 1),
                Get(max(m, left), right, m, r, v * 2 + 2));
  }
  T GetUpTo(size_t right) {
    T result = TF::Neutral;
    if (right == 0) {
      return result;
    }
    size_t l = 0;
    size_t r = Data.size() / 2 + 1;
    size_t v = 0;
    while (r > right) {
      size_t m = l + (r - l) / 2;
      if (m >= right) {
        r = m;
        v = v * 2 + 1;
      } else {
        result = Func(Data.at(v * 2 + 1), result);
        v = v * 2 + 2;
        l = m;
      }
    }
    result = Func(Data.at(v), result);
    return result;
  }
};
struct TDSU {
  vector<size_t> Parents;
  vector<size_t> Sizes;
  TDSU(size_t n) : Parents(n), Sizes(n, 1) {
    iota(Parents.begin(), Parents.end(), 0);
  }
  size_t Get(size_t x) {
    if (Parents[x] != x) {
      Parents[x] = Get(Parents[x]);
    }
    return Parents[x];
  }
  void Unite(size_t x, size_t y) {
    x = Get(x);
    y = Get(y);
    if (x == y) {
      return;
    }
    if (Sizes[x] > Sizes[y]) {
      std::swap(x, y);
    }
    Parents[x] = y;
    Sizes[y] += Sizes[x];
  }
};
template <class T>
struct TDisjointIntervalSet : public set<pair<T, T>> {
  using TParent = set<pair<T, T>>;
  void Insert(T left, T right) {
    if (right <= left) {
      return;
    }
    auto it = TParent::upper_bound(make_pair(right, numeric_limits<T>::max()));
    auto it1 = it;
    while (it != TParent::begin()) {
      --it;
      if (it->second >= left) {
        remin(left, it->first);
        remax(right, it->second);
      } else {
        ++it;
        break;
      }
    }
    TParent::erase(it, it1);
    TParent::emplace(left, right);
  }
};
void Solve() {}
void RunGCJ() {
  size_t __number_of_cases;
  cin >> __number_of_cases;
  for (size_t __number_of_case = 0; __number_of_case < __number_of_cases;
       ++__number_of_case) {
    cout << "Case #" << __number_of_case + 1 << ": ";
    Solve();
  }
}
int main(void) {
  int n, m;
  cin >> n >> m;
  vector<vector<int>> a(n, vector<int>(m, 0));
  cin >> a;
  vector<int> rows(n, 0), columns(m, 0);
  for (rows[0] = 0; rows[0] < 2; ++rows[0]) {
    for (int first1 = 0; first1 <= m; ++first1) {
      for (int i = 0; i < m; ++i) {
        if ((a[0][i] ^ rows[0]) != (i >= first1)) {
          columns[i] = 1;
        } else {
          columns[i] = 0;
        }
      }
      bool ok = true;
      bool need_ones = (first1 < m);
      for (int j = 1; j < n; ++j) {
        bool has1 = false, has0 = false;
        for (int k = 0; k < m; ++k) {
          if (a[j][k] ^ columns[k]) {
            has1 = true;
          } else {
            has0 = true;
          }
        }
        if (has0 && has1) {
          if (need_ones) {
            ok = false;
            break;
          }
          if (a[j][0] ^ columns[0]) {
            rows[j] = 1;
          } else {
            rows[j] = 0;
          }
          bool saw_one = false;
          for (int k = 0; k < m; ++k) {
            if (a[j][k] ^ rows[j] ^ columns[k]) {
              saw_one = true;
            } else if (saw_one) {
              ok = false;
              break;
            }
          }
          need_ones = true;
          if (!ok) {
            break;
          }
        } else if (has0 == need_ones) {
          rows[j] = 1;
        } else {
          rows[j] = 0;
        }
      }
      if (ok) {
        cout << "YES" << endl;
        for (auto x : rows) {
          cout << x;
        }
        cout << endl;
        for (auto x : columns) cout << x;
        cout << endl;
        return 0;
      }
    }
  }
  cout << "NO" << endl;
  return 0;
}