#include <bits/stdc++.h>
using namespace std;
struct edge {
  int idx;
  int lenth;
  edge() {}
  edge(int ii, int ll) {
    idx = ii;
    lenth = ll;
  }
};
vector<edge> node[1000010];
int maze[1010][1010];
int idx[1010][1010];
int gcd(int a, int b) {
  if (b == 0)
    return a;
  else
    return gcd(b, a % b);
}
int size;
void generate_graph(int n, int m) {
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      if (maze[i][j] == 0) continue;
      bool ver = false;
      bool hri = false;
      if (i > 1 && i < n && maze[i - 1][j] && maze[i + 1][j]) ver = true;
      if (j > 1 && j < m && maze[i][j - 1] && maze[i][j + 1]) hri = true;
      if (ver == hri) {
        idx[i][j] = ++size;
      }
    }
  }
  for (int i = 1; i <= n; i++) {
    int pre = -1;
    int prej;
    for (int j = 1; j <= m; j++) {
      if (idx[i][j] > 0) {
        if (pre != -1) {
          node[idx[i][j]].push_back(edge(pre, j - prej));
          node[pre].push_back(edge(idx[i][j], j - prej));
        }
        pre = idx[i][j];
        prej = j;
      }
      if (maze[i][j] == 0) {
        pre = -1;
      }
    }
  }
  for (int i = 1; i <= n; i++) {
    int pre = -1;
    int prej;
    for (int j = 1; j <= m; j++) {
      if (idx[j][i] > 0) {
        if (pre != -1) {
          node[idx[j][i]].push_back(edge(pre, j - prej));
          node[pre].push_back(edge(idx[j][i], j - prej));
        }
        pre = idx[j][i];
        prej = j;
      }
      if (maze[j][i] == 0) {
        pre = -1;
      }
    }
  }
}
bool mark[1000010];
void dfs(int x) {
  mark[x] = true;
  for (int i = 0; i < node[x].size(); i++) {
    int n = node[x][i].idx;
    if (mark[n] == false) {
      dfs(n);
    }
  }
}
bool check_connected(int n, int m) {
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      if (idx[i][j]) {
        dfs(idx[i][j]);
        i = n + 1;
        break;
      }
    }
  }
  for (int i = 1; i <= size; i++) {
    if (!mark[i]) return false;
  }
  return true;
}
int degree[1000010];
bool euler_check() {
  for (int i = 1; i <= size; i++) {
    for (int j = 0; j < node[i].size(); j++) {
      degree[node[i][j].idx]++;
    }
  }
  int cnt = 0;
  for (int i = 1; i <= size; i++) {
    if (degree[i] % 2 == 1) cnt++;
  }
  return cnt == 0 || cnt == 2;
}
int main() {
  int n, m;
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      scanf("%d", &maze[i][j]);
    }
  }
  generate_graph(n, m);
  if (check_connected(n, m) == false || euler_check() == false) {
    puts("-1");
    return 0;
  }
  int ans = 0;
  for (int i = 1; i <= size; i++) {
    for (int j = 0; j < node[i].size(); j++) {
      ans = gcd(ans, node[i][j].lenth);
    }
  }
  if (ans == 0 || ans == 1) {
    puts("-1");
    return 0;
  }
  vector<int> buf;
  for (int i = 2; i <= 1000; i++) {
    if (ans % i == 0) buf.push_back(i);
  }
  for (int i = 0; i < buf.size(); i++) {
    if (i) printf(" ");
    printf("%d", buf[i]);
  }
  puts("");
  return 0;
}
