#pragma comment(linker, "/STACK:128777216")

#include <cstdio>
#include <cmath>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <vector>
#include <deque>
#include <string>
#include <map>
#include <set>
#include <iostream>
#include <functional>
#include <numeric>
#include <sstream>
#include <exception>
#include <cassert>

typedef long long i64;
typedef unsigned int u32;
const int null = 0;

using namespace std;

template<class T> int size(const T &a) {
	return int(a.size());
}
template<class T> T abs(const T &a) {
	return (a < 0? -a: a);
}
template<class T> T sqr(const T &a) {
	return a * a;
}

#define all(a) a.begin(),a.end()

const int max_n = 2001;

int a[max_n][max_n];
typedef bool bool2d[max_n][max_n];
bool2d was, was2, was3;
int n, m;

struct Pos {
	int r, c;
	void init(int r, int c) {
		this->r = r;
		this->c = c;
	}
} q[max_n * max_n], q1[max_n * max_n], q2[max_n * max_n];

void bfs(int i, int j, Pos* q, bool2d &was, int &u) {
	q[0].init(i, j);
	was[i][j] = true;
	u = 1;
	for (int d = 0; d < u; d++) {
		int i = q[d].r, j = q[d].c;
		for (int di = -1; di <= 1; di++) {
			for (int dj = -1; dj <= 1; dj++) {
				int r = i + di, c = j + dj;
				if (r >= 0 && c >= 0 && r < n && c < m) {
					if (!was[r][c]) {
						q[u++].init(r, c);
						was[r][c] = true;
					}
				}
			}
		}
	}
}

int bfs2(int i, int j, int dist) {
	q2[0].init(i, j);
	was2[i][j] = true;
	int u = 1;
	for (int i = 0, d = 0; i < dist; i++) {
		int cu = u;
		for (; d < cu; d++) {
			int i = q2[d].r, j = q2[d].c;
			for (int di = -1; di <= 1; di++) {
				for (int dj = -1; dj <= 1; dj++) {
					int r = i + di, c = j + dj;
					if (r >= 0 && c >= 0 && r < n && c < m) {
						if (!was2[r][c]) {
							q2[u++].init(r, c);
							was2[r][c] = true;
						}
					}
				}
			}
		}
	}
	for (int i = 0; i < u; i++) {
		was2[q2[i].r][q2[i].c] = false;
	}
	return u;
}

vector<int> res;

int main() {
#ifdef pperm
	freopen("input.txt", "r", stdin);
	//freopen("input.txt", "w", stdout);
	//freopen("output.txt", "w", stdout);
#endif
	scanf("%d %d", &n, &m);
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			scanf("%d", &a[i][j]);
			if (!a[i][j]) {
				was[i][j] = was2[i][j] = was3[i][j] = true;
			}
		}
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if (a[i][j] && !was[i][j]) {
				int u;
				bfs(i , j, q, was, u);
				for (int i = 0; i < u; i++) {
					int r = q[i].r, c = q[i].c;
					if (bfs2(r, c, 10) > 90) {
						was3[r][c] = true;
					}
				}
				int cur = 0;
				for (int i = 0; i < u; i++) {
					int r = q[i].r, c = q[i].c;
					if (!was3[r][c]) {
						int q = 0;
						bfs(r, c, q1, was3, q);
						cur++;
					}
				}
				res.push_back(cur);
			}
		}
	}
	printf("%d\n", res.size());
	sort(all(res));
	for (int i = 0; i < res.size(); i++) {
		printf("%d ", res[i]);
	}
#ifdef pperm
	fprintf(stderr, "\n%.3lf\n", clock() / double(CLOCKS_PER_SEC));
#endif
	return 0;
}


#pragma comment(linker, "/STACK:128777216")

#include <cstdio>
#include <cmath>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <vector>
#include <deque>
#include <string>
#include <map>
#include <set>
#include <iostream>
#include <functional>
#include <numeric>
#include <sstream>
#include <exception>
#include <cassert>

typedef long long i64;
typedef unsigned int u32;
const int null = 0;

using namespace std;

template<class T> int size(const T &a) {
	return int(a.size());
}
template<class T> T abs(const T &a) {
	return (a < 0? -a: a);
}
template<class T> T sqr(const T &a) {
	return a * a;
}

#define all(a) a.begin(),a.end()

const int max_n = 2001;

int a[max_n][max_n];
typedef bool bool2d[max_n][max_n];
bool2d was, was2, was3;
int n, m;

struct Pos {
	int r, c;
	void init(int r, int c) {
		this->r = r;
		this->c = c;
	}
} q[max_n * max_n], q1[max_n * max_n], q2[max_n * max_n];

void bfs(int i, int j, Pos* q, bool2d &was, int &u) {
	q[0].init(i, j);
	was[i][j] = true;
	u = 1;
	for (int d = 0; d < u; d++) {
		int i = q[d].r, j = q[d].c;
		for (int di = -1; di <= 1; di++) {
			for (int dj = -1; dj <= 1; dj++) {
				int r = i + di, c = j + dj;
				if (r >= 0 && c >= 0 && r < n && c < m) {
					if (!was[r][c]) {
						q[u++].init(r, c);
						was[r][c] = true;
					}
				}
			}
		}
	}
}

int bfs2(int i, int j, int dist) {
	q2[0].init(i, j);
	was2[i][j] = true;
	int u = 1;
	for (int i = 0, d = 0; i < dist; i++) {
		int cu = u;
		for (; d < cu; d++) {
			int i = q2[d].r, j = q2[d].c;
			for (int di = -1; di <= 1; di++) {
				for (int dj = -1; dj <= 1; dj++) {
					int r = i + di, c = j + dj;
					if (r >= 0 && c >= 0 && r < n && c < m) {
						if (!was2[r][c]) {
							q2[u++].init(r, c);
							was2[r][c] = true;
						}
					}
				}
			}
		}
	}
	for (int i = 0; i < u; i++) {
		was2[q2[i].r][q2[i].c] = false;
	}
	return u;
}

vector<int> res;

int main() {
#ifdef pperm
	freopen("input.txt", "r", stdin);
	//freopen("input.txt", "w", stdout);
	//freopen("output.txt", "w", stdout);
#endif
	scanf("%d %d", &n, &m);
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			scanf("%d", &a[i][j]);
			if (!a[i][j]) {
				was[i][j] = was2[i][j] = was3[i][j] = true;
			}
		}
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if (a[i][j] && !was[i][j]) {
				int u;
				bfs(i , j, q, was, u);
				for (int i = 0; i < u; i++) {
					int r = q[i].r, c = q[i].c;
					if (bfs2(r, c, 10) > 90) {
						was3[r][c] = true;
					}
				}
				int cur = 0;
				for (int i = 0; i < u; i++) {
					int r = q[i].r, c = q[i].c;
					if (!was3[r][c]) {
						int q = 0;
						bfs(r, c, q1, was3, q);
						cur++;
					}
				}
				res.push_back(cur);
			}
		}
	}
	printf("%\n", res.size());
	sort(all(res));
	for (int i = 0; i < res.size(); i++) {
		printf("%d ", res[i]);
	}
#ifdef pperm
	fprintf(stderr, "\n%.3lf\n", clock() / double(CLOCKS_PER_SEC));
#endif
	return 0;
}


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (1600+10)
long long mul(long long a,long long b){return (a*b)%F;}
long long add(long long a,long long b){return (a+b)%F;}
long long sub(long long a,long long b){return (a-b+(a-b)/F*F+F)%F;}
int n,m;
int a[MAXN][MAXN]={0},b[MAXN][MAXN]={0},c[MAXN][MAXN]={0};
void oper1()
{
    memset(b,0,sizeof(b));
    For(i,n) For(j,m)
        if (!(a[i+1][j]&&a[i-1][j]&&a[i][j+1]&&a[i][j-1])&&a[i][j]) b[i][j]=1;
    For(i,n) For(j,m)
        if (b[i][j]) a[i][j]=0;
}
void oper2()
{
    memset(b,0,sizeof(b));
    For(i,n) For(j,m)
        if ((a[i+1][j]||a[i-1][j]||a[i][j+1]||a[i][j-1])&&!a[i][j]) b[i][j]=1;
    For(i,n) For(j,m)
        if (b[i][j]) a[i][j]=1;
}
void pri()
{
    For(i,n)
    {
        For(j,m) cout<<b[i][j]<<' ';cout<<endl;
    }
}
int totblock,ans[MAXN*MAXN]={0},size=0;
void floodray(int x,int y)
{
    b[x][y]=0;totblock++;
    if (b[x+1][y]) floodray(x+1,y);
    if (b[x-1][y]) floodray(x-1,y);
    if (b[x][y+1]) floodray(x,y+1);
    if (b[x][y-1]) floodray(x,y-1);
}
void floodfill(int x,int y)
{
    if (b[x][y]) totblock=0,floodray(x,y)/*,cout<<totblock<<' '*/,ans[size]+=totblock>6;
    c[x][y]=0;
    if (c[x+1][y]) floodfill(x+1,y);
    if (c[x-1][y]) floodfill(x-1,y);
    if (c[x][y+1]) floodfill(x,y+1);
    if (c[x][y-1]) floodfill(x,y-1);
}
int main()
{
    //freopen("21.in.txt","r",stdin);
    //freopen("pic.out","w",stdout);
    cin>>n>>m;
    For(i,n) For(j,m) cin>>a[i][j];
    memcpy(c,a,sizeof(c));
    For(i,4) oper1();
    For(j,5) oper2();
    MEM(b) For(i,n) For(j,m) b[i][j]=(a[i][j]==0&&c[i][j]==1);
    //pri();
    For(i,n) For(j,m) if (c[i][j])
    {
        size++;floodfill(i,j);
    }
    sort(ans+1,ans+1+size);
    cout<<size<<endl;
    For(i,size-1) cout<<ans[i]<<' ';cout<<ans[size]<<endl;
    return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cassert>
#include <ctime>
#include <algorithm>
#include <numeric>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <list>
#include <map>
#include <set>

using namespace std;

#define eprintf(...) fprintf(stderr, __VA_ARGS__)
#define pb push_back
#define mp make_pair
#define sz(x) ((int)(x).size())

typedef long long ll;
typedef vector<ll> vll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<bool> vb;
typedef vector<vb> vvb;
typedef pair<int, int> pii;

const int MAXH = 1700;
const int MAXW = 1700;

const int dx[] = { 1, 0, -1, 0 };
const int dy[] = { 0, 1, 0, -1 };

int f[MAXH][MAXW];
int h, w;
bool check_circ(int x0, int y0, int maxr) {
  int rs = sqrt(maxr) + 5;
  while (rs * rs > maxr) rs--;

  for (int dy = -rs; dy <= rs; dy++)
  for (int dx = -rs; dx <= rs; dx++)
    if (dx * dx + dy * dy <= maxr) {
      int x = x0 + dx, y = y0 + dy;
      if (x < 0 || y < 0 || x >= w || y >= h) return false;
      if (!f[y][x]) return false;
    }
  return true;
}

int was[MAXH][MAXW];

const int C = 5;
int sumx, sumy, sumc;
vector<pii> pts;

void dfs(int x, int y) {
  if (x < 0 || y < 0 || x >= w || y >= h) return;
  if (was[y][x]) return;
  if (!f[y][x]) return;

  bool g = true;
  for (int y1 = -C; y1 <= C; y1++)
  for (int x1 = -C; x1 <= C; x1++) {
    int nx = x + x1, ny = y + y1;
    if (nx < 0 || ny < 0 || nx >= w || ny >= h)
      g = false;
    else
      g = g && f[ny][nx];
  }
  if (g) {
    sumx += x;
    sumy += y;
    sumc++;
  } else {
    pts.pb(mp(x, y));
  }

  was[y][x] = true;
  for (int i = 0; i < 4; i++)
    dfs(x + dx[i], y + dy[i]);
}

double radius;
void dfs2(int x, int y) {
  if (x < 0 || y < 0 || x >= w || y >= h) return;
  if (was[y][x] >= 2) return;
  if (!f[y][x]) return;

  int curd = (x - sumx) * (x - sumx) + (y - sumy) * (y - sumy);
  if (sqrt(curd) <= radius + 3) return;

  was[y][x] = 2;
  for (int i = 0; i < 4; i++)
    dfs2(x + dx[i], y + dy[i]);
}

int main() {
  #ifdef DEBUG
  freopen(".in", "r", stdin);
  freopen(".out", "w", stdout);
  #endif

  while (scanf("%d%d", &h, &w) >= 1) {
    for (int y = 0; y < h; y++)
    for (int x = 0; x < w; x++)
      scanf("%d", &f[y][x]);

    vi anses;

    memset(was, 0, sizeof was);
    for (int y = 0; y < h; y++)
    for (int x = 0; x < w; x++) if (f[y][x] && !was[y][x]) {
      sumx = 0;
      sumy = 0;
      sumc = 0;
      pts.clear();

      dfs(x, y);
      assert(sumc);
      sumx /= sumc;
      sumy /= sumc;
      f[sumy][sumx] = 2;

      int L = 0, R = min(w, h) * min(w, h) + 100;
      while (L + 1 < R) {
        int M = (L + R) / 2;
        if (check_circ(sumx, sumy, M)) L = M;
        else R = M;
      }
      radius = sqrt(L);

      int cans = 0;
      for (int i = 0; i < sz(pts); i++) {
        int x = pts[i].first, y = pts[i].second;
        if (was[y][x] >= 2) continue;

        int cd = (x - sumx) * (x - sumx) + (y - sumy) * (y - sumy);
        if (sqrt(cd) >= radius + 8) {
          cans++;
          dfs2(x, y);
        }
      }
      anses.pb(cans);
    }
    sort(anses.begin(), anses.end());
    printf("%d\n", sz(anses));
    for (int i = 0; i < sz(anses); i++)
      printf("%d%c", anses[i], "\n "[i + 1 < sz(anses)]);
  }
  return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cassert>
#include <ctime>
#include <algorithm>
#include <numeric>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <list>
#include <map>
#include <set>

using namespace std;

#define eprintf(...) fprintf(stderr, __VA_ARGS__)
#define pb push_back
#define mp make_pair
#define sz(x) ((int)(x).size())

typedef long long ll;
typedef vector<ll> vll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<bool> vb;
typedef vector<vb> vvb;
typedef pair<int, int> pii;

const int MAXH = 1700;
const int MAXW = 1700;

const int dx[] = { 1, 0, -1, 0 };
const int dy[] = { 0, 1, 0, -1 };

int f[MAXH][MAXW];
int h, w;
bool check_circ(int x0, int y0, int maxr) {
  int rs = sqrt(maxr) + 5;
  while (rs * rs > maxr) rs--;

  for (int dy = -rs; dy <= rs; dy++)
  for (int dx = -rs; dx <= rs; dx++)
    if (dx * dx + dy * dy <= maxr) {
      int x = x0 + dx, y = y0 + dy;
      if (x < 0 || y < 0 || x >= w || y >= h) return false;
      if (!f[y][x]) return false;
    }
  return true;
}

int was[MAXH][MAXW];

const int C = 5;
int sumx, sumy, sumc;
vector<pii> pts;

void dfs(int x, int y) {
  if (x < 0 || y < 0 || x >= w || y >= h) return;
  if (was[y][x]) return;
  if (!f[y][x]) return;

  bool g = true;
  for (int y1 = -C; y1 <= C; y1++)
  for (int x1 = -C; x1 <= C; x1++) {
    int nx = x + x1, ny = y + y1;
    if (nx < 0 || ny < 0 || nx >= w || ny >= h)
      g = false;
    else
      g = g && f[ny][nx];
  }
  if (g) {
    sumx += x;
    sumy += y;
    sumc++;
  } else {
    pts.pb(mp(x, y));
  }

  was[y][x] = true;
  for (int i = 0; i < 4; i++)
    dfs(x + dx[i], y + dy[i]);
}

double radius;
void dfs2(int x, int y) {
  if (x < 0 || y < 0 || x >= w || y >= h) return;
  if (was[y][x] >= 2) return;
  if (!f[y][x]) return;

  int curd = (x - sumx) * (x - sumx) + (y - sumy) * (y - sumy);
  if (sqrt(curd) <= radius + 5) return;

  was[y][x] = 2;
  for (int i = 0; i < 4; i++)
    dfs2(x + dx[i], y + dy[i]);
}

int main() {
  #ifdef DEBUG
  freopen(".in", "r", stdin);
  freopen(".out", "w", stdout);
  #endif

  while (scanf("%d%d", &h, &w) >= 1) {
    for (int y = 0; y < h; y++)
    for (int x = 0; x < w; x++)
      scanf("%d", &f[y][x]);

    vi anses;

    memset(was, 0, sizeof was);
    for (int y = 0; y < h; y++)
    for (int x = 0; x < w; x++) if (f[y][x] && !was[y][x]) {
      sumx = 0;
      sumy = 0;
      sumc = 0;
      pts.clear();

      dfs(x, y);
      assert(sumc);
      sumx /= sumc;
      sumy /= sumc;
      f[sumy][sumx] = 2;

      int L = 0, R = min(w, h) * min(w, h) + 100;
      while (L + 1 < R) {
        int M = (L + R) / 2;
        if (check_circ(sumx, sumy, M)) L = M;
        else R = M;
      }
      radius = sqrt(L);

      int cans = 0;
      for (int i = 0; i < sz(pts); i++) {
        int x = pts[i].first, y = pts[i].second;

        int cd = (x - sumx) * (x - sumx) + (y - sumy) * (y - sumy);
        if (sqrt(cd) <= radius + 6) continue;
        f[y][x] = 3;
        if (was[y][x] >= 2) continue;

        cans++;
        dfs2(x, y);
      }
      anses.pb(cans);
    }
    #ifdef DEBUG
    for (int y = 0; y < h; y++)
    for (int x = 0; x < w; x++)
      printf("%d%c", f[y][x], "\n "[x + 1 < w]);
    #endif

    sort(anses.begin(), anses.end());
    printf("%d\n", sz(anses));
    for (int i = 0; i < sz(anses); i++)
      printf("%d%c", anses[i], "\n "[i + 1 < sz(anses)]);
  }
  return 0;
}


#include <cstdio>
#include <cstring>
#include <algorithm>
#define probaj(x,y) if(LoopPart[x][y]==sunac){xc=x;yc=y;goto zajedno;}
using namespace std;

int D[1605][1605],N,M;
int A[1605][1605],RayPart[1605][1605],LoopPart[1605][1605];
int Zraka[1000];

void ucitaj(){
    int i,j;
    scanf("%d%d",&N,&M);
    for (i=1; i<=N; i++){
        for (j=1; j<=M; j++) scanf("%d",A[i]+j);
    }
}

int Qx[2560005],Qy[2560005],qs,qe,suns;

void obidji0(int x,int y){
    if (x<1 || x>N || y<1 || y>M) return;
    if (D[x][y] != 0) return;
    if (A[x][y] == 0) return;
    qe++;
    Qx[qe] = x;
    Qy[qe] = y;
    D[x][y] = suns;
}

void bfs0(int x,int y){
    suns++;
    qs=1;
    qe=1;
    Qx[1] = x;
    Qy[1] = y;
    while (qs<=qe){
        x = Qx[qs];
        y = Qy[qs];
        qs++;
        obidji0(x+1,y);
        obidji0(x-1,y);
        obidji0(x,y+1);
        obidji0(x,y-1);
    }
}

void find_suns(){
    int x,y;
    for (x=1; x<=N; x++){
        for (y=1; y<=M; y++){
            if (D[x][y] == 0 && A[x][y] == 1) bfs0(x,y);
        }
    }
}

inline int sun_index(int x,int y){
    if (x<1 || x>N || y<1 || y>M) return 0;
    return D[x][y];
}

void find_rays(){
    int x,y,dx,dy;
    bool found;
    for (x=1; x<=N; x++){
        for (y=1; y<=M; y++){
            //uslov:
            //da pripadaju krugu
            //da u njihovoj 1,2,3-okolini postoji polje koje ne pripada krugu
            if (D[x][y] != 0){
                found=false;
                for (dy=-3; dy<=3; dy++){
                    for (dx=abs(dy)-3; dx<=3-abs(dy); dx++){
                        if (sun_index(x+dx,y+dy)==0){
                            found=true;
                            goto fuck;
                        }
                    }
                }
                fuck:
                if (found) RayPart[x][y] = D[x][y];
            }
        }
    }
}

int pknz(int x,int y){
    if (x<1 || x>N || y<1 || y>M) return 0;
    if (RayPart[x][y]!=0) return 0;
    return D[x][y];
}

void find_loops(){
    int x,y,dx,dy;
    int found5;
    bool found4;
    for (x=1; x<=N; x++){
        for (y=1; y<=M; y++){
            //uslov
            //da njihova 4-okolina ne sadrzi polje koje pripada krugu i nije zrak, ali da 5-okolina sadrzi
            found4=false;
            for (dx=-6; dx<=6; dx++){
                if (pknz(x+dx,y+6-abs(dx))!=0 || pknz(x+dx,y-(6-abs(dx)))!=0){
                    found4=true;
                    break;
                }
            }
            if (found4) continue;
            found5=0;
            for (dx=-7; dx<=7; dx++){
                found5 = pknz(x+dx,y+7-abs(dx));
                if (found5!=0) break;
                found5 = pknz(x+dx,y-(7-abs(dx)));
                if (found5!=0) break;
            }
            if (found5!=0){
                LoopPart[x][y] = found5;
                //printf("loop of %d : %d %d\n",found5,x,y);
            }
        }
    }
}

void traverse_loops(){
    int x,y,xc,yc,pres,i,j,sunac,len;
    for (x=1; x<=N; x++){
        for (y=1; y<=M; y++){
            if (LoopPart[x][y]!=0 && RayPart[x][y]==0){
                //krecemo da se zebavamo po tu oblas
                xc=x;
                yc=y;
                sunac = LoopPart[x][y];
                pres = 0;
                len = 0;
                while (true){
                    len++;
                    //brisemo postojanja
                    LoopPart[xc][yc] = 0;
                    j = RayPart[xc][yc];
                    //trazimo suseda u kog cemo da idemo
                    if (LoopPart[xc+1][yc] == sunac){
                        xc++;
                        goto zajedno;
                    }
                    if (LoopPart[xc-1][yc] == sunac){
                        xc--;
                        goto zajedno;
                    }
                    if (LoopPart[xc][yc+1] == sunac){
                        yc++;
                        goto zajedno;
                    }
                    if (LoopPart[xc][yc-1] == sunac){
                        yc--;
                        goto zajedno;
                    }
                    //onda po dijagonali
                    if (LoopPart[xc+1][yc+1] == sunac){
                        xc++;
                        yc++;
                        goto zajedno;
                    }
                    if (LoopPart[xc-1][yc+1] == sunac){
                        xc--;
                        yc++;
                        goto zajedno;
                    }
                    if (LoopPart[xc+1][yc-1] == sunac){
                        xc++;
                        yc--;
                        goto zajedno;
                    }
                    if (LoopPart[xc-1][yc-1] == sunac){
                        xc--;
                        yc--;
                        goto zajedno;
                    }
                    //nismo nasli suseda
                    //printf("%d %d\n",sunac,len);
                    break;
                    zajedno:
                    if (RayPart[xc][yc]==sunac && j==0) pres++;
                }
                if (len > 50) Zraka[sunac] = pres;
            }
        }
    }
}

void printem(){
    sort(Zraka+1,Zraka+suns+1);
    printf("%d\n",suns);
    for (int i=1; i<=suns; i++) printf("%d%c",Zraka[i],i==suns?'\n':' ');
}

int main(){
    //freopen("21.in.txt","r",stdin);
    ucitaj();
    find_suns();
    find_rays();
    find_loops();
    traverse_loops();
    printem();
    return 0;
}


#include <cstdio>
#include <cstring>
#include <algorithm>
#define probaj(x,y) if(LoopPart[x][y]==sunac){xc=x;yc=y;goto zajedno;}
using namespace std;

int D[1605][1605],N,M;
int A[1605][1605],RayPart[1605][1605],LoopPart[1605][1605];
int Zraka[1000];

void ucitaj(){
    int i,j;
    scanf("%d%d",&N,&M);
    for (i=1; i<=N; i++){
        for (j=1; j<=M; j++) scanf("%d",A[i]+j);
    }
}

int Qx[2560005],Qy[2560005],qs,qe,suns;

void obidji0(int x,int y){
    if (x<1 || x>N || y<1 || y>M) return;
    if (D[x][y] != 0) return;
    if (A[x][y] == 0) return;
    qe++;
    Qx[qe] = x;
    Qy[qe] = y;
    D[x][y] = suns;
}

void bfs0(int x,int y){
    suns++;
    qs=1;
    qe=1;
    Qx[1] = x;
    Qy[1] = y;
    while (qs<=qe){
        x = Qx[qs];
        y = Qy[qs];
        qs++;
        obidji0(x+1,y);
        obidji0(x-1,y);
        obidji0(x,y+1);
        obidji0(x,y-1);
    }
}

void find_suns(){
    int x,y;
    for (x=1; x<=N; x++){
        for (y=1; y<=M; y++){
            if (D[x][y] == 0 && A[x][y] == 1) bfs0(x,y);
        }
    }
}

inline int sun_index(int x,int y){
    if (x<1 || x>N || y<1 || y>M) return 0;
    return D[x][y];
}

void find_rays(){
    int x,y,dx,dy;
    bool found;
    for (x=1; x<=N; x++){
        for (y=1; y<=M; y++){
            //uslov:
            //da pripadaju krugu
            //da u njihovoj 1,2,3-okolini postoji polje koje ne pripada krugu
            if (D[x][y] != 0){
                found=false;
                for (dy=-3; dy<=3; dy++){
                    for (dx=abs(dy)-3; dx<=3-abs(dy); dx++){
                        if (sun_index(x+dx,y+dy)==0){
                            found=true;
                            goto fuck;
                        }
                    }
                }
                fuck:
                if (found) RayPart[x][y] = D[x][y];
            }
        }
    }
}

int pknz(int x,int y){
    if (x<1 || x>N || y<1 || y>M) return 0;
    if (RayPart[x][y]!=0) return 0;
    return D[x][y];
}

void find_loops(){
    int x,y,dx,dy;
    int found5;
    bool found4;
    for (x=1; x<=N; x++){
        for (y=1; y<=M; y++){
            //uslov
            //da njihova 4-okolina ne sadrzi polje koje pripada krugu i nije zrak, ali da 5-okolina sadrzi
            found4=false;
            for (dx=-6; dx<=6; dx++){
                if (pknz(x+dx,y+6-abs(dx))!=0 || pknz(x+dx,y-(6-abs(dx)))!=0){
                    found4=true;
                    break;
                }
            }
            if (found4) continue;
            found5=0;
            for (dx=-7; dx<=7; dx++){
                found5 = pknz(x+dx,y+7-abs(dx));
                if (found5!=0) break;
                found5 = pknz(x+dx,y-(7-abs(dx)));
                if (found5!=0) break;
            }
            if (found5!=0){
                LoopPart[x][y] = found5;
                //printf("loop of %d : %d %d\n",found5,x,y);
            }
        }
    }
}

void traverse_loops(){
    int x,y,xc,yc,pres,i,j,sunac,len;
    for (x=1; x<=N; x++){
        for (y=1; y<=M; y++){
            if (LoopPart[x][y]!=0 && RayPart[x][y]==0){
                //krecemo da se zebavamo po tu oblas
                xc=x;
                yc=y;
                sunac = LoopPart[x][y];
                pres = 0;
                len = 0;
                while (true){
                    len++;
                    //brisemo postojanja
                    LoopPart[xc][yc] = 0;
                    j = RayPart[xc][yc];
                    //trazimo suseda u kog cemo da idemo
                    if (LoopPart[xc+1][yc] == sunac){
                        xc++;
                        goto zajedno;
                    }
                    if (LoopPart[xc-1][yc] == sunac){
                        xc--;
                        goto zajedno;
                    }
                    if (LoopPart[xc][yc+1] == sunac){
                        yc++;
                        goto zajedno;
                    }
                    if (LoopPart[xc][yc-1] == sunac){
                        yc--;
                        goto zajedno;
                    }
                    //onda po dijagonali
                    if (LoopPart[xc+1][yc+1] == sunac){
                        xc++;
                        yc++;
                        goto zajedno;
                    }
                    if (LoopPart[xc-1][yc+1] == sunac){
                        xc--;
                        yc++;
                        goto zajedno;
                    }
                    if (LoopPart[xc+1][yc-1] == sunac){
                        xc++;
                        yc--;
                        goto zajedno;
                    }
                    if (LoopPart[xc-1][yc-1] == sunac){
                        xc--;
                        yc--;
                        goto zajedno;
                    }
                    //nismo nasli suseda
                    //printf("%d %d\n",sunac,len);
                    break;
                    zajedno:
                    if (RayPart[xc][yc]==sunac && j==0) pres++;
                }
                if (len > 50) Zraka[sunac] = pres;
            }
        }
    }
}

void printem(){
    sort(Zraka+1,Zraka+suns+1);
    printf("%d\n",suns);
    for (int i=1; i<=suns; i++) printf("%d%c",Zraka[i],i==suns?'\n':' ');
}

int main(){
    freopen("21.in.txt","r",stdin);
    ucitaj();
    find_suns();
    find_rays();
    find_loops();
    traverse_loops();
    printem();
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define rep(i,n,N) for(int i = n; i<=N; i++)
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
const int MAX = 1600 + 5;
const int dr[] = {0,0,1,-1,1,-1,1,-1};
const int dc[] = {1,-1,0,0,1,1,-1,-1};

int n,m,nr,nc,cnt,ct;
bool grid[MAX][MAX], x[MAX][MAX], y[MAX][MAX], z[MAX][MAX], val;
vector<int> ans;
pii cur;
bool inside(int r,int c){
	if(r>0 && r<=n && c>0 && c<=m)return 1;
	return 0;
}
void dfs(int r,int c){
	grid[r][c] = 0;
	x[r][c] = 1;
	rep(i,0,4){
		nr = r+dr[i], nc = c+dc[i];
		if(!grid[nr][nc])continue;
		dfs(nr,nc);
	}
}
void cs(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!x[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		if(val){
			y[r][c] = 1;
			rep(k,0,7)y[r+dr[k]][c+dc[k]] = 1;
		}
	}
}
void cas(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+2,c+2))continue;
		val = 1;
		rep(i,r-1,r+2)rep(j,c-1,c+2)if(!x[i][j]){
			val = 0; break;
		}
		if(val)rep(i,r-1,r+1)rep(j,c-2,c+2)z[i][j] = 1;
	}
	rep(r,1,n)rep(c,1,n)z[r][c]^=y[r][c];
}
void cast(){
	rep(r,1,n)rep(c,1,m){
		if(!z[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!z[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		y[r][c] = val;
	}
}
void df(int r,int c){
	ct++;
	y[r][c] = 0;
	rep(i,0,7){
		nr = r+dr[i], nc = c+dc[i];
		if(!y[nr][nc])continue;
		df(nr,nc);
	}
}
void hit(){
	rep(i,1,n)rep(j,1,m){
		if(!y[i][j])continue;
		ct = 0;
		df(i,j);
		if(ct>8)cnt++;
	}
}

int main(){
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin>>n>>m;
	rep(i,1,n)rep(j,1,m)cin>>grid[i][j];
	rep(i,1,n)rep(j,1,n){
		if(!grid[i][j])continue;
		memset(x,0,sizeof x);
		memset(y,0,sizeof y);
		memset(z,0,sizeof z);
		dfs(i,j);
		cs();
		cas();
		cast();
		cnt = 0;
		hit();
		ans.pb(cnt);
	}
	sort(ans.begin(),ans.end());
	cout<<ans.size()<<endl;
	for(auto i:ans)cout<<i<<" ";
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define rep(i,n,N) for(int i = n; i<=N; i++)
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
const int MAX = 1600 + 5;
const int dr[] = {0,0,1,-1,1,-1,1,-1};
const int dc[] = {1,-1,0,0,1,1,-1,-1};

int n,m,nr,nc,cnt,ct;
bool grid[MAX][MAX], x[MAX][MAX], y[MAX][MAX], z[MAX][MAX], val;
vector<int> ans;
pii cur;
bool inside(int r,int c){
	if(r>0 && r<=n && c>0 && c<=m)return 1;
	return 0;
}
void dfs(int r,int c){
	grid[r][c] = 0;
	x[r][c] = 1;
	rep(i,0,3){
		nr = r+dr[i], nc = c+dc[i];
		if(!grid[nr][nc])continue;
		dfs(nr,nc);
	}
}
void cs(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!x[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		if(val){
			y[r][c] = 1;
			rep(k,0,7)y[r+dr[k]][c+dc[k]] = 1;
		}
	}
}
void cas(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+2,c+2))continue;
		val = 1;
		rep(i,r-1,r+2)rep(j,c-1,c+2)if(!x[i][j]){
			val = 0; break;
		}
		if(val)rep(i,r-1,r+2)rep(j,c-1,c+2)z[i][j] = 1;
	}
	rep(r,1,n)rep(c,1,n)z[r][c]^=y[r][c];
}
void cast(){
	rep(r,1,n)rep(c,1,m){
		if(!z[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!z[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		y[r][c] = val;
	}
}
void df(int r,int c){
	ct++;
	y[r][c] = 0;
	rep(i,0,7){
		nr = r+dr[i], nc = c+dc[i];
		if(!y[nr][nc])continue;
		df(nr,nc);
	}
}
void hit(){
	rep(i,1,n)rep(j,1,m){
		if(!y[i][j])continue;
		ct = 0;
		df(i,j);
		if(ct>5)cnt++;
	}
}

int main(){
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin>>n>>m;
	rep(i,1,n)rep(j,1,m)cin>>grid[i][j];
	rep(i,1,n)rep(j,1,n){
		if(!grid[i][j])continue;
		memset(x,0,sizeof x);
		memset(y,0,sizeof y);
		memset(z,0,sizeof z);
		dfs(i,j);
		cs();
		cas();
		memset(y,0,sizeof y);
		cast();
		cnt = 0;
		hit();
		ans.pb(cnt);
	}
	sort(ans.begin(),ans.end());
	cout<<ans.size()<<endl;
	for(auto i:ans)cout<<i<<" ";
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define rep(i,n,N) for(int i = n; i<=N; i++)
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
const int MAX = 1600 + 5;
const int dr[] = {0,0,1,-1,1,-1,1,-1};
const int dc[] = {1,-1,0,0,1,1,-1,-1};

int n,m,nr,nc,cnt,ct;
bool grid[MAX][MAX], x[MAX][MAX], y[MAX][MAX], z[MAX][MAX], val;
vector<int> ans;
pii cur;
bool inside(int r,int c){
	if(r>0 && r<=n && c>0 && c<=m)return 1;
	return 0;
}
void dfs(int r,int c){
	grid[r][c] = 0;
	x[r][c] = 1;
	rep(i,0,3){
		nr = r+dr[i], nc = c+dc[i];
		if(!grid[nr][nc])continue;
		dfs(nr,nc);
	}
}
void cs(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!x[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		if(val){
			y[r][c] = 1;
			rep(k,0,7)y[r+dr[k]][c+dc[k]] = 1;
		}
	}
}
void cas(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+2,c+2))continue;
		val = 1;
		rep(i,r-1,r+2)rep(j,c-1,c+2)if(!x[i][j]){
			val = 0; break;
		}
		if(val)rep(i,r-1,r+2)rep(j,c-1,c+2)z[i][j] = 1;
	}
	rep(r,1,n)rep(c,1,n)z[r][c]^=y[r][c];
}
void cast(){
	rep(r,1,n)rep(c,1,m){
		if(!z[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!z[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		y[r][c] = val;
	}
}
void df(int r,int c){
	ct++;
	y[r][c] = 0;
	rep(i,0,7){
		nr = r+dr[i], nc = c+dc[i];
		if(!y[nr][nc])continue;
		df(nr,nc);
	}
}
void hit(){
	rep(i,1,n)rep(j,1,m){
		if(!y[i][j])continue;
		ct = 0;
		df(i,j);
		if(ct>1)cnt++;
	}
}

int main(){
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin>>n>>m;
	rep(i,1,n)rep(j,1,m)cin>>grid[i][j];
	rep(i,1,n)rep(j,1,n){
		if(!grid[i][j])continue;
		memset(x,0,sizeof x);
		memset(y,0,sizeof y);
		memset(z,0,sizeof z);
		dfs(i,j);
		cs();
		cas();
		memset(y,0,sizeof y);
		cast();
		cnt = 0;
		hit();
		ans.pb(cnt);
	}
	sort(ans.begin(),ans.end());
	cout<<ans.size()<<endl;
	for(auto i:ans)cout<<i<<" ";
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define rep(i,n,N) for(int i = n; i<=N; i++)
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
const int MAX = 1600 + 5;
const int dr[] = {0,0,1,-1,1,-1,1,-1};
const int dc[] = {1,-1,0,0,1,1,-1,-1};

int n,m,nr,nc,cnt,ct;
bool grid[MAX][MAX], x[MAX][MAX], y[MAX][MAX], z[MAX][MAX], val;
vector<int> ans;
pii cur;
bool inside(int r,int c){
	if(r>0 && r<=n && c>0 && c<=m)return 1;
	return 0;
}
void dfs(int r,int c){
	grid[r][c] = 0;
	x[r][c] = 1;
	rep(i,0,4){
		nr = r+dr[i], nc = c+dc[i];
		if(!grid[nr][nc])continue;
		dfs(nr,nc);
	}
}
void cs(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!x[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		if(val){
			y[r][c] = 1;
			rep(k,0,7)y[r+dr[k]][c+dc[k]] = 1;
		}
	}
}
void cas(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-2,c-2))continue;
		if(!inside(r+2,c+2))continue;
		val = 1;
		rep(i,r-2,r+2)rep(j,c-2,c+2)if(!x[i][j]){
			val = 0; break;
		}
		if(val)rep(i,r-2,r+2)rep(j,c-2,c+2)z[i][j] = 1;
	}
	rep(r,1,n)rep(c,1,n)z[r][c]^=y[r][c];
}
void cast(){
	rep(r,1,n)rep(c,1,m){
		if(!z[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!z[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		y[r][c] = val;
	}
}
void df(int r,int c){
	ct++;
	y[r][c] = 0;
	rep(i,0,7){
		nr = r+dr[i], nc = c+dc[i];
		if(!y[nr][nc])continue;
		df(nr,nc);
	}
}
void hit(){
	rep(i,1,n)rep(j,1,m){
		if(!y[i][j])continue;
		ct = 0;
		df(i,j);
		if(ct>9)cnt++;
	}
}

int main(){
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin>>n>>m;
	rep(i,1,n)rep(j,1,m)cin>>grid[i][j];
	rep(i,1,n)rep(j,1,n){
		if(!grid[i][j])continue;
		memset(x,0,sizeof x);
		memset(y,0,sizeof y);
		memset(z,0,sizeof z);
		dfs(i,j);
		cs();
		cas();
		cast();
		cnt = 0;
		hit();
		ans.pb(cnt);
	}
	sort(ans.begin(),ans.end());
	cout<<ans.size()<<endl;
	for(auto i:ans)cout<<i<<" ";
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define rep(i,n,N) for(int i = n; i<=N; i++)
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
const int MAX = 1600 + 5;
const int dr[] = {0,0,1,-1,1,-1,1,-1};
const int dc[] = {1,-1,0,0,1,1,-1,-1};

int n,m,nr,nc,cnt,ct;
bool grid[MAX][MAX], x[MAX][MAX], y[MAX][MAX], z[MAX][MAX], val;
vector<int> ans;
pii cur;
bool inside(int r,int c){
	if(r>0 && r<=n && c>0 && c<=m)return 1;
	return 0;
}
void dfs(int r,int c){
	grid[r][c] = 0;
	x[r][c] = 1;
	rep(i,0,3){
		nr = r+dr[i], nc = c+dc[i];
		if(!grid[nr][nc])continue;
		dfs(nr,nc);
	}
}
void cs(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!x[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		if(val){
			y[r][c] = 1;
			rep(k,0,7)y[r+dr[k]][c+dc[k]] = 1;
		}
	}
}
void cas(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-2,c-2))continue;
		if(!inside(r+2,c+2))continue;
		val = 1;
		rep(i,r-2,r+2)rep(j,c-2,c+2)if(!x[i][j]){
			val = 0; break;
		}
		if(val)rep(i,r-2,r+2)rep(j,c-2,c+2)z[i][j] = 1;
	}
	rep(r,1,n)rep(c,1,n)z[r][c]^=y[r][c];
}
void cast(){
	rep(r,1,n)rep(c,1,m){
		if(!z[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!z[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		y[r][c] = val;
	}
}
void df(int r,int c){
	ct++;
	y[r][c] = 0;
	rep(i,0,7){
		nr = r+dr[i], nc = c+dc[i];
		if(!y[nr][nc])continue;
		df(nr,nc);
	}
}
void hit(){
	rep(i,1,n)rep(j,1,m){
		if(!y[i][j])continue;
		ct = 0;
		df(i,j);
		if(ct>3)cnt++;
	}
}

int main(){
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin>>n>>m;
	rep(i,1,n)rep(j,1,m)cin>>grid[i][j];
	rep(i,1,n)rep(j,1,n){
		if(!grid[i][j])continue;
		memset(x,0,sizeof x);
		memset(y,0,sizeof y);
		memset(z,0,sizeof z);
		dfs(i,j);
		cs();
		cas();
		memset(y,0,sizeof y);
		cast();
		cnt = 0;
		hit();
		ans.pb(cnt);
	}
	sort(ans.begin(),ans.end());
	cout<<ans.size()<<endl;
	for(auto i:ans)cout<<i<<" ";
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define rep(i,n,N) for(int i = n; i<=N; i++)
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
const int MAX = 1600 + 5;
const int dr[] = {0,0,1,-1,1,-1,1,-1};
const int dc[] = {1,-1,0,0,1,1,-1,-1};

int n,m,nr,nc,cnt,ct;
bool grid[MAX][MAX], x[MAX][MAX], y[MAX][MAX], z[MAX][MAX], val;
vector<int> ans;
pii cur;
bool inside(int r,int c){
	if(r>0 && r<=n && c>0 && c<=m)return 1;
	return 0;
}
void dfs(int r,int c){
	grid[r][c] = 0;
	x[r][c] = 1;
	rep(i,0,3){
		nr = r+dr[i], nc = c+dc[i];
		if(!grid[nr][nc])continue;
		dfs(nr,nc);
	}
}
void cs(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!x[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		if(val){
			y[r][c] = 1;
			rep(k,0,7)y[r+dr[k]][c+dc[k]] = 1;
		}
	}
}
void cas(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+2,c+2))continue;
		val = 1;
		rep(i,r-1,r+2)rep(j,c-1,c+2)if(!x[i][j]){
			val = 0; break;
		}
		if(val)rep(i,r-1,r+2)rep(j,c-1,c+2)z[i][j] = 1;
	}
	rep(r,1,n)rep(c,1,n)z[r][c]^=y[r][c];
}
void cast(){
	rep(r,1,n)rep(c,1,m){
		if(!z[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!z[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		y[r][c] = val;
	}
}
void df(int r,int c){
	ct++;
	y[r][c] = 0;
	rep(i,0,7){
		nr = r+dr[i], nc = c+dc[i];
		if(!y[nr][nc])continue;
		df(nr,nc);
	}
}
void hit(){
	rep(i,1,n)rep(j,1,m){
		if(!y[i][j])continue;
		ct = 0;
		df(i,j);
		if(ct>6)cnt++;
	}
}

int main(){
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin>>n>>m;
	rep(i,1,n)rep(j,1,m)cin>>grid[i][j];
	rep(i,1,n)rep(j,1,n){
		if(!grid[i][j])continue;
		memset(x,0,sizeof x);
		memset(y,0,sizeof y);
		memset(z,0,sizeof z);
		dfs(i,j);
		cs();
		cas();
		memset(y,0,sizeof y);
		cast();
		cnt = 0;
		hit();
		ans.pb(cnt);
	}
	sort(ans.begin(),ans.end());
	cout<<ans.size()<<endl;
	for(auto i:ans)cout<<i<<" ";
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define rep(i,n,N) for(int i = n; i<=N; i++)
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
const int MAX = 1600 + 5;
const int dr[] = {0,0,1,-1,1,-1,1,-1};
const int dc[] = {1,-1,0,0,1,1,-1,-1};

int n,m,nr,nc,cnt,ct;
bool grid[MAX][MAX], x[MAX][MAX], y[MAX][MAX], z[MAX][MAX], val;
vector<int> ans;
pii cur;
bool inside(int r,int c){
	if(r>0 && r<=n && c>0 && c<=m)return 1;
	return 0;
}
void dfs(int r,int c){
	grid[r][c] = 0;
	x[r][c] = 1;
	rep(i,0,7){
		nr = r+dr[i], nc = c+dc[i];
		if(!grid[nr][nc])continue;
		dfs(nr,nc);
	}
}
void cs(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!x[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		if(val){
			y[r][c] = 1;
			rep(k,0,7)y[r+dr[k]][c+dc[k]] = 1;
		}
	}
}
void cas(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-2,c-2))continue;
		if(!inside(r+2,c+2))continue;
		val = 1;
		rep(i,r-2,r+2)rep(j,c-2,c+2)if(!x[i][j]){
			val = 0; break;
		}
		if(val)rep(i,r-2,r+2)rep(j,c-2,c+2)z[i][j] = 1;
	}
	rep(r,1,n)rep(c,1,n)z[r][c]^=y[r][c];
}
void cast(){
	rep(r,1,n)rep(c,1,m){
		if(!z[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!z[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		y[r][c] = val;
	}
}
void df(int r,int c){
	ct++;
	y[r][c] = 0;
	rep(i,0,7){
		nr = r+dr[i], nc = c+dc[i];
		if(!y[nr][nc])continue;
		df(nr,nc);
	}
}
void hit(){
	rep(i,1,n)rep(j,1,m){
		if(!y[i][j])continue;
		//ct = 0;
		//if(ct>3)
		df(i,j);
		cnt++;
	}
}

int main(){
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin>>n>>m;
	rep(i,1,n)rep(j,1,m)cin>>grid[i][j];
	rep(i,1,n)rep(j,1,n){
		if(!grid[i][j])continue;
		memset(x,0,sizeof x);
		memset(y,0,sizeof y);
		memset(z,0,sizeof z);
		dfs(i,j);
		cs();
		cas();
		memset(y,0,sizeof y);
		cast();
		cnt = 0;
		hit();
		ans.pb(cnt);
	}
	sort(ans.begin(),ans.end());
	cout<<ans.size()<<endl;
	for(auto i:ans)cout<<i<<" ";
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define rep(i,n,N) for(int i = n; i<=N; i++)
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
const int MAX = 1600 + 5;
const int dr[] = {0,0,1,-1,1,-1,1,-1};
const int dc[] = {1,-1,0,0,1,1,-1,-1};

int n,m,nr,nc,cnt,ct;
bool grid[MAX][MAX], x[MAX][MAX], y[MAX][MAX], z[MAX][MAX], val;
vector<int> ans;
pii cur;
bool inside(int r,int c){
	if(r>0 && r<=n && c>0 && c<=m)return 1;
	return 0;
}
void dfs(int r,int c){
	grid[r][c] = 0;
	x[r][c] = 1;
	rep(i,0,3){
		nr = r+dr[i], nc = c+dc[i];
		if(!grid[nr][nc])continue;
		dfs(nr,nc);
	}
}
void cs(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!x[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		if(val){
			y[r][c] = 1;
			rep(k,0,7)y[r+dr[k]][c+dc[k]] = 1;
		}
	}
}
void cas(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-2,c-2))continue;
		if(!inside(r+2,c+2))continue;
		val = 1;
		rep(i,r-2,r+2)rep(j,c-2,c+2)if(!x[i][j]){
			val = 0; break;
		}
		if(val)rep(i,r-2,r+2)rep(j,c-2,c+2)z[i][j] = 1;
	}
	rep(r,1,n)rep(c,1,m)z[r][c]^=y[r][c];
}
void cast(){
	rep(r,1,n)rep(c,1,m){
		if(!z[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!z[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		y[r][c] = val;
	}
}
void df(int r,int c){
	ct++;
	y[r][c] = 0;
	rep(i,0,7){
		nr = r+dr[i], nc = c+dc[i];
		if(!y[nr][nc])continue;
		df(nr,nc);
	}
}
void hit(){
	rep(i,1,n)rep(j,1,m){
		if(!y[i][j])continue;
		ct = 0;
		df(i,j);
		if(ct>3)cnt++;
	}
}

int main(){
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin>>n>>m;
	rep(i,1,n)rep(j,1,m)cin>>grid[i][j];
	rep(i,1,n)rep(j,1,n){
		if(!grid[i][j])continue;
		memset(x,0,sizeof x);
		memset(y,0,sizeof y);
		memset(z,0,sizeof z);
		dfs(i,j);
		cs();
		cas();
		memset(y,0,sizeof y);
		cast();
		cnt = 0;
		hit();
		ans.pb(cnt);
	}
	sort(ans.begin(),ans.end());
	cout<<ans.size()<<endl;
	for(auto i:ans)cout<<i<<" ";
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define rep(i,n,N) for(int i = n; i<=N; i++)
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
const int MAX = 1600 + 5;
const int dr[] = {0,0,1,-1,1,-1,1,-1};
const int dc[] = {1,-1,0,0,1,1,-1,-1};

int n,m,nr,nc,cnt,ct;
bool grid[MAX][MAX], x[MAX][MAX], y[MAX][MAX], z[MAX][MAX], val;
vector<int> ans;
pii cur;
bool inside(int r,int c){
	if(r>0 && r<=n && c>0 && c<=m)return 1;
	return 0;
}
void dfs(int r,int c){
	grid[r][c] = 0;
	x[r][c] = 1;
	rep(i,0,3){
		nr = r+dr[i], nc = c+dc[i];
		if(!grid[nr][nc])continue;
		dfs(nr,nc);
	}
}
void cs(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!x[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		if(val){
			y[r][c] = 1;
			rep(k,0,7)y[r+dr[k]][c+dc[k]] = 1;
		}
	}
}
void cas(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-2,c-2))continue;
		if(!inside(r+2,c+2))continue;
		val = 1;
		rep(i,r-2,r+2)rep(j,c-2,c+2)if(!x[i][j]){
			val = 0; break;
		}
		if(val)rep(i,r-2,r+2)rep(j,c-2,c+2)z[i][j] = 1;
	}
	rep(r,1,n)rep(c,1,m)z[r][c]^=y[r][c];
}
void cast(){
	rep(r,1,n)rep(c,1,m){
		if(!z[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!z[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		y[r][c] = val;
	}
}
void df(int r,int c){
	ct++;
	y[r][c] = 0;
	rep(i,0,7){
		nr = r+dr[i], nc = c+dc[i];
		if(!y[nr][nc])continue;
		df(nr,nc);
	}
}
void hit(){
	rep(i,1,n)rep(j,1,m){
		if(!y[i][j])continue;
		//ct = 0;
		//if(ct>3)
		df(i,j);
		cnt++;
	}
}

int main(){
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin>>n>>m;
	rep(i,1,n)rep(j,1,m)cin>>grid[i][j];
	rep(i,1,n)rep(j,1,n){
		if(!grid[i][j])continue;
		memset(x,0,sizeof x);
		memset(y,0,sizeof y);
		memset(z,0,sizeof z);
		dfs(i,j);
		cs();
		cas();
		memset(y,0,sizeof y);
		cast();
		cnt = 0;
		hit();
		ans.pb(cnt);
	}
	sort(ans.begin(),ans.end());
	cout<<ans.size()<<endl;
	for(auto i:ans)cout<<i<<" ";
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define rep(i,n,N) for(int i = n; i<=N; i++)
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
const int MAX = 1600 + 5;
const int dr[] = {0,0,1,-1,1,-1,1,-1};
const int dc[] = {1,-1,0,0,1,1,-1,-1};

int n,m,nr,nc,cnt,ct;
bool grid[MAX][MAX], x[MAX][MAX], y[MAX][MAX], z[MAX][MAX], val;
vector<int> ans;
pii cur;
bool inside(int r,int c){
	if(r>0 && r<=n && c>0 && c<=m)return 1;
	return 0;
}
void dfs(int r,int c){
	grid[r][c] = 0;
	x[r][c] = 1;
	rep(i,0,3){
		nr = r+dr[i], nc = c+dc[i];
		if(!grid[nr][nc])continue;
		dfs(nr,nc);
	}
}
void cs(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!x[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		if(val){
			y[r][c] = 1;
			rep(k,0,7)y[r+dr[k]][c+dc[k]] = 1;
		}
	}
}
void cas(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+2,c+2))continue;
		val = 1;
		rep(i,r-1,r+2)rep(j,c-1,c+2)if(!x[i][j]){
			val = 0; break;
		}
		if(val)rep(i,r-1,r+2)rep(j,c-1,c+2)z[i][j] = 1;
	}
	rep(r,1,n)rep(c,1,n)z[r][c]^=y[r][c];
}
void cast(){
	rep(r,1,n)rep(c,1,m){
		if(!z[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!z[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		y[r][c] = val;
	}
}
void df(int r,int c){
	ct++;
	y[r][c] = 0;
	rep(i,0,7){
		nr = r+dr[i], nc = c+dc[i];
		if(!y[nr][nc])continue;
		df(nr,nc);
	}
}
void hit(){
	rep(i,1,n)rep(j,1,m){
		if(!y[i][j])continue;
		ct = 0;
		df(i,j);
		if(ct>8)cnt++;
	}
}

int main(){
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin>>n>>m;
	rep(i,1,n)rep(j,1,m)cin>>grid[i][j];
	rep(i,1,n)rep(j,1,n){
		if(!grid[i][j])continue;
		memset(x,0,sizeof x);
		memset(y,0,sizeof y);
		memset(z,0,sizeof z);
		dfs(i,j);
		cs();
		cas();
		memset(y,0,sizeof y);
		cast();
		cnt = 0;
		hit();
		ans.pb(cnt);
	}
	sort(ans.begin(),ans.end());
	cout<<ans.size()<<endl;
	for(auto i:ans)cout<<i<<" ";
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define rep(i,n,N) for(int i = n; i<=N; i++)
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
const int MAX = 1600 + 5;
const int dr[] = {0,0,1,-1,1,-1,1,-1};
const int dc[] = {1,-1,0,0,1,1,-1,-1};

int n,m,nr,nc,cnt,ct;
bool grid[MAX][MAX], x[MAX][MAX], y[MAX][MAX], z[MAX][MAX], val;
vector<int> ans;
pii cur;
bool inside(int r,int c){
	if(r>0 && r<=n && c>0 && c<=m)return 1;
	return 0;
}
void dfs(int r,int c){
	grid[r][c] = 0;
	x[r][c] = 1;
	rep(i,0,4){
		nr = r+dr[i], nc = c+dc[i];
		if(!grid[nr][nc])continue;
		dfs(nr,nc);
	}
}
void cs(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!x[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		if(val){
			y[r][c] = 1;
			rep(k,0,7)y[r+dr[k]][c+dc[k]] = 1;
		}
	}
}
void cas(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-2,c-2))continue;
		if(!inside(r+2,c+2))continue;
		val = 1;
		rep(i,r-2,r+2)rep(j,c-2,c+2)if(!x[i][j]){
			val = 0; break;
		}
		if(val)rep(i,r-2,r+2)rep(j,c-2,c+2)z[i][j] = 1;
	}
	rep(r,1,n)rep(c,1,n)z[r][c]^=y[r][c];
}
void cast(){
	rep(r,1,n)rep(c,1,m){
		if(!z[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!z[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		y[r][c] = val;
	}
}
void df(int r,int c){
	ct++;
	y[r][c] = 0;
	rep(i,0,7){
		nr = r+dr[i], nc = c+dc[i];
		if(!y[nr][nc])continue;
		df(nr,nc);
	}
}
void hit(){
	rep(i,1,n)rep(j,1,m){
		if(!y[i][j])continue;
		ct = 0;
		df(i,j);
		if(ct>7)cnt++;
	}
}

int main(){
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin>>n>>m;
	rep(i,1,n)rep(j,1,m)cin>>grid[i][j];
	rep(i,1,n)rep(j,1,n){
		if(!grid[i][j])continue;
		memset(x,0,sizeof x);
		memset(y,0,sizeof y);
		memset(z,0,sizeof z);
		dfs(i,j);
		cs();
		cas();
		cast();
		cnt = 0;
		hit();
		ans.pb(cnt);
	}
	sort(ans.begin(),ans.end());
	cout<<ans.size()<<endl;
	for(auto i:ans)cout<<i<<" ";
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define rep(i,n,N) for(int i = n; i<=N; i++)
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
const int MAX = 1600 + 5;
const int dr[] = {0,0,1,-1,1,-1,1,-1};
const int dc[] = {1,-1,0,0,1,1,-1,-1};

int n,m,nr,nc,cnt,ct;
bool grid[MAX][MAX], x[MAX][MAX], y[MAX][MAX], z[MAX][MAX], val;
vector<int> ans;
pii cur;
bool inside(int r,int c){
	if(r>0 && r<=n && c>0 && c<=m)return 1;
	return 0;
}
void dfs(int r,int c){
	grid[r][c] = 0;
	x[r][c] = 1;
	rep(i,0,4){
		nr = r+dr[i], nc = c+dc[i];
		if(!grid[nr][nc])continue;
		dfs(nr,nc);
	}
}
void cs(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!x[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		if(val){
			y[r][c] = 1;
			rep(k,0,7)y[r+dr[k]][c+dc[k]] = 1;
		}
	}
}
void cas(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+2,c+2))continue;
		val = 1;
		rep(i,r-1,r+2)rep(j,c-1,c+2)if(!x[i][j]){
			val = 0; break;
		}
		if(val)rep(i,r-1,r+2)rep(j,c-1,c+2)z[i][j] = 1;
	}
	rep(r,1,n)rep(c,1,n)z[r][c]^=y[r][c];
}
void cast(){
	rep(r,1,n)rep(c,1,m){
		if(!z[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!z[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		y[r][c] = val;
	}
}
void df(int r,int c){
	ct++;
	y[r][c] = 0;
	rep(i,0,7){
		nr = r+dr[i], nc = c+dc[i];
		if(!y[nr][nc])continue;
		df(nr,nc);
	}
}
void hit(){
	rep(i,1,n)rep(j,1,m){
		if(!y[i][j])continue;
		ct = 0;
		df(i,j);
		if(ct>7)cnt++;
	}
}

int main(){
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin>>n>>m;
	rep(i,1,n)rep(j,1,m)cin>>grid[i][j];
	rep(i,1,n)rep(j,1,n){
		if(!grid[i][j])continue;
		memset(x,0,sizeof x);
		memset(y,0,sizeof y);
		memset(z,0,sizeof z);
		dfs(i,j);
		cs();
		cas();
		cast();
		cnt = 0;
		hit();
		ans.pb(cnt);
	}
	sort(ans.begin(),ans.end());
	cout<<ans.size()<<endl;
	for(auto i:ans)cout<<i<<" ";
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define rep(i,n,N) for(int i = n; i<=N; i++)
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
const int MAX = 1600 + 5;
const int dr[] = {0,0,1,-1,1,-1,1,-1};
const int dc[] = {1,-1,0,0,1,1,-1,-1};

int n,m,nr,nc,cnt,ct;
bool grid[MAX][MAX], x[MAX][MAX], y[MAX][MAX], z[MAX][MAX], val;
vector<int> ans;
pii cur;
bool inside(int r,int c){
	if(r>0 && r<=n && c>0 && c<=m)return 1;
	return 0;
}
void dfs(int r,int c){
	grid[r][c] = 0;
	x[r][c] = 1;
	rep(i,0,3){
		nr = r+dr[i], nc = c+dc[i];
		if(!grid[nr][nc])continue;
		dfs(nr,nc);
	}
}
void cs(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!x[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		if(val){
			y[r][c] = 1;
			rep(k,0,7)y[r+dr[k]][c+dc[k]] = 1;
		}
	}
}
void cas(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+2,c+2))continue;
		val = 1;
		rep(i,r-1,r+2)rep(j,c-1,c+2)if(!x[i][j]){
			val = 0; break;
		}
		if(val)rep(i,r-1,r+2)rep(j,c-1,c+2)z[i][j] = 1;
	}
	rep(r,1,n)rep(c,1,n)z[r][c]^=y[r][c];
}
void cast(){
	rep(r,1,n)rep(c,1,m){
		if(!z[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!z[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		y[r][c] = val;
	}
}
void df(int r,int c){
	ct++;
	y[r][c] = 0;
	rep(i,0,7){
		nr = r+dr[i], nc = c+dc[i];
		if(!y[nr][nc])continue;
		df(nr,nc);
	}
}
void hit(){
	rep(i,1,n)rep(j,1,m){
		if(!y[i][j])continue;
		ct = 0;
		df(i,j);
		if(ct>2)cnt++;
	}
}

int main(){
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin>>n>>m;
	rep(i,1,n)rep(j,1,m)cin>>grid[i][j];
	rep(i,1,n)rep(j,1,n){
		if(!grid[i][j])continue;
		memset(x,0,sizeof x);
		memset(y,0,sizeof y);
		memset(z,0,sizeof z);
		dfs(i,j);
		cs();
		cas();
		memset(y,0,sizeof y);
		cast();
		cnt = 0;
		hit();
		ans.pb(cnt);
	}
	sort(ans.begin(),ans.end());
	cout<<ans.size()<<endl;
	for(auto i:ans)cout<<i<<" ";
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define rep(i,n,N) for(int i = n; i<=N; i++)
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
const int MAX = 1600 + 5;
const int dr[] = {0,0,1,-1,1,-1,1,-1};
const int dc[] = {1,-1,0,0,1,1,-1,-1};

int n,m,nr,nc,cnt,ct;
bool grid[MAX][MAX], x[MAX][MAX], y[MAX][MAX], z[MAX][MAX], val;
vector<int> ans;
pii cur;
bool inside(int r,int c){
	if(r>0 && r<=n && c>0 && c<=m)return 1;
	return 0;
}
void dfs(int r,int c){
	grid[r][c] = 0;
	x[r][c] = 1;
	rep(i,0,4){
		nr = r+dr[i], nc = c+dc[i];
		if(!grid[nr][nc])continue;
		dfs(nr,nc);
	}
}
void cs(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!x[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		if(val){
			y[r][c] = 1;
			rep(k,0,7)y[r+dr[k]][c+dc[k]] = 1;
		}
	}
}
void cas(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+2,c+2))continue;
		val = 1;
		rep(i,r-1,r+2)rep(j,c-1,c+2)if(!x[i][j]){
			val = 0; break;
		}
		if(val)rep(i,r-1,r+1)rep(j,c-1,c+2)z[i][j] = 1;
	}
	rep(r,1,n)rep(c,1,n)z[r][c]^=y[r][c];
}
void cast(){
	rep(r,1,n)rep(c,1,m){
		if(!z[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!z[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		y[r][c] = val;
	}
}
void df(int r,int c){
	ct++;
	y[r][c] = 0;
	rep(i,0,7){
		nr = r+dr[i], nc = c+dc[i];
		if(!y[nr][nc])continue;
		df(nr,nc);
	}
}
void hit(){
	rep(i,1,n)rep(j,1,m){
		if(!y[i][j])continue;
		ct = 0;
		df(i,j);
		if(ct>8)cnt++;
	}
}

int main(){
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin>>n>>m;
	rep(i,1,n)rep(j,1,m)cin>>grid[i][j];
	rep(i,1,n)rep(j,1,n){
		if(!grid[i][j])continue;
		memset(x,0,sizeof x);
		memset(y,0,sizeof y);
		memset(z,0,sizeof z);
		dfs(i,j);
		cs();
		cas();
		cast();
		cnt = 0;
		hit();
		ans.pb(cnt);
	}
	sort(ans.begin(),ans.end());
	cout<<ans.size()<<endl;
	for(auto i:ans)cout<<i<<" ";
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define rep(i,n,N) for(int i = n; i<=N; i++)
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
const int MAX = 1600 + 5;
const int dr[] = {0,0,1,-1,1,-1,1,-1};
const int dc[] = {1,-1,0,0,1,1,-1,-1};

int n,m,nr,nc,cnt,ct;
bool grid[MAX][MAX], x[MAX][MAX], y[MAX][MAX], z[MAX][MAX], val;
vector<int> ans;
pii cur;
bool inside(int r,int c){
	if(r>0 && r<=n && c>0 && c<=m)return 1;
	return 0;
}
void dfs(int r,int c){
	grid[r][c] = 0;
	x[r][c] = 1;
	rep(i,0,4){
		nr = r+dr[i], nc = c+dc[i];
		if(!grid[nr][nc])continue;
		dfs(nr,nc);
	}
}
void cs(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!x[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		if(val){
			y[r][c] = 1;
			rep(k,0,7)y[r+dr[k]][c+dc[k]] = 1;
		}
	}
}
void cas(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+2,c+2))continue;
		val = 1;
		rep(i,r-1,r+2)rep(j,c-1,c+2)if(!x[i][j]){
			val = 0; break;
		}
		if(val)rep(i,r-1,r+2)rep(j,c-1,c+2)z[i][j] = 1;
	}
	rep(r,1,n)rep(c,1,n)z[r][c]^=y[r][c];
}
void cast(){
	rep(r,1,n)rep(c,1,m){
		if(!z[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!z[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		y[r][c] = val;
	}
}
void df(int r,int c){
	ct++;
	y[r][c] = 0;
	rep(i,0,7){
		nr = r+dr[i], nc = c+dc[i];
		if(!y[nr][nc])continue;
		df(nr,nc);
	}
}
void hit(){
	rep(i,1,n)rep(j,1,m){
		if(!y[i][j])continue;
		ct = 0;
		df(i,j);
		if(ct>8)cnt++;
	}
}

int main(){
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin>>n>>m;
	rep(i,1,n)rep(j,1,m)cin>>grid[i][j];
	rep(i,1,n)rep(j,1,n){
		if(!grid[i][j])continue;
		memset(x,0,sizeof x);
		memset(y,0,sizeof y);
		memset(z,0,sizeof z);
		dfs(i,j);
		cs();
		cas();
		cast();
		cnt = 0;
		hit();
		ans.pb(cnt);
	}
	sort(ans.begin(),ans.end());
	cout<<ans.size()<<endl;
	for(auto i:ans)cout<<i<<" ";
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define rep(i,n,N) for(int i = n; i<=N; i++)
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
const int MAX = 1600 + 5;
const int dr[] = {0,0,1,-1,1,-1,1,-1};
const int dc[] = {1,-1,0,0,1,1,-1,-1};

int n,m,nr,nc,cnt,ct;
bool grid[MAX][MAX], x[MAX][MAX], y[MAX][MAX], z[MAX][MAX], val;
vector<int> ans;
pii cur;
bool inside(int r,int c){
	if(r>0 && r<=n && c>0 && c<=m)return 1;
	return 0;
}
void dfs(int r,int c){
	grid[r][c] = 0;
	x[r][c] = 1;
	rep(i,0,4){
		nr = r+dr[i], nc = c+dc[i];
		if(!grid[nr][nc])continue;
		dfs(nr,nc);
	}
}
void cs(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!x[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		if(val){
			y[r][c] = 1;
			rep(k,0,7)y[r+dr[k]][c+dc[k]] = 1;
		}
	}
}
void cas(){
	rep(r,1,n)rep(c,1,m){
		if(!x[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+2,c+2))continue;
		val = 1;
		rep(i,r-1,r+2)rep(j,c-1,c+2)if(!x[i][j]){
			val = 0; break;
		}
		if(val)rep(i,r-1,r+1)rep(j,c-2,c+2)z[i][j] = 1;
	}
	rep(r,1,n)rep(c,1,n)z[r][c]^=y[r][c];
}
void cast(){
	rep(r,1,n)rep(c,1,m){
		if(!z[r][c])continue;
		if(!inside(r-1,c-1))continue;
		if(!inside(r+1,c+1))continue;
		val = 1;
		rep(k,0,7)if(!z[r+dr[k]][c+dc[k]]){
			val = 0; break;
		}
		y[r][c] = val;
	}
}
void df(int r,int c){
	ct++;
	y[r][c] = 0;
	rep(i,0,7){
		nr = r+dr[i], nc = c+dc[i];
		if(!y[nr][nc])continue;
		df(nr,nc);
	}
}
void hit(){
	rep(i,1,n)rep(j,1,m){
		if(!y[i][j])continue;
		ct = 0;
		df(i,j);
		if(ct>7)cnt++;
	}
}

int main(){
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin>>n>>m;
	rep(i,1,n)rep(j,1,m)cin>>grid[i][j];
	rep(i,1,n)rep(j,1,n){
		if(!grid[i][j])continue;
		memset(x,0,sizeof x);
		memset(y,0,sizeof y);
		memset(z,0,sizeof z);
		dfs(i,j);
		cs();
		cas();
		cast();
		cnt = 0;
		hit();
		ans.pb(cnt);
	}
	sort(ans.begin(),ans.end());
	cout<<ans.size()<<endl;
	for(auto i:ans)cout<<i<<" ";
	return 0;
}


#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

int N, M; long long COUNT = 0;
vector<pair<int, int> > con;
vector<int> order;
vector<long long> hash;
char tmp[32];

#define READ(N, M)                                                          \
    fgets(tmp, 32, stdin);                                                  \
    char *p = tmp;                                                          \
    for (N = 0; '0' <= *p && *p <= '9'; p++) {                              \
        N = N * 10 + *p - '0';                                              \
    }                                                                       \
    for (M = 0, p++; '0' <= *p && *p <= '9'; p++) {                         \
        M = M * 10 + *p - '0';                                              \
    }

inline int cmp(int a, int b) {
    return hash[a] < hash[b];
}

inline void solve() {
    sort(con.begin(), con.end());
    for (int i = 0, p = 0; i < N; i++) {
        hash[i] = 1;
        for (; p < M && con[p].first == i; p++) {
            hash[i] = hash[i] * 1000003 + con[p].second + 1;
        }
    }
    sort(order.begin(), order.end(), cmp);
    for (int l = 0, r; l < N; l = r + 1) {
        for (r = l; r + 1 < N && hash[order[l]] == hash[order[r + 1]]; r++);
        COUNT += (r - l) * (r - l + 1LL) / 2LL;
    }
}

int main() {
    READ(N, M);
    hash.resize(N); order.resize(N);
    for (int i = 0; i < M; i++) {
        int x, y;
        READ(x, y);
        x -= 1; y -= 1;
        con.push_back(make_pair(x, y));
        con.push_back(make_pair(y, x));
    }
    for (int i = 0; i < N; i++) {
        order[i] = i;
    }
    M *= 2;

    solve();
    for (int i = 0; i < N; i++) {
        con.push_back(make_pair(i, i));
        M += 1;
    }
    solve();

    printf("%I64d\n", COUNT);
    return 0;
}


#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

vector<vector<int> > con;
vector<int> hash, order;
char tmp[32];

#define READ(N, M)                                                          \
    fgets(tmp, 32, stdin);                                                  \
    char *p = tmp;                                                          \
    for (N = 0; '0' <= *p && *p <= '9'; p++) {                              \
        N = N * 10 + *p - '0';                                              \
    }                                                                       \
    for (M = 0, p++; '0' <= *p && *p <= '9'; p++) {                         \
        M = M * 10 + *p - '0';                                              \
    }

inline int getHash(const vector<int> &v) {
    int hash = -1;
    for (size_t k = 0; k < v.size(); k++) {
        hash = hash * 1000003 + v[k];
    }
    return hash;
}

inline int cmp(int a, int b) {
    if (hash[a] == hash[b]) {
    //    return con[a] < con[b];
    }
    return hash[a] < hash[b];
}

int main() {
    int N, M; long long COUNT = 0;
    READ(N, M);
    con.resize(N); hash.resize(N); order.resize(N);
    for (; M; M--) {
        int x, y;
        READ(x, y);
        x -= 1; y -= 1;
        con[x].push_back(y);
        con[y].push_back(x);
    }

    for (int i = 0; i < N; i++) {
        sort(con[i].begin(), con[i].end());
        hash[i] = getHash(con[i]);
        order[i] = i;
    }
    sort(order.begin(), order.end(), cmp);
    for (int l = 0, r; l < N; l = r + 1) {
        for (r = l; r + 1 < N && con[order[l]] == con[order[r + 1]]; r++);
        COUNT += (r - l) * (r - l + 1LL) / 2LL;
    }
    for (int i = 0; i < N; i++) {
        con[i].push_back(i);
        sort(con[i].begin(), con[i].end());
        hash[i] = getHash(con[i]);
    }
    sort(order.begin(), order.end(), cmp);
    for (int l = 0, r; l < N; l = r + 1) {
        for (r = l; r + 1 < N && con[order[l]] == con[order[r + 1]]; r++);
        COUNT += (r - l) * (r - l + 1LL) / 2LL;
    }

    printf("%I64d\n", COUNT);
    return 0;
}


#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

vector<vector<int> > con;
vector<int> order;
vector<long long> hash, pow;
char tmp[32];

#define READ(N, M)                                                          \
    fgets(tmp, 32, stdin);                                                  \
    char *p = tmp;                                                          \
    for (N = 0; '0' <= *p && *p <= '9'; p++) {                              \
        N = N * 10 + *p - '0';                                              \
    }                                                                       \
    for (M = 0, p++; '0' <= *p && *p <= '9'; p++) {                         \
        M = M * 10 + *p - '0';                                              \
    }

inline long long getHash(const vector<int> &v) {
    long long hash = 1;
    for (size_t k = 0; k < v.size(); k++) {
        hash *= pow[v[k] - (k == 0 ? 0 : v[k - 1])];
        hash += 239;
    }
    return hash;
}

inline int cmp(int a, int b) {
    return hash[a] < hash[b];
}

int main() {
    int N, M; long long COUNT = 0;
    READ(N, M);
    con.resize(N); hash.resize(N); order.resize(N);
    pow.resize(N);
    pow[0] = 1;
    for (int i = 1; i < N; i++) {
        pow[i] = pow[i - 1] * 98124001;
    }
    for (; M; M--) {
        int x, y;
        READ(x, y);
        x -= 1; y -= 1;
        con[x].push_back(y);
        con[y].push_back(x);
    }

    for (int i = 0; i < N; i++) {
        sort(con[i].begin(), con[i].end());
        hash[i] = getHash(con[i]);
        order[i] = i;
    }
    sort(order.begin(), order.end(), cmp);
    for (int l = 0, r; l < N; l = r + 1) {
        for (r = l; r + 1 < N && hash[order[l]] == hash[order[r + 1]]; r++);
        COUNT += (r - l) * (r - l + 1LL) / 2LL;
    }
    for (int i = 0; i < N; i++) {
        con[i].push_back(i);
        sort(con[i].begin(), con[i].end());
        hash[i] = getHash(con[i]);
    }
    sort(order.begin(), order.end(), cmp);
    for (int l = 0, r; l < N; l = r + 1) {
        for (r = l; r + 1 < N && hash[order[l]] == hash[order[r + 1]]; r++);
        COUNT += (r - l) * (r - l + 1LL) / 2LL;
    }

    printf("%I64d\n", COUNT);
    return 0;
}


#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

vector<vector<int> > con;
vector<int> hash, order, pow;
char tmp[32];

#define READ(N, M)                                                          \
    fgets(tmp, 32, stdin);                                                  \
    char *p = tmp;                                                          \
    for (N = 0; '0' <= *p && *p <= '9'; p++) {                              \
        N = N * 10 + *p - '0';                                              \
    }                                                                       \
    for (M = 0, p++; '0' <= *p && *p <= '9'; p++) {                         \
        M = M * 10 + *p - '0';                                              \
    }

inline int getHash(const vector<int> &v) {
    int hash = 0;
    for (size_t k = 0; k < v.size(); k++) {
        hash += pow[v[k]];
    }
    return hash;
}

inline int cmp(int a, int b) {
    return hash[a] < hash[b];
}

int main() {
    int N, M; long long COUNT = 0;
    READ(N, M);
    con.resize(N); hash.resize(N); order.resize(N);
    pow.resize(N);
    pow[0] = 1;
    for (int i = 1; i < N; i++) {
        pow[i] = pow[i - 1] * 1000003;
    }
    for (; M; M--) {
        int x, y;
        READ(x, y);
        x -= 1; y -= 1;
        con[x].push_back(y);
        con[y].push_back(x);
    }

    for (int i = 0; i < N; i++) {
        sort(con[i].begin(), con[i].end());
        hash[i] = getHash(con[i]);
        order[i] = i;
    }
    sort(order.begin(), order.end(), cmp);
    for (int l = 0, r; l < N; l = r + 1) {
        for (r = l; r + 1 < N && hash[order[l]] == hash[order[r + 1]]; r++);
        COUNT += (r - l) * (r - l + 1LL) / 2LL;
    }
    for (int i = 0; i < N; i++) {
        con[i].push_back(i);
        sort(con[i].begin(), con[i].end());
        hash[i] = getHash(con[i]);
    }
    sort(order.begin(), order.end(), cmp);
    for (int l = 0, r; l < N; l = r + 1) {
        for (r = l; r + 1 < N && hash[order[l]] == hash[order[r + 1]]; r++);
        COUNT += (r - l) * (r - l + 1LL) / 2LL;
    }

    printf("%I64d\n", COUNT);
    return 0;
}


#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

vector<vector<int> > con;
vector<int> hash, order;
char tmp[32];

#define READ(N, M)                                                          \
    fgets(tmp, 32, stdin);                                                  \
    char *p = tmp;                                                          \
    for (N = 0; '0' <= *p && *p <= '9'; p++) {                              \
        N = N * 10 + *p - '0';                                              \
    }                                                                       \
    for (M = 0, p++; '0' <= *p && *p <= '9'; p++) {                         \
        M = M * 10 + *p - '0';                                              \
    }

inline int getHash(vector<int> &v) {
    int hash = 0;
    for (size_t k = 0; k < v.size(); k++) {
        hash = hash * 1000003 + v[k];
    }
    return hash;
}

inline int cmp(int a, int b) {
    if (hash[a] == hash[b]) {
    //    return con[a] < con[b];
    }
    return hash[a] < hash[b];
}

int main() {
    int N, M; long long COUNT = 0;
    READ(N, M);
    con.resize(N); hash.resize(N); order.resize(N);
    for (; M; M--) {
        int x, y;
        READ(x, y);
        x -= 1; y -= 1;
        con[x].push_back(y);
        con[y].push_back(x);
    }

    for (int i = 0; i < N; i++) {
        sort(con[i].begin(), con[i].end());
        hash[i] = getHash(con[i]);
        order[i] = i;
    }
    sort(order.begin(), order.end(), cmp);
    for (int l = 0, r; l < N; l = r + 1) {
        for (r = l; r + 1 < N && con[order[l]] == con[order[r + 1]]; r++);
        COUNT += (r - l) * (r - l + 1LL) / 2LL;
    }
    for (int i = 0; i < N; i++) {
        con[i].push_back(i);
        sort(con[i].begin(), con[i].end());
        hash[i] = getHash(con[i]);
    }
    sort(order.begin(), order.end(), cmp);
    for (int l = 0, r; l < N; l = r + 1) {
        for (r = l; r + 1 < N && con[order[l]] == con[order[r + 1]]; r++);
        COUNT += (r - l) * (r - l + 1LL) / 2LL;
    }

    printf("%I64d\n", COUNT);
    return 0;
}


#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

int N, M; long long COUNT = 0;
vector<pair<int, int> > con;
vector<int> order;
vector<long long> hash;
char tmp[32];

/*
#define READ(N, M)                                                          \
    fgets(tmp, 32, stdin);                                                  \
    char *p = tmp;                                                          \
    for (N = 0; '0' <= *p && *p <= '9'; p++) {                              \
        N = N * 10 + *p - '0';                                              \
    }                                                                       \
    for (M = 0, p++; '0' <= *p && *p <= '9'; p++) {                         \
        M = M * 10 + *p - '0';                                              \
    }
*/
#define READ(N, M)
    scanf("%d %d", &N, &M);

inline int cmp(int a, int b) {
    return hash[a] < hash[b];
}

inline void solve() {
    sort(con.begin(), con.end());
    for (int i = 0, p = 0; i < N; i++) {
        hash[i] = 1;
        for (; p < M && con[p].first == i; p++) {
            hash[i] = hash[i] * 1000003 + con[p].second + 1;
        }
    }
    sort(order.begin(), order.end(), cmp);
    for (int l = 0, r; l < N; l = r + 1) {
        for (r = l; r + 1 < N && hash[order[l]] == hash[order[r + 1]]; r++);
        COUNT += (r - l) * (r - l + 1LL) / 2LL;
    }
}

int main() {
    READ(N, M);
    hash.resize(N); order.resize(N);
    for (int i = 0; i < M; i++) {
        int x, y;
        READ(x, y);
        x -= 1; y -= 1;
        con.push_back(make_pair(x, y));
        con.push_back(make_pair(y, x));
    }
    for (int i = 0; i < N; i++) {
        order[i] = i;
    }
    M *= 2;

    solve();
    for (int i = 0; i < N; i++) {
        con.push_back(make_pair(i, i));
        M += 1;
    }
    solve();

    printf("%I64d\n", COUNT);
    return 0;
}


#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

int N, M; long long COUNT = 0;
vector<pair<int, int> > con;
vector<int> order;
vector<long long> hash;
char tmp[32];

/*
#define READ(N, M)                                                          \
    fgets(tmp, 32, stdin);                                                  \
    char *p = tmp;                                                          \
    for (N = 0; '0' <= *p && *p <= '9'; p++) {                              \
        N = N * 10 + *p - '0';                                              \
    }                                                                       \
    for (M = 0, p++; '0' <= *p && *p <= '9'; p++) {                         \
        M = M * 10 + *p - '0';                                              \
    }
*/
#define READ(N, M) scanf("%d %d", &N, &M);

inline int cmp(int a, int b) {
    return hash[a] < hash[b];
}

inline void solve() {
    sort(con.begin(), con.end());
    for (int i = 0, p = 0; i < N; i++) {
        hash[i] = 1;
        for (; p < M && con[p].first == i; p++) {
            hash[i] = hash[i] * 1000003 + con[p].second + 1;
        }
    }
    sort(order.begin(), order.end(), cmp);
    for (int l = 0, r; l < N; l = r + 1) {
        for (r = l; r + 1 < N && hash[order[l]] == hash[order[r + 1]]; r++);
        COUNT += (r - l) * (r - l + 1LL) / 2LL;
    }
}

int main() {
    READ(N, M);
    hash.resize(N); order.resize(N);
    for (int i = 0; i < M; i++) {
        int x, y;
        READ(x, y);
        x -= 1; y -= 1;
        con.push_back(make_pair(x, y));
        con.push_back(make_pair(y, x));
    }
    for (int i = 0; i < N; i++) {
        order[i] = i;
    }
    M *= 2;

    solve();
    for (int i = 0; i < N; i++) {
        con.push_back(make_pair(i, i));
        M += 1;
    }
    solve();

    printf("%I64d\n", COUNT);
    return 0;
}


#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

vector<vector<int> > con;
vector<int> hash, order;
char tmp[32];

#define READ(N, M)                                                          \
    fgets(tmp, 32, stdin);                                                  \
    char *p = tmp;                                                          \
    for (N = 0; '0' <= *p && *p <= '9'; p++) {                              \
        N = N * 10 + *p - '0';                                              \
    }                                                                       \
    for (M = 0, p++; '0' <= *p && *p <= '9'; p++) {                         \
        M = M * 10 + *p - '0';                                              \
    }

inline int getHash(const vector<int> &v) {
    int hash = 0;
    for (size_t k = 0; k < v.size(); k++) {
        hash = hash * 1000003 + v[k] + 239;
    }
    return hash;
}

inline int cmp(int a, int b) {
    if (hash[a] == hash[b]) {
    //    return con[a] < con[b];
    }
    return hash[a] < hash[b];
}

int main() {
    int N, M; long long COUNT = 0;
    READ(N, M);
    con.resize(N); hash.resize(N); order.resize(N);
    for (; M; M--) {
        int x, y;
        READ(x, y);
        x -= 1; y -= 1;
        con[x].push_back(y);
        con[y].push_back(x);
    }

    for (int i = 0; i < N; i++) {
        sort(con[i].begin(), con[i].end());
        hash[i] = getHash(con[i]);
        order[i] = i;
    }
    sort(order.begin(), order.end(), cmp);
    for (int l = 0, r; l < N; l = r + 1) {
        for (r = l; r + 1 < N && hash[order[l]] == hash[order[r + 1]]; r++);
        COUNT += (r - l) * (r - l + 1LL) / 2LL;
    }
    for (int i = 0; i < N; i++) {
        con[i].push_back(i);
        sort(con[i].begin(), con[i].end());
        hash[i] = getHash(con[i]);
    }
    sort(order.begin(), order.end(), cmp);
    for (int l = 0, r; l < N; l = r + 1) {
        for (r = l; r + 1 < N && hash[order[l]] == hash[order[r + 1]]; r++);
        COUNT += (r - l) * (r - l + 1LL) / 2LL;
    }

    printf("%I64d\n", COUNT);
    return 0;
}


#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

vector<vector<int> > con;
vector<int> hash, order, pow;
char tmp[32];

#define READ(N, M)                                                          \
    fgets(tmp, 32, stdin);                                                  \
    char *p = tmp;                                                          \
    for (N = 0; '0' <= *p && *p <= '9'; p++) {                              \
        N = N * 10 + *p - '0';                                              \
    }                                                                       \
    for (M = 0, p++; '0' <= *p && *p <= '9'; p++) {                         \
        M = M * 10 + *p - '0';                                              \
    }

inline int getHash(const vector<int> &v) {
    int hash = 1;
    for (size_t k = 0; k < v.size(); k++) {
        hash *= pow[v[k]];
        hash += 239;
    }
    return hash;
}

inline int cmp(int a, int b) {
    return hash[a] < hash[b];
}

int main() {
    int N, M; long long COUNT = 0;
    READ(N, M);
    con.resize(N); hash.resize(N); order.resize(N);
    pow.resize(N);
    pow[0] = 1;
    for (int i = 1; i < N; i++) {
        pow[i] = pow[i - 1] * 98124001;
    }
    for (; M; M--) {
        int x, y;
        READ(x, y);
        x -= 1; y -= 1;
        con[x].push_back(y);
        con[y].push_back(x);
    }

    for (int i = 0; i < N; i++) {
        sort(con[i].begin(), con[i].end());
        hash[i] = getHash(con[i]);
        order[i] = i;
    }
    sort(order.begin(), order.end(), cmp);
    for (int l = 0, r; l < N; l = r + 1) {
        for (r = l; r + 1 < N && hash[order[l]] == hash[order[r + 1]]; r++);
        COUNT += (r - l) * (r - l + 1LL) / 2LL;
    }
    for (int i = 0; i < N; i++) {
        con[i].push_back(i);
        sort(con[i].begin(), con[i].end());
        hash[i] = getHash(con[i]);
    }
    sort(order.begin(), order.end(), cmp);
    for (int l = 0, r; l < N; l = r + 1) {
        for (r = l; r + 1 < N && hash[order[l]] == hash[order[r + 1]]; r++);
        COUNT += (r - l) * (r - l + 1LL) / 2LL;
    }

    printf("%I64d\n", COUNT);
    return 0;
}


#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
vector < vector <long long> > g;
long double hash[1000003];
long double b[1000003];
int n,m;
long long ans;
long long coun;
long double a[1000003];
void mergesort(long double *a,long double *b,long long n)
{
    long long i,i0,i1,iRight,iEnd,width,j;
    for(width=1;width<n;width*=2)
        for(i=0;i<n;i+=width*2)
        {
            i0=i;
            i1=iRight=min(i+width,n);
            iEnd=min(i+width*2,n);
            for(j=i;j<iEnd;j++)
                if(i0<iRight && (i1==iEnd || a[i0]<=a[i1]))
                    b[j]=a[i0++];
                else
                    b[j]=a[i1++];
            for(j=i;j<iEnd;j++)
                a[j]=b[j];
        }
}
int main()
{
    long double mnog=(1.0*sqrt(5)-1.0)/2.0;
    scanf("%d %d",&n,&m);
    g.resize(n);
    int i,j;
    long long x,y;
    for(i=0;i<m;i++)
    {
        scanf("%I64d %I64d",&x,&y);
        x--;
        y--;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    for(i=0;i<n;i++)
    {
        coun=0;
        for(j=0;j<g[i].size();j++)
            a[coun++]=g[i][j];
        mergesort(a,b,coun);
        hash[i]=0;
        for(j=0;j<coun;j++)
            hash[i]=(hash[i]*mnog+a[j]+13.0);
    }
    mergesort(hash,b,n);
    i=0;
    while(i<n)
    {
        coun=0;
        j=i;
        while(j<n && hash[j]>=hash[i]-0.0000000000000001 && hash[j]<=hash[i]+0.0000000000000001)
        {
            j++;
            coun++;
        }
        i=j;
        ans+=((coun*coun-coun)/2);
    }
    for(i=0;i<n;i++)
    {
        g[i].push_back(i);
        coun=0;
        for(j=0;j<g[i].size();j++)
            a[coun++]=g[i][j];
        mergesort(a,b,coun);
        hash[i]=0;
        for(j=0;j<coun;j++)
            hash[i]=(hash[i]*mnog+a[j]+13.0);
    }
    mergesort(hash,b,n);
    i=0;
    while(i<n)
    {
        coun=0;
        j=i;
        while(j<n && hash[j]>=hash[i]-0.0000000000000001 && hash[j]<=hash[i]+0.0000000000000001)
        {
            j++;
            coun++;
        }
        i=j;
        ans+=((coun*coun-coun)/2);
    }
    printf("%I64d\n",ans);
    return 0;
}


#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
vector < vector <long long> > g;
long long hash[1000003];
long long b[1000003];
int n,m;
long long ans;
int coun;
long long a[1000003];
void mergesort(long long *a,long long *b,int n)
{
    int i,i0,i1,iRight,iEnd,width,j;
    for(width=1;width<n;width*=2)
        for(i=0;i<n;i+=width*2)
        {
            i0=i;
            i1=iRight=min(i+width,n);
            iEnd=min(i+width*2,n);
            for(j=i;j<iEnd;j++)
                if(i0<iRight && (i1==iEnd || a[i0]<=a[i1]))
                    b[j]=a[i0++];
                else
                    b[j]=a[i1++];
            for(j=i;j<iEnd;j++)
                a[j]=b[j];
        }
}
int main()
{
    scanf("%d %d",&n,&m);
    g.resize(n);
    int i,j;
    long long x,y;
    for(i=0;i<m;i++)
    {
        scanf("%I64d %I64d",&x,&y);
        x--;
        y--;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    for(i=0;i<n;i++)
    {
        if(g[i].size()>0)
            g[i].push_back(i);
        coun=0;
        for(j=0;j<g[i].size();j++)
            a[coun++]=g[i][j];
        mergesort(a,b,coun);
        hash[i]=0;
        for(j=0;j<coun;j++)
            hash[i]=(hash[i]*37+a[j])%17397537375329787;
    }
    mergesort(hash,b,n);
    i=0;
    while(i<n)
    {
        coun=0;
        j=i;
        while(j<n && hash[j]==hash[i])
        {
            j++;
            coun++;
        }
        i=j;
        ans+=((coun*coun-coun)>>1);
    }
    cout<<ans<<endl;
    return 0;
}


#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
vector < vector <long long> > g;
long double hash[1000003];
long double b[1000003];
int n,m;
long long ans;
long long coun;
long double a[1000003];
void mergesort(long double *a,long double *b,long long n)
{
    long long i,i0,i1,iRight,iEnd,width,j;
    for(width=1;width<n;width*=2)
        for(i=0;i<n;i+=width*2)
        {
            i0=i;
            i1=iRight=min(i+width,n);
            iEnd=min(i+width*2,n);
            for(j=i;j<iEnd;j++)
                if(i0<iRight && (i1==iEnd || a[i0]<=a[i1]))
                    b[j]=a[i0++];
                else
                    b[j]=a[i1++];
            for(j=i;j<iEnd;j++)
                a[j]=b[j];
        }
}
int main()
{
    long double mnog=(1.0*sqrt(5)-1.0)/2.0;
    scanf("%d %d",&n,&m);
    g.resize(n);
    int i,j;
    long long x,y;
    for(i=0;i<m;i++)
    {
        scanf("%I64d %I64d",&x,&y);
        x--;
        y--;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    for(i=0;i<n;i++)
    {
        coun=0;
        for(j=0;j<g[i].size();j++)
            a[coun++]=g[i][j];
        mergesort(a,b,coun);
        hash[i]=0;
        for(j=0;j<coun;j++)
            hash[i]=(hash[i]*mnog+a[j]+13.0);
    }
    mergesort(hash,b,n);
    i=0;
    while(i<n)
    {
        coun=0;
        j=i;
        while(j<n && hash[j]>=hash[i]-0.000000000000000001 && hash[j]<=hash[i]+0.000000000000000001)
        {
            j++;
            coun++;
        }
        i=j;
        ans+=((coun*coun-coun)/2);
    }
    for(i=0;i<n;i++)
    {
        g[i].push_back(i);
        coun=0;
        for(j=0;j<g[i].size();j++)
            a[coun++]=g[i][j];
        mergesort(a,b,coun);
        hash[i]=0;
        for(j=0;j<coun;j++)
            hash[i]=(hash[i]*mnog+a[j]+13.0);
    }
    mergesort(hash,b,n);
    i=0;
    while(i<n)
    {
        coun=0;
        j=i;
        while(j<n && hash[j]>=hash[i]-0.000000000000000001 && hash[j]<=hash[i]+0.000000000000000001)
        {
            j++;
            coun++;
        }
        i=j;
        ans+=((coun*coun-coun)/2);
    }
    printf("%I64d\n",ans);
    return 0;
}


#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
vector < vector <int> > g;
long long hash[1000003];
long long b[1000003];
int n,m;
long long ans;
long long coun;
long long a[1000003];
int aa[1000003];
int d[1000003];
void radixsort(int *a,int n)
{
    int k=4;
    int i,j;
    for(i=0;i<k;i++)
    {
        int c[32]={0};
        for(j=0;j<n;j++)
            c[(a[j]>>(5*i)&31)]++;
        for(j=1;j<32;j++)
            c[j]+=c[j-1];
        for(j=n-1;j>-1;j--)
            d[--c[(a[j]>>(5*i)&31)]]=a[j];
        for(j=0;j<n;j++)
            a[j]=d[j];
    }
}
void radixsort2(long long *a,int n)
{
    int k=sizeof(long long);
    int i,j;
    for(i=0;i<k;i++)
    {
        int c[256]={0};
        for(j=0;j<n;j++)
            c[(a[j]>>(8*i)&255)]++;
        for(j=1;j<256;j++)
            c[j]+=c[j-1];
        for(j=n-1;j>-1;j--)
            b[--c[(a[j]>>(8*i)&255)]]=a[j];
        for(j=0;j<n;j++)
            a[j]=b[j];
    }
}
int main()
{
    long long mnog=37;
    scanf("%d %d",&n,&m);
    g.resize(n);
    int i,j;
    long long x,y;
    for(i=0;i<m;i++)
    {
        scanf("%I64d %I64d",&x,&y);
        x--;
        y--;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    for(i=0;i<n;i++)
    {
        coun=0;
        for(j=0;j<g[i].size();j++)
            a[coun++]=g[i][j];
        for(j=0;j<coun;j++)
            aa[j]=(int)a[j];
        radixsort(aa,(int)coun);
        for(j=0;j<coun;j++)
            a[j]=(long long)aa[j];
        hash[i]=0;
        for(j=0;j<coun;j++)
        {
            a[j]++;
            while(a[j]>0)
            {
                hash[i]=(hash[i]*mnog+a[j]%10+'0')%717472347921347957;
                a[j]/=10;
            }
        }
    }
    radixsort2(hash,n);
    i=0;
    while(i<n)
    {
        coun=0;
        j=i;
        while(j<n && hash[i]==hash[j])
        {
            j++;
            coun++;
        }
        i=j;
        ans+=((coun*coun-coun)/2);
    }
    for(i=0;i<n;i++)
    {
        g[i].push_back(i);
        coun=0;
        for(j=0;j<g[i].size();j++)
            a[coun++]=g[i][j];
        for(j=0;j<coun;j++)
            aa[j]=(int)a[j];
        radixsort(aa,(int)coun);
        for(j=0;j<coun;j++)
            a[j]=(long long)aa[j];
        hash[i]=0;
        for(j=0;j<coun;j++)
        {
            a[j]++;
            while(a[j]>0)
            {
                hash[i]=(hash[i]*mnog+a[j]%10+'0')%717472347921347957;
                a[j]/=10;
            }
        }
    }
    radixsort2(hash,n);
    i=0;
    while(i<n)
    {
        coun=0;
        j=i;
        while(j<n && hash[i]==hash[j])
        {
            j++;
            coun++;
        }
        i=j;
        ans+=((coun*coun-coun)/2);
    }
    printf("%I64d\n",ans);
    return 0;
}


#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
vector < vector <long long> > g;
long long hash[1000003];
long long b[1000003];
int n,m;
long long ans;
long long coun;
long long a[1000003];
void mergesort(long long *a,long long *b,long long n)
{
    long long i,i0,i1,iRight,iEnd,width,j;
    for(width=1;width<n;width*=2)
        for(i=0;i<n;i+=width*2)
        {
            i0=i;
            i1=iRight=min(i+width,n);
            iEnd=min(i+width*2,n);
            for(j=i;j<iEnd;j++)
                if(i0<iRight && (i1==iEnd || a[i0]<=a[i1]))
                    b[j]=a[i0++];
                else
                    b[j]=a[i1++];
            for(j=i;j<iEnd;j++)
                a[j]=b[j];
        }
}
int main()
{
    long long mnog=37;
    scanf("%d %d",&n,&m);
    g.resize(n);
    int i,j;
    long long x,y;
    for(i=0;i<m;i++)
    {
        scanf("%I64d %I64d",&x,&y);
        x--;
        y--;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    for(i=0;i<n;i++)
    {
        coun=0;
        for(j=0;j<g[i].size();j++)
            a[coun++]=g[i][j];
        mergesort(a,b,coun);
        hash[i]=0;
        for(j=0;j<coun;j++)
        {
            a[j]++;
            while(a[j]>0)
            {
                hash[i]=(hash[i]*mnog+a[j]%10)%717472347921347957;
                a[j]/=10;
            }
        }
    }
    mergesort(hash,b,n);
    i=0;
    while(i<n)
    {
        coun=0;
        j=i;
        while(j<n && hash[i]==hash[j])
        {
            j++;
            coun++;
        }
        i=j;
        ans+=((coun*coun-coun)/2);
    }
    for(i=0;i<n;i++)
    {
        g[i].push_back(i);
        coun=0;
        for(j=0;j<g[i].size();j++)
            a[coun++]=g[i][j];
        mergesort(a,b,coun);
        hash[i]=0;
        for(j=0;j<coun;j++)
        {
            a[j]++;
            while(a[j]>0)
            {
                hash[i]=(hash[i]*mnog+a[j]%10)%717472347921347957;
                a[j]/=10;
            }
        }
    }
    mergesort(hash,b,n);
    i=0;
    while(i<n)
    {
        coun=0;
        j=i;
        while(j<n && hash[i]==hash[j])
        {
            j++;
            coun++;
        }
        i=j;
        ans+=((coun*coun-coun)/2);
    }
    printf("%I64d\n",ans);
    return 0;
}


#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
vector < vector <int> > g;
long long hash[1000003];
long long b[1000003];
int n,m;
long long ans;
long long coun;
long long a[1000003];
void mergesort(long long *a,long long *b,int n)
{
    int i,i0,i1,iRight,iEnd,width,j;
    for(width=1;width<n;width*=2)
        for(i=0;i<n;i+=width*2)
        {
            i0=i;
            i1=iRight=min(i+width,n);
            iEnd=min(i+width*2,n);
            for(j=i;j<iEnd;j++)
                if(i0<iRight && (i1==iEnd || a[i0]<=a[i1]))
                    b[j]=a[i0++];
                else
                    b[j]=a[i1++];
            for(j=i;j<iEnd;j++)
                a[j]=b[j];
        }
}
bool flag[1000003];
void cherpak(long long *a,int n)
{
    int cou=0;
    int i;
    int maxi=-1;
    for(i=0;i<n;i++)
        maxi=max(maxi,(int)a[i]);
    for(i=0;i<=maxi;i++)
        flag[i]=false;
    for(i=0;i<n;i++)
        flag[a[i]]=true;
    for(i=0;i<=maxi;i++)
        if(flag[i])
            a[cou++]=i;
}
int main()
{
    long long mnog=37;
    scanf("%d %d",&n,&m);
    g.resize(n);
    int i,j;
    long long x,y;
    for(i=0;i<m;i++)
    {
        scanf("%I64d %I64d",&x,&y);
        x--;
        y--;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    for(i=0;i<n;i++)
    {
        coun=0;
        for(j=0;j<g[i].size();j++)
            a[coun++]=g[i][j];
        cherpak(a,(int)coun);
        hash[i]=0;
        for(j=0;j<coun;j++)
        {
            a[j]++;
            while(a[j]>0)
            {
                hash[i]=(hash[i]*mnog+a[j]%10+'0')%717472347921347957;
                a[j]/=10;
            }
        }
    }
    mergesort(hash,b,n);
    i=0;
    while(i<n)
    {
        coun=0;
        j=i;
        while(j<n && hash[i]==hash[j])
        {
            j++;
            coun++;
        }
        i=j;
        ans+=((coun*coun-coun)/2);
    }
    for(i=0;i<n;i++)
    {
        g[i].push_back(i);
        coun=0;
        for(j=0;j<g[i].size();j++)
            a[coun++]=g[i][j];
        cherpak(a,(int)coun);
        hash[i]=0;
        for(j=0;j<coun;j++)
        {
            a[j]++;
            while(a[j]>0)
            {
                hash[i]=(hash[i]*mnog+a[j]%10+'0')%717472347921347957;
                a[j]/=10;
            }
        }
    }
    mergesort(hash,b,n);
    i=0;
    while(i<n)
    {
        coun=0;
        j=i;
        while(j<n && hash[i]==hash[j])
        {
            j++;
            coun++;
        }
        i=j;
        ans+=((coun*coun-coun)/2);
    }
    printf("%I64d\n",ans);
    return 0;
}


#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
vector < vector <int> > g;
long long hash[1000003];
long long b[1000003];
int n,m;
long long ans;
long long coun;
long long a[1000003];
int aa[1000003];
int d[1000003];
void radixsort(int *a,int n)
{
    int k=2;
    int i,j;
    for(i=0;i<k;i++)
    {
        int c[256]={0};
        for(j=0;j<n;j++)
            c[(a[j]>>(16*i)&255)]++;
        for(j=1;j<256;j++)
            c[j]+=c[j-1];
        for(j=n-1;j>-1;j--)
            d[--c[(a[j]>>(16*i)&255)]]=a[j];
        for(j=0;j<n;j++)
            a[j]=d[j];
    }
}
void radixsort2(long long *a,int n)
{
    int k=sizeof(long long);
    int i,j;
    for(i=0;i<k;i++)
    {
        int c[256]={0};
        for(j=0;j<n;j++)
            c[(a[j]>>(8*i)&255)]++;
        for(j=1;j<256;j++)
            c[j]+=c[j-1];
        for(j=n-1;j>-1;j--)
            b[--c[(a[j]>>(8*i)&255)]]=a[j];
        for(j=0;j<n;j++)
            a[j]=b[j];
    }
}
int main()
{
    long long mnog=37;
    scanf("%d %d",&n,&m);
    g.resize(n);
    int i,j;
    long long x,y;
    for(i=0;i<m;i++)
    {
        scanf("%I64d %I64d",&x,&y);
        x--;
        y--;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    for(i=0;i<n;i++)
    {
        coun=0;
        for(j=0;j<g[i].size();j++)
            a[coun++]=g[i][j];
        for(j=0;j<coun;j++)
            aa[j]=(int)a[j];
        radixsort(aa,(int)coun);
        for(j=0;j<coun;j++)
            a[j]=(long long)aa[j];
        hash[i]=0;
        for(j=0;j<coun;j++)
        {
            a[j]++;
            while(a[j]>0)
            {
                hash[i]=(hash[i]*mnog+a[j]%10+'0')%717472347921347957;
                a[j]/=10;
            }
        }
    }
    radixsort2(hash,n);
    i=0;
    while(i<n)
    {
        coun=0;
        j=i;
        while(j<n && hash[i]==hash[j])
        {
            j++;
            coun++;
        }
        i=j;
        ans+=((coun*coun-coun)/2);
    }
    for(i=0;i<n;i++)
    {
        g[i].push_back(i);
        coun=0;
        for(j=0;j<g[i].size();j++)
            a[coun++]=g[i][j];
        for(j=0;j<coun;j++)
            aa[j]=(int)a[j];
        radixsort(aa,(int)coun);
        for(j=0;j<coun;j++)
            a[j]=(long long)aa[j];
        hash[i]=0;
        for(j=0;j<coun;j++)
        {
            a[j]++;
            while(a[j]>0)
            {
                hash[i]=(hash[i]*mnog+a[j]%10+'0')%717472347921347957;
                a[j]/=10;
            }
        }
    }
    radixsort2(hash,n);
    i=0;
    while(i<n)
    {
        coun=0;
        j=i;
        while(j<n && hash[i]==hash[j])
        {
            j++;
            coun++;
        }
        i=j;
        ans+=((coun*coun-coun)/2);
    }
    printf("%I64d\n",ans);
    return 0;
}


#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
vector < vector <long long> > g;
long long hash[1000003];
long long b[1000003];
int n,m;
long long ans;
long long coun;
long long a[1000003];
void mergesort(long long *a,long long *b,long long n)
{
    long long i,i0,i1,iRight,iEnd,width,j;
    for(width=1;width<n;width*=2)
        for(i=0;i<n;i+=width*2)
        {
            i0=i;
            i1=iRight=min(i+width,n);
            iEnd=min(i+width*2,n);
            for(j=i;j<iEnd;j++)
                if(i0<iRight && (i1==iEnd || a[i0]<=a[i1]))
                    b[j]=a[i0++];
                else
                    b[j]=a[i1++];
            for(j=i;j<iEnd;j++)
                a[j]=b[j];
        }
}
int main()
{
    scanf("%d %d",&n,&m);
    g.resize(n);
    int i,j;
    long long x,y;
    for(i=0;i<m;i++)
    {
        scanf("%I64d %I64d",&x,&y);
        x--;
        y--;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    for(i=0;i<n;i++)
    {
        coun=0;
        for(j=0;j<g[i].size();j++)
            a[coun++]=g[i][j];
        mergesort(a,b,coun);
        hash[i]=0;
        for(j=0;j<coun;j++)
            hash[i]=(hash[i]*23+a[j]+19)%175397537375329787;
    }
    mergesort(hash,b,n);
    i=0;
    while(i<n)
    {
        coun=0;
        j=i;
        while(j<n && hash[j]==hash[i])
        {
            j++;
            coun++;
        }
        i=j;
        ans+=((coun*coun-coun)/2);
    }
    for(i=0;i<n;i++)
    {
        g[i].push_back(i);
        coun=0;
        for(j=0;j<g[i].size();j++)
            a[coun++]=g[i][j];
        mergesort(a,b,coun);
        hash[i]=0;
        for(j=0;j<coun;j++)
            hash[i]=(hash[i]*23+a[j]+19)%175397537375329787;
    }
    mergesort(hash,b,n);
    i=0;
    while(i<n)
    {
        coun=0;
        j=i;
        while(j<n && hash[j]==hash[i])
        {
            j++;
            coun++;
        }
        i=j;
        ans+=((coun*coun-coun)/2);
    }
    printf("%I64d\n",ans);
    return 0;
}


#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
vector < vector <long long> > g;
long long hash[1000003];
long long b[1000003];
int n,m;
long long ans;
long long coun;
long long a[1000003];
void mergesort(long long *a,long long *b,long long n)
{
    long long i,i0,i1,iRight,iEnd,width,j;
    for(width=1;width<n;width*=2)
        for(i=0;i<n;i+=width*2)
        {
            i0=i;
            i1=iRight=min(i+width,n);
            iEnd=min(i+width*2,n);
            for(j=i;j<iEnd;j++)
                if(i0<iRight && (i1==iEnd || a[i0]<=a[i1]))
                    b[j]=a[i0++];
                else
                    b[j]=a[i1++];
            for(j=i;j<iEnd;j++)
                a[j]=b[j];
        }
}
int main()
{
    long long mnog=37;
    scanf("%d %d",&n,&m);
    g.resize(n);
    int i,j;
    long long x,y;
    for(i=0;i<m;i++)
    {
        scanf("%I64d %I64d",&x,&y);
        x--;
        y--;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    for(i=0;i<n;i++)
    {
        coun=0;
        for(j=0;j<g[i].size();j++)
            a[coun++]=g[i][j];
        mergesort(a,b,coun);
        hash[i]=0;
        for(j=0;j<coun;j++)
        {
            a[j]++;
            while(a[j]>0)
            {
                hash[i]=(hash[i]*mnog+a[j]%10+'0')%717472347921347957;
                a[j]/=10;
            }
        }
    }
    mergesort(hash,b,n);
    i=0;
    while(i<n)
    {
        coun=0;
        j=i;
        while(j<n && hash[i]==hash[j])
        {
            j++;
            coun++;
        }
        i=j;
        ans+=((coun*coun-coun)/2);
    }
    for(i=0;i<n;i++)
    {
        g[i].push_back(i);
        coun=0;
        for(j=0;j<g[i].size();j++)
            a[coun++]=g[i][j];
        mergesort(a,b,coun);
        hash[i]=0;
        for(j=0;j<coun;j++)
        {
            a[j]++;
            while(a[j]>0)
            {
                hash[i]=(hash[i]*mnog+a[j]%10+'0')%717472347921347957;
                a[j]/=10;
            }
        }
    }
    mergesort(hash,b,n);
    i=0;
    while(i<n)
    {
        coun=0;
        j=i;
        while(j<n && hash[i]==hash[j])
        {
            j++;
            coun++;
        }
        i=j;
        ans+=((coun*coun-coun)/2);
    }
    printf("%I64d\n",ans);
    return 0;
}