#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e3;
const int oops = MAXN + 5;
const int dr[] = {0, 1, 0, -1};
const int dc[] = {-1, 0, 1, 0};
vector<int> rowNodes[MAXN + 5], colNodes[MAXN + 5];
int n, m;
int grid[MAXN + 5][MAXN + 5];
bool vis[MAXN + 5][MAXN + 5];
int flood(int i, int j) {
  if (vis[i][j]) return 0;
  if (!grid[i][j]) return 0;
  vis[i][j] = 1;
  int ret = 1;
  for (int d = 0; d < 4; d++) ret += flood(i + dr[d], j + dc[d]);
  return ret;
}
int getValue(int i, int j) {
  int neighbours = 0;
  bool isCorner = false;
  for (int d = 0; d < 4; d++) {
    neighbours += grid[i + dr[d]][j + dc[d]];
    if (grid[i + dr[d]][j + dc[d]] &&
        grid[i + dr[d + 1 & 3]][j + dc[d + 1 & 3]])
      isCorner = true;
  }
  return (isCorner || (neighbours & 1)) ? neighbours : 0;
}
int main() {
  int c, c2;
  scanf("%d%d", &n, &m);
  for (c = 1; c <= n; c++)
    for (c2 = 1; c2 <= m; c2++) scanf("%d", &grid[c][c2]);
  int ones = 0, odds = 0;
  int si, sj;
  bool bad = false;
  for (c = 1; c <= n; c++)
    for (c2 = 1; c2 <= m; c2++) {
      if (!grid[c][c2]) continue;
      ones++;
      si = c;
      sj = c2;
      int v = getValue(c, c2);
      if (v > 0) {
        odds += v & 1;
        rowNodes[c].push_back(c2);
        colNodes[c2].push_back(c);
      }
    }
  if (odds > 2 || ones == 1 || flood(si, sj) < ones)
    printf("%d\n", -1);
  else {
    int mi = oops;
    for (c = 1; c <= n; c++) {
      for (c2 = 0; c2 + 1 < rowNodes[c].size(); c2++)
        mi = min(mi, rowNodes[c][c2 + 1] - rowNodes[c][c2]);
    }
    for (c2 = 1; c2 <= m; c2++) {
      for (c = 0; c + 1 < colNodes[c2].size(); c++)
        mi = min(mi, colNodes[c2][c + 1] - colNodes[c2][c]);
    }
    for (int d = 2; d <= mi; d++)
      if (mi % d == 0) printf("%d ", d);
    if (mi == 1) printf("-1\n");
  }
  return 0;
}
