#include <bits/stdc++.h>
using namespace std;
namespace io {
const int SIZE = (1 << 21) + 1;
char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c,
                                       qu[55];
int f, qr;
inline void flush() {
  fwrite(obuf, 1, oS - obuf, stdout);
  oS = obuf;
}
inline void putc(char x) {
  *oS++ = x;
  if (oS == oT) flush();
}
template <class I>
inline void read(I &x) {
  for (f = 1, c = (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, SIZE, stdin),
                              (iS == iT ? EOF : *iS++))
                            : *iS++);
       c < '0' || c > '9';
       c = (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, SIZE, stdin),
                       (iS == iT ? EOF : *iS++))
                     : *iS++))
    if (c == '-') f = -1;
  for (x = 0; c <= '9' && c >= '0';
       c = (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, SIZE, stdin),
                       (iS == iT ? EOF : *iS++))
                     : *iS++))
    x = x * 10 + (c & 15);
  x *= f;
}
template <class I>
inline void print(I x) {
  if (!x) putc('0');
  if (x < 0) putc('-'), x = -x;
  while (x) qu[++qr] = x % 10 + '0', x /= 10;
  while (qr) putc(qu[qr--]);
}
struct Flusher_ {
  ~Flusher_() { flush(); }
} io_flusher_;
}  // namespace io
using io ::print;
using io ::putc;
using io ::read;
using namespace std;
int n, m, amount;
int gcd;
int mat[1005][1005];
bool vis[1005][1005];
bool flaglen[1005];
int GCD(int a, int b) {
  if (!b)
    return a;
  else
    return GCD(b, a % b);
}
int existone() {
  for (int i = 1; i < n; i++)
    for (int j = 1; j < m; j++)
      if (mat[i][j] && mat[i][j + 1] && mat[i + 1][j] && mat[i + 1][j + 1])
        return 1;
  return 0;
}
int searchconnected(int i, int j) {
  if (i < 1 || i > n || j < 1 || j > m) return 0;
  if (!mat[i][j] || vis[i][j]) return 0;
  vis[i][j] = true;
  return searchconnected(i + 1, j) + searchconnected(i - 1, j) +
         searchconnected(i, j + 1) + searchconnected(i, j - 1) + 1;
}
int connected() {
  memset(vis, 0, sizeof(vis));
  for (int i = 1; i <= n; i++)
    for (int j = 1; j <= m; j++)
      if (mat[i][j])
        if (searchconnected(i, j) != amount)
          return 0;
        else
          return 1;
      else
        continue;
}
int solve() {
  int di[4] = {0, 0, 1, -1};
  int dj[4] = {1, -1, 0, 0};
  int t;
  int cnt;
  int cntodd = 0;
  memset(flaglen, 0, sizeof(flaglen));
  memset(vis, 0, sizeof(vis));
  for (int i = 1; i <= n; i++)
    for (int j = 1; j <= m; j++)
      if (mat[i][j]) {
        cnt = mat[i - 1][j] + mat[i + 1][j] + mat[i][j - 1] + mat[i][j + 1];
        cntodd += cnt & 0x01;
        if (cntodd >= 3) return 0;
        if ((cnt == 2) && ((mat[i - 1][j] && mat[i + 1][j]) ||
                           (mat[i][j - 1] && mat[i][j + 1])))
          continue;
        else
          vis[i][j] = true;
      }
  gcd = 1;
  for (int i = 1; i <= n; i++)
    for (int j = 1; j <= m; j++)
      if (vis[i][j])
        for (int k = 0; k < 4; k++) {
          for (t = 1; mat[i + di[k] * t][j + dj[k] * t] &&
                      !vis[i + di[k] * t][j + dj[k] * t];
               t++)
            ;
          if (t > 1) {
            flaglen[t] = true;
            gcd = t;
          }
        }
  for (t = max(n, m); t > 1; t--)
    if (flaglen[t]) gcd = GCD(gcd, t);
  return gcd != 1;
}
void print(int n) {
  for (int i = 2; i < n; i++)
    if (n % i == 0) printf("%d ", i);
  printf("%d\n", n);
}
int main() {
  scanf("%d%d", &n, &m);
  memset(mat, 0, sizeof(mat));
  amount = 0;
  for (int i = 1; i <= n; i++)
    for (int j = 1; j <= m; amount += mat[i][j], j++) scanf("%d", &mat[i][j]);
  if (existone() || !connected()) {
    printf("-1\n");
    return 0;
  }
  if (solve() != 0)
    print(gcd);
  else
    printf("-1\n");
  return 0;
}
