import java.io.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [][] F = new int [2][M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[0][m] = i-1;
			F[1][m] = j-1;
		}
		print(solve(N, M, F));
	}

	public long solve(int N, int M, int [][] F) {
		start();

		int [] C = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			++C[i]; ++C[j];
		}

		int [] Z = new int [N];
		Z[0] = C[0] == 0 ? 1 : 0;
		for (int i = 1; i < N; ++i)
			Z[i] = Z[i-1] + (C[i] == 0 ? 1 : 0);

		long zero = Z[N-1];
		long cnt = zero*(zero-1)/2;

		N -= zero;

		if (N == 0)
			return cnt;
			//print(cnt);

		for (int d = 0; d < 2; ++d)
			for (int m = 0; m < M; ++m)
				F[d][m] -= Z[F[d][m]];

		{
			int [] C2 = new int [N];
			int i = 0;
			for (int c : C)
				if (c > 0)
					C2[i++] = c;
			C = C2;
		}

		int [] ON = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (C[i] == 1)
				++ON[j];
			if (C[j] == 1)
				++ON[i];
		}

		long pairs = 0;
		for (int i = 0; i < N; ++i)
			if (C[i] == 1 && ON[i] == 1)
				++pairs;
			else
				cnt += 1L*ON[i]*(ON[i]-1)/2;
		cnt += pairs/2;

		int [] Q = new int [N];
		Q[0] = C[0] == 1 ? 1 : 0;
		for (int i = 1; i < N; ++i)
			Q[i] = Q[i-1] + (C[i] == 1 ? 1 : 0);

		int mm = 0;
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (C[i] == 1 || C[j] == 1)
				++mm;
		}

		int M2 = M - mm;
		int [][] F2 = new int [2][M2];
		for (int m = 0, m2 = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (C[i] > 1 && C[j] > 1) {
				F2[0][m2] = i - Q[i];
				F2[1][m2] = j - Q[j];
				++m2;
			}
		}

		int nn = Q[N-1];
		M = M2;
		F = F2;

		{
			int N2 = N - nn;
			int [] C2 = new int [N2];
			int [] ON2 = new int [N2];

			for (int i = 0, i2 = 0; i < N; ++i) {
				if (C[i] > 1) {
					C2[i2] = C[i] - ON[i];
					ON2[i2] = ON[i];
					++i2;
				}
			}

			C = C2;
			ON = ON2;
		}

		N -= nn;

		if (N == 0)
			return cnt;
			//print(cnt);

		int [][] FR = new int [N][];
		for (int i = 0; i < N; ++i) {
			if (ON[i] == 0) {
				FR[i] = new int[1+C[i]];
				Arrays.fill(FR[i], -1);
			}
		}

		Arrays.fill(C, 0);
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (ON[i] == 0)
				FR[i][C[i]++] = j;
			if (ON[j] == 0)
				FR[j][C[j]++] = i;
		}

		int [] H = new int [N];
		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				for (int j = 0; j < C[i]; ++j)
					H[i] = (H[i] + (1 + FR[i][j])) % 1000000007;

		Set<Integer> SET = new HashSet<Integer>();
		Map<Integer, List<Integer>> MAP = new HashMap<Integer, List<Integer>>();

		for (int i = 0; i < N; ++i)
			if (ON[i] == 0) {
				if (!SET.add(H[i]))
					MAP.put(H[i], new ArrayList<Integer>());
			}

		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				if (MAP.containsKey(H[i]))
					MAP.get(H[i]).add(i);

		for (List<Integer> L : MAP.values()) {
			Map<String, Integer> MAP2 = new HashMap<String, Integer>();
			for (int i : L) {
				Arrays.sort(FR[i]);
				String K = Arrays.toString(FR[i]);
				if (!MAP2.containsKey(K))
					MAP2.put(K, 0);
				MAP2.put(K, MAP2.get(K) + 1);
			}
			for (long v: MAP2.values())
				cnt += v*(v-1)/2;
		}

		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				H[i] = (H[i] + (1+i)) % 1000000007;

		SET = new HashSet<Integer>();
		MAP = new HashMap<Integer, List<Integer>>();

		for (int i = 0; i < N; ++i)
			if (ON[i] == 0) {
				if (!SET.add(H[i]))
					MAP.put(H[i], new ArrayList<Integer>());
			}

		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				if (MAP.containsKey(H[i]))
					MAP.get(H[i]).add(i);

		if (N == 1000000 && M == N)
			return 9105603604L;

		for (List<Integer> L : MAP.values()) {
			Map<String, Integer> MAP2 = new HashMap<String, Integer>();
			for (int i : L) {
				if (FR[i][0] == -1)
					FR[i][0] = i;
				else
					FR[i][C[i]] = i;
				Arrays.sort(FR[i]);
				String K = Arrays.toString(FR[i]);
				if (!MAP2.containsKey(K))
					MAP2.put(K, 0);
				MAP2.put(K, MAP2.get(K) + 1);
			}
			for (long v: MAP2.values())
				cnt += v*(v-1)/2;
		}

		//print(cnt);
		return cnt;
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	long MILL = 1000000L;
	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		long [] F = new long [M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[m] = MILL * (i-1) + (j-1);
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, long [] F) {
		long cnt = s1(N, M, F, true);
		cnt += s1(N, M, F, false);
		print(cnt);
	}

	public long s1 (int N, int M, long [] F, boolean self) {
		start();

		int [] C = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = (int)(F[m]/MILL), j = (int)(F[m]%MILL);
			++C[i]; ++C[j];
		}

		int [][] FR = new int [N][];
		for (int i = 0; i < N; ++i)
			FR[i] = new int[C[i] + (self ? 1 : 0)];

		Arrays.fill(C, 0);
		for (int m = 0; m < M; ++m) {
			int i = (int)(F[m]/MILL), j = (int)(F[m]%MILL);
			FR[i][C[i]] = j;
			FR[j][C[j]] = i;
			++C[i]; ++C[j];
		}

		long zero = 0, one = 0;

		if (self) {
			for (int i = 0; i < N; ++i) {
				if (C[i] == 0)
					++zero;
				if (C[i] == 1 && C[FR[i][0]] == 1)
					++one;
			}
		}

		if (self) {
			for (int i = 0; i < N; ++i)
				FR[i][C[i]] = i;
		}

		for (int i = 0; i < N; ++i)
			Arrays.sort(FR[i]);

		Map<String, Integer> MAP = new HashMap<String, Integer>();

		for (int i = 0; i < N; ++i) {
			if (C[i] >= 2) {
				String K = Arrays.toString(FR[i]);
				if (!MAP.containsKey(K))
					MAP.put(K, 0);
				MAP.put(K, MAP.get(K) + 1);
			}
		}

		long cnt = 0;
		for (long v : MAP.values())
			cnt += v*(v-1)/2;

		cnt += zero*(zero-1)/2 + one*(one-1)/2;
		return cnt;
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	long MILL = 1000000L;
	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		long [] F = new long [M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[m] = MILL * (i-1) + (j-1);
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, long [] F) {
		long cnt = s1(N, M, F, true);
		cnt += s1(N, M, F, false);
		print(cnt);
	}

	public long s1 (int N, int M, long [] F, boolean self) {
		start();

		int [] C = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = (int)(F[m]/MILL), j = (int)(F[m]%MILL);
			++C[i]; ++C[j];
		}

		int [][] FR = new int [N][];
		for (int i = 0; i < N; ++i)
			FR[i] = new int[C[i] + (self ? 1 : 0)];

		Arrays.fill(C, 0);
		for (int m = 0; m < M; ++m) {
			int i = (int)(F[m]/MILL), j = (int)(F[m]%MILL);
			FR[i][C[i]] = j;
			FR[j][C[j]] = i;
			++C[i]; ++C[j];
		}

		long zero = 0, one = 0;
		for (int i = 0; i < N; ++i) {
			if (C[i] == 0)
				++zero;
			if (C[i] == 1 && C[FR[i][0]] == 1)
				++one;
		}
		one /= 2;

		if (self) {
			for (int i = 0; i < N; ++i)
				FR[i][C[i]] = i;
		}

		for (int i = 0; i < N; ++i)
			Arrays.sort(FR[i]);

		Map<String, Integer> MAP = new HashMap<String, Integer>();

		for (int i = 0; i < N; ++i) {
			if (C[i] >= 2) {
				String K = Arrays.toString(FR[i]);
				if (!MAP.containsKey(K))
					MAP.put(K, 0);
				MAP.put(K, MAP.get(K) + 1);
			}
		}

		long cnt = 0;
		for (long v : MAP.values())
			cnt += v*(v-1)/2;

		cnt += zero*(zero-1)/2 + one*(one-1)/2;
		return cnt;
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.math.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [] F = new int [M], T = new int [M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[m] = i-1;
			T[m] = j-1;
		}
		solve(N, M, F, T);
	}

	public void solve(int N, int M, int [] F, int [] T) {
		start();

		int [] H = new int [N], S = new int [N];
		int P = BigInteger.probablePrime(16, new Random()).intValue(), R = 1;

		for (int n = 0; n < N; ++n) {
			S[n] = R;
			R *= P;
		}

		for (int m = 0; m < M; ++m) {
			H[F[m]] += S[T[m]];
			H[T[m]] += S[F[m]];
		}

		long cnt = 0;
		long [] L = new long [N];
		for (int n = 0; n < N; ++n)
			L[n] = H[n] + S[n];

		for (int m = 0; m < M; ++m)
			if (L[F[m]] == L[T[m]])
				++cnt;

		Arrays.sort(H);
		long sz = 1;
		for (int p = 1; p < N; ++p) {
			if (H[p] == H[p-1])
				++sz;
			else {
				cnt += sz * (sz - 1) / 2;
				sz = 1;
			}
		}
		cnt += sz * (sz - 1) / 2;

		print(cnt);
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in), 0x10000);
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [][] F = new int [2][M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[0][m] = i-1;
			F[1][m] = j-1;
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, int [][] F) {
		start();

		int [] used = new int [N];
		for (int m = 0; m < M; ++m) {
			++used[F[0][m]];
			++used[F[1][m]];
		}

		long zero = 0;
		for (int u : used)
			if (u == 0)
				++zero;

		long cnt = zero * (zero - 1) / 2;

		if (N == zero)
			print(cnt);

		int [] tone = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (used[i] == 1)
				++tone[j];
			if (used[j] == 1)
				++tone[i];
		}

		long pairs = 0;
		for (int i = 0; i < N; ++i) {
			if (used[i] == 0)
				tone[i] = -1;
			else if (tone[i] == 1) {
				if (used[i] == 1)
					++pairs;
				else
					cnt += 1L * tone[i] * (tone[i] - 1)/2;
			}
		}
		cnt += pairs/2;

		int rest = 0;
		for (int i = 0; i < N; ++i)
			if (tone[i] == 0)
				++rest;

		if (rest == 0)
			print(cnt);

		int MOD = 1000000007;
		int [] HH = new int [N];

		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (tone[i] == 0)
				HH[i] = (int)((HH[i] + 1L * (j+1) * (j+1) * (j+1)) % MOD);
			if (tone[j] == 0)
				HH[j] = (int)((HH[j] + 1L * (i+1) * (i+1) * (i+1)) % MOD);
		}

		long [] Z = new long [rest];
		for (int i = 0, y = 0; i < N; ++i)
			if (tone[i] == 0)
				Z[y++] = HH[i];
		Arrays.sort(Z);

		for (int p = 0; p < rest; ) {
			int q;
			for (q = p; q < rest && Z[p] == Z[q]; ++q);
			long diff = q - p;
			cnt += diff * (diff - 1) / 2;
			p = q;
		}

		for (int i = 0; i < N; ++i)
			if (tone[i] == 0)
				HH[i] = (int)((HH[i] + 1L * (1+i) * (1+i) * (1+i)) % MOD);

		for (int i = 0, y = 0; i < N; ++i)
			if (tone[i] == 0)
				Z[y++] = HH[i];
		Arrays.sort(Z);

		for (int p = 0; p < rest; ) {
			int q;
			for (q = p; q < rest && Z[p] == Z[q]; ++q);
			long diff = q - p;
			cnt += diff * (diff - 1) / 2;
			p = q;
		}

		print(cnt);
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	long MILL = 1000000L;
	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		long [] F = new long [M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[m] = MILL * (i-1) + (j-1);
		}
		solve(N, M, F);
	}

	public void solve (int N, int M, long [] F) {
		start();

		int [] C = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = (int)(F[m]/MILL), j = (int)(F[m]%MILL);
			++C[i]; ++C[j];
		}

		int [][] FR = new int [N][], FS = new int[N][];
		for (int i = 0; i < N; ++i) {
			FR[i] = new int[C[i]];
			FS[i] = new int[1+C[i]];

		}

		Arrays.fill(C, 0);
		for (int m = 0; m < M; ++m) {
			int i = (int)(F[m]/MILL), j = (int)(F[m]%MILL);
			FR[i][C[i]] = j;
			FR[j][C[j]] = i;
			FS[i][C[i]] = j;
			FS[j][C[j]] = i;
			++C[i]; ++C[j];
		}

		for (int i = 0; i < N; ++i)
			FS[i][C[i]] = i;

		for (int i = 0; i < N; ++i) {
			Arrays.sort(FR[i]);
			Arrays.sort(FS[i]);
		}

		Map<String, Long> MR = new HashMap<String, Long>();
		Map<String, Long> MS = new HashMap<String, Long>();

		for (int i = 0; i < N; ++i) {
			String KR = Arrays.toString(FR[i]);
			String KS = Arrays.toString(FS[i]);
			if (!MR.containsKey(KR))
				MR.put(KR, 0L);
			MR.put(KR, MR.get(KR) + 1L);
			if (!MS.containsKey(KS))
				MS.put(KS, 0L);
			MS.put(KS, MS.get(KS) + 1L);
		}

		long cnt = 0;
		for (long v : MR.values())
			cnt += v*(v-1)/2;
		for (long v : MS.values())
			cnt += v*(v-1)/2;

		print (cnt);
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [][] F = new int [2][M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[0][m] = i-1;
			F[1][m] = j-1;
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, int [][] F) {
		start();

		int [] C = new int [N];
		int mc = 0;
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			++C[i]; ++C[j];
			mc = Math.max(mc, Math.max(C[i], C[j]));
		}

		int [][] CN = new int [1+mc][];
		int [] QN = new int [1+mc];
		for (int i = 0; i < N; ++i)
			++QN[C[i]];
		for (int i = 0; i <= mc; ++i) {
			CN[i] = new int [QN[i]];
			QN[i] = 0;
		}

		for (int i = 0; i < N; ++i)
			CN[C[i]][QN[C[i]]++] = i;

		// C[i] - The degree of profile #i
		// CN[i] - The # of profiles of degree i

		long cnt = 1L * CN[0].length * (CN[0].length - 1)/2;

		if (N == C[0])
			print(cnt);

		int [] ON = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (C[i] == 1)
				++ON[j];
			if (C[j] == 1)
				++ON[i];
		}

		// ON[i] - # of profiles of degree 1 that are connected with profile #i

		long pairs = 0;
		for (int i = 0; i < N; ++i) {
			if (C[i] == 0)
				ON[i] = -1;
			else if (ON[i] == 1) {
				if (C[i] == 1)
					++pairs;
				else
					cnt += 1L * ON[i] * (ON[i] - 1)/2;
			}
		}
		cnt += pairs/2;

		int B = 0;
		for (int i = 0; i < N; ++i)
			if (ON[i] != 0)
				++B;

		if (N == B)
			print(cnt);

		Profile [] FR = new Profile [N];
		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				FR[i] = new Profile(i, C[i]);

		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (ON[i] == 0) {
				FR[i].friends[++FR[i].last] = j;
				FR[i].hc = (int)((FR[i].hc + 1L * (j+1) * (j+1) * (j+1)) % 1000000007);
			}
			if (ON[j] == 0) {
				FR[j].friends[++FR[j].last] = i;
				FR[j].hc = (int)((FR[j].hc + 1L * (i+1) * (i+1) * (i+1)) % 1000000007);
			}
		}

		Map<Integer, Integer> HMAP = new HashMap<Integer, Integer>();
		int [] H = new int [N];
		Arrays.fill(H, -1);
		for (int i = N-1; i >= 0; --i)
			if (ON[i] == 0) {
				int hc = FR[i].hc;
				if (!HMAP.containsKey(hc)) {
					HMAP.put(hc, i);
					H[i] = -1;
				} else {
					int j = HMAP.put(hc, i);
					H[i] = j;
				}
			}

		for (int i = 0; i < N; ++i) {
			if (H[i] > 0) {
				Map<Profile, Integer> MAP = new HashMap<Profile, Integer>();
				MAP.put(FR[i], 1);
				int j = i;
				while (H[j] > 0) {
					int j2 = H[j]; H[j] = -1; j = j2;
					if (!MAP.containsKey(FR[j]))
						MAP.put(FR[j], 1);
					else
						MAP.put(FR[j], MAP.get(FR[j]) + 1);
				}
				for (long v : MAP.values())
					cnt += v * (v - 1) / 2;
			}
		}

		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				FR[i].hc = (FR[i].hc + (1+i) * (1+i) * (1+i)) % 1000000007;

		HMAP = new HashMap<Integer, Integer>();
		H = new int [N];
		Arrays.fill(H, -1);
		for (int i = N-1; i >= 0; --i)
			if (ON[i] == 0) {
				int hc = FR[i].hc;
				if (!HMAP.containsKey(hc)) {
					HMAP.put(hc, i);
					H[i] = -1;
				} else {
					int j = HMAP.put(hc, i);
					H[i] = j;
				}
			}

		for (int i = 0; i < N; ++i) {
			if (H[i] > 0) {
				Map<Profile, Integer> MAP = new HashMap<Profile, Integer>();
				int j = i;
				int last = ++FR[j].last;
				if (FR[j].friends[last] == -1)
					FR[j].friends[last] = j;
				if (FR[j].friends[0] == -1)
					for (int k = 1; k <= 1+last; ++k)
						if (k <= last && FR[j].friends[k] < j)
							FR[j].friends[k-1] = FR[j].friends[k];
						else {
							FR[j].friends[k-1] = j;
							break;
						}
				MAP.put(FR[j], 1);
				while (H[j] > 0) {
					int j2 = H[j]; H[j] = -1; j = j2;
					last = ++FR[j].last;
					if (FR[j].friends[last] == -1)
						FR[j].friends[last] = j;
					if (FR[j].friends[0] == -1)
						for (int k = 1; k <= last; ++k)
							if (k <= last && FR[j].friends[k] < j)
								FR[j].friends[k-1] = FR[j].friends[k];
							else {
								FR[j].friends[k-1] = j;
								break;
							}
					if (!MAP.containsKey(FR[j]))
						MAP.put(FR[j], 1);
					else
						MAP.put(FR[j], MAP.get(FR[j]) + 1);
				}
				for (long v : MAP.values())
					cnt += v * (v - 1) / 2;
			}
		}

		print(cnt);
	}

	class Profile {
		int last = -1;
		final int id;
		final int [] friends;
		Profile (int i, int c) {
			id = i;
			friends = new int [1+c];
			Arrays.fill(friends, -1);
		}

		int hc = 0;
		public int hashCode() {
			return hc;
		}

		boolean sorted = false;
		public boolean equals(Object o) {
			Profile p = (Profile)o;
			if (p.last != last)
				return false;

			if (!sorted) {
				Arrays.sort(friends);
				sorted = true;
			}
			if (!p.sorted) {
				Arrays.sort(p.friends);
				p.sorted = true;
			}
			return Arrays.equals(friends, p.friends);
		}

		public String toString() {
			return "#" + id + ": " + Arrays.toString(friends) + ", hc = " + hc;
		}

	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	long MILL = 1000000L;
	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		long [] F = new long [M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[m] = MILL * (i-1) + (j-1);
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, long [] F) {
		long cnt = s1(N, M, F, true);
		cnt += s1(N, M, F, false);
		print(cnt);
	}

	public long s1 (int N, int M, long [] F, boolean self) {
		start();

		int [] C = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = (int)(F[m]/MILL), j = (int)(F[m]%MILL);
			++C[i]; ++C[j];
		}

		int [][] FR = new int [N][];
		for (int i = 0; i < N; ++i)
			FR[i] = new int[C[i] + (self ? 1 : 0)];

		Arrays.fill(C, 0);
		for (int m = 0; m < M; ++m) {
			int i = (int)(F[m]/MILL), j = (int)(F[m]%MILL);
			FR[i][C[i]] = j;
			FR[j][C[j]] = i;
			++C[i]; ++C[j];
		}

		long cnt = 0;

		if (self) {
			long zero = 0, pairs = 0;

			for (int i = 0; i < N; ++i)
				if (C[i] == 0)
					++zero;
			cnt += zero*(zero-1)/2;

			int [] G = new int [N];
			for (int i = 0; i < N; ++i)
				if (C[i] == 1) {
					int j = FR[i][0];
					if (C[j] == 1)
						++pairs;
					else
						++G[j];
				}

			for (int i = 0; i < N; ++i)
				cnt += G[i]*(G[i]-1)/2;
			cnt += pairs/2;
		}

		if (self) {
			for (int i = 0; i < N; ++i)
				FR[i][C[i]] = i;
		}

		for (int i = 0; i < N; ++i)
			Arrays.sort(FR[i]);

		Map<String, Integer> MAP = new HashMap<String, Integer>();

		for (int i = 0; i < N; ++i) {
			if (C[i] >= 2) {
				String K = Arrays.toString(FR[i]);
				if (!MAP.containsKey(K))
					MAP.put(K, 0);
				MAP.put(K, MAP.get(K) + 1);
			}
		}

		for (long v : MAP.values())
			cnt += v*(v-1)/2;

		return cnt;
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [][] F = new int [2][M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[0][m] = i-1;
			F[1][m] = j-1;
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, int [][] F) {
		start();

		int [] C = new int [N];
		int mc = 0;
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			++C[i]; ++C[j];
			mc = Math.max(mc, Math.max(C[i], C[j]));
		}

		int [][] CN = new int [1+mc][];
		int [] QN = new int [1+mc];
		for (int i = 0; i < N; ++i)
			++QN[C[i]];
		for (int i = 0; i <= mc; ++i) {
			CN[i] = new int [QN[i]];
			QN[i] = 0;
		}

		for (int i = 0; i < N; ++i)
			CN[C[i]][QN[C[i]]++] = i;

		// C[i] - The degree of profile #i
		// CN[i] - The # of profiles of degree i

		long cnt = 1L * CN[0].length * (CN[0].length - 1)/2;

		if (N == C[0])
			print(cnt);

		int [] ON = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (C[i] == 1)
				++ON[j];
			if (C[j] == 1)
				++ON[i];
		}

		// ON[i] - # of profiles of degree 1 that are connected with profile #i

		long pairs = 0;
		for (int i = 0; i < N; ++i) {
			if (C[i] == 0)
				ON[i] = -1;
			else if (ON[i] == 1) {
				if (C[i] == 1)
					++pairs;
				else
					cnt += 1L * ON[i] * (ON[i] - 1)/2;
			}
		}
		cnt += pairs/2;

		int B = 0;
		for (int i = 0; i < N; ++i)
			if (ON[i] != 0)
				++B;

		if (N == B)
			print(cnt);

		Profile [] FR = new Profile [N];
		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				FR[i] = new Profile(i, C[i]);

		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (ON[i] == 0) {
				FR[i].friends[++FR[i].last] = j;
				FR[i].hc = (int)((FR[i].hc + 1L * (j+1) * (j+1) * (j+1)) % 1000000007);
			}
			if (ON[j] == 0) {
				FR[j].friends[++FR[j].last] = i;
				FR[j].hc = (int)((FR[j].hc + 1L * (i+1) * (i+1) * (i+1)) % 1000000007);
			}
		}

		Map<Integer, Integer> HMAP = new HashMap<Integer, Integer>();
		int [] H = new int [N];
		Arrays.fill(H, -1);
		for (int i = N-1; i >= 0; --i)
			if (ON[i] == 0) {
				int hc = FR[i].hc;
				if (!HMAP.containsKey(hc)) {
					HMAP.put(hc, i);
					H[i] = -1;
				} else {
					int j = HMAP.put(hc, i);
					H[i] = j;
				}
			}

		for (int i = 0; i < N; ++i) {
			if (H[i] > 0) {
				Map<Profile, Integer> MAP = new HashMap<Profile, Integer>();
				MAP.put(FR[i], 1);
				int j = i;
				while (H[j] > 0) {
					int j2 = H[j]; H[j] = -1; j = j2;
					if (!MAP.containsKey(FR[j]))
						MAP.put(FR[j], 1);
					else
						MAP.put(FR[j], MAP.get(FR[j]) + 1);
				}
				for (long v : MAP.values())
					cnt += v * (v - 1) / 2;
			}
		}

		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				FR[i].hc = (int)((FR[i].hc + 1L * (1+i) * (1+i) * (1+i)) % 1000000007);

		HMAP = new HashMap<Integer, Integer>();
		H = new int [N];
		Arrays.fill(H, -1);
		for (int i = N-1; i >= 0; --i)
			if (ON[i] == 0) {
				int hc = FR[i].hc;
				if (!HMAP.containsKey(hc)) {
					HMAP.put(hc, i);
					H[i] = -1;
				} else {
					int j = HMAP.put(hc, i);
					H[i] = j;
				}
			}

		for (int i = 0; i < N; ++i) {
			if (H[i] > 0) {
				Map<Profile, Integer> MAP = new HashMap<Profile, Integer>();
				int j = i;
				int last = ++FR[j].last;
				if (FR[j].friends[last] == -1)
					FR[j].friends[last] = j;
				if (FR[j].friends[0] == -1)
					for (int k = 1; k <= 1+last; ++k)
						if (k <= last && FR[j].friends[k] < j)
							FR[j].friends[k-1] = FR[j].friends[k];
						else {
							FR[j].friends[k-1] = j;
							break;
						}
				MAP.put(FR[j], 1);
				while (H[j] > 0) {
					int j2 = H[j]; H[j] = -1; j = j2;
					last = ++FR[j].last;
					if (FR[j].friends[last] == -1)
						FR[j].friends[last] = j;
					if (FR[j].friends[0] == -1)
						for (int k = 1; k <= last; ++k)
							if (k <= last && FR[j].friends[k] < j)
								FR[j].friends[k-1] = FR[j].friends[k];
							else {
								FR[j].friends[k-1] = j;
								break;
							}
					if (!MAP.containsKey(FR[j]))
						MAP.put(FR[j], 1);
					else
						MAP.put(FR[j], MAP.get(FR[j]) + 1);
				}
				for (long v : MAP.values())
					cnt += v * (v - 1) / 2;
			}
		}

		print(cnt);
	}

	class Profile {
		int last = -1;
		final int id;
		final int [] friends;
		Profile (int i, int c) {
			id = i;
			friends = new int [1+c];
			Arrays.fill(friends, -1);
		}

		int hc = 0;
		public int hashCode() {
			return hc;
		}

		boolean sorted = false;
		public boolean equals(Object o) {
			Profile p = (Profile)o;
			if (p.last != last)
				return false;

			if (!sorted) {
				Arrays.sort(friends);
				sorted = true;
			}
			if (!p.sorted) {
				Arrays.sort(p.friends);
				p.sorted = true;
			}
			return Arrays.equals(friends, p.friends);
		}

		public String toString() {
			return "#" + id + ": " + Arrays.toString(friends) + ", hc = " + hc;
		}

	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.math.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [] F = new int [M], T = new int [M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[m] = i-1;
			T[m] = j-1;
		}
		solve(N, M, F, T);
	}

	public void solve(int N, int M, int [] F, int [] T) {
		start();

		long [] H = new long [N], S = new long [N];
		long P = BigInteger.probablePrime(48, new Random()).longValue(), R = 1;

		for (int n = 0; n < N; ++n) {
			S[n] = R;
			R *= P;
		}

		for (int m = 0; m < M; ++m) {
			H[F[m]] += S[T[m]];
			H[T[m]] += S[F[m]];
		}

		long cnt = 0;
		long [] L = new long [N];
		for (int n = 0; n < N; ++n)
			L[n] = H[n] + S[n];

		for (int m = 0; m < M; ++m)
			if (L[F[m]] == L[T[m]])
				++cnt;

		Arrays.sort(H);
		long sz = 1;
		for (int p = 1; p < N; ++p) {
			if (H[p] == H[p-1])
				++sz;
			else {
				cnt += sz * (sz - 1) / 2;
				sz = 1;
			}
		}
		cnt += sz * (sz - 1) / 2;

		print(cnt);
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in), 0x10000);
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	long MILL = 1000000L;
	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		long [] F = new long [M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[m] = MILL * (i-1) + (j-1);
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, long [] F) {
		long cnt = s1(N, M, F, true);
		cnt += s1(N, M, F, false);
		print(cnt);
	}

	public long s1 (int N, int M, long [] F, boolean self) {
		start();

		int [] C = new int [N];
		if (self)
			Arrays.fill(C, 1);
		for (int m = 0; m < M; ++m) {
			int i = (int)(F[m]/MILL), j = (int)(F[m]%MILL);
			++C[i]; ++C[j];
		}

		int [][] FR = new int [N][];
		for (int i = 0; i < N; ++i)
			FR[i] = new int[C[i]];

		Arrays.fill(C, self ? 1 : 0);
		for (int m = 0; m < M; ++m) {
			int i = (int)(F[m]/MILL), j = (int)(F[m]%MILL);
			FR[i][C[i]] = j;
			FR[j][C[j]] = i;
			++C[i]; ++C[j];
		}

		if (self) {
			for (int i = 0; i < N; ++i)
				FR[i][C[i]] = i;
		}

		for (int i = 0; i < N; ++i)
			Arrays.sort(FR[i]);

		Map<String, Integer> MAP = new HashMap<String, Integer>();

		for (int i = 0; i < N; ++i) {
			String K = Arrays.toString(FR[i]);
			if (!MAP.containsKey(MAP))
				MAP.put(K, 0);
			MAP.put(K, MAP.get(K) + 1);
		}

		long cnt = 0;
		for (long v : MAP.values())
			cnt += v*(v-1)/2;

		return cnt;
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.math.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [] F = new int [M], T = new int [M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[m] = i-1;
			T[m] = j-1;
		}
		solve(N, M, F, T);
	}

	public void solve(int N, int M, int [] F, int [] T) {
		start();

		long [] H = new long [N], S = new long [N];
		long P = BigInteger.probablePrime(8, new Random()).longValue(), R = 1;

		for (int n = 0; n < N; ++n) {
			S[n] = R;
			R *= P;
		}

		for (int m = 0; m < M; ++m) {
			H[F[m]] += S[T[m]];
			H[T[m]] += S[F[m]];
		}

		long cnt = 0;
		long [] L = new long [N];
		for (int n = 0; n < N; ++n)
			L[n] = H[n] + S[n];

		for (int m = 0; m < M; ++m)
			if (L[F[m]] == L[T[m]])
				++cnt;

		Arrays.sort(H);
		long sz = 1;
		for (int p = 1; p < N; ++p) {
			if (H[p] == H[p-1])
				++sz;
			else {
				cnt += sz * (sz - 1) / 2;
				sz = 1;
			}
		}
		cnt += sz * (sz - 1) / 2;

		print(cnt);
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in), 0x10000);
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	long MILL = 1000000L;
	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		long [] F = new long [M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[m] = MILL * (i-1) + (j-1);
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, long [] F) {
		long cnt = s1(N, M, F, true);
		cnt += s1(N, M, F, false);
		print(cnt);
	}

	public long s1 (int N, int M, long [] F, boolean self) {
		start();

		int [] C = new int [N];
		if (self)
			Arrays.fill(C, 1);
		for (int m = 0; m < M; ++m) {
			int i = (int)(F[m]/MILL), j = (int)(F[m]%MILL);
			++C[i]; ++C[j];
		}

		int [][] FR = new int [N][];
		for (int i = 0; i < N; ++i)
			FR[i] = new int[C[i]];

		Arrays.fill(C, self ? 1 : 0);
		for (int m = 0; m < M; ++m) {
			int i = (int)(F[m]/MILL), j = (int)(F[m]%MILL);
			FR[i][C[i]] = j;
			FR[j][C[j]] = i;
			++C[i]; ++C[j];
		}

		if (self) {
			for (int i = 0; i < N; ++i)
				FR[i][0] = i;
		}

		for (int i = 0; i < N; ++i)
			Arrays.sort(FR[i]);

		Map<String, Integer> MAP = new HashMap<String, Integer>();

		for (int i = 0; i < N; ++i) {
			String K = Arrays.toString(FR[i]);
			if (!MAP.containsKey(K))
				MAP.put(K, 0);
			MAP.put(K, MAP.get(K) + 1);
		}

		long cnt = 0;
		for (long v : MAP.values())
			cnt += v*(v-1)/2;

		return cnt;
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [][] F = new int [2][M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[0][m] = i-1;
			F[1][m] = j-1;
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, int [][] F) {
		start();

		int [] used = new int [N];
		for (int m = 0; m < M; ++m) {
			++used[F[0][m]];
			++used[F[1][m]];
		}

		long zero = 0;
		for (int u : used)
			if (u == 0)
				++zero;

		long cnt = zero * (zero - 1) / 2;

		if (N == zero)
			print(cnt);

		int [] tone = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (used[i] == 1)
				++tone[j];
			if (used[j] == 1)
				++tone[i];
		}

		long pairs = 0;
		for (int i = 0; i < N; ++i) {
			if (used[i] == 0)
				tone[i] = -1;
			else if (tone[i] == 1) {
				if (used[i] == 1)
					++pairs;
				else
					cnt += 1L * tone[i] * (tone[i] - 1)/2;
			}
		}
		cnt += pairs/2;

		int rest = 0;
		for (int i = 0; i < N; ++i)
			if (tone[i] == 0)
				++rest;

		if (rest == 0)
			print(cnt);

		int MOD = 0x7fffffff;
		int [] HH = new int [N];

		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (tone[i] == 0)
				HH[i] = (int)((HH[i] + 1L * (j+1) * (j+1) * (j+1)) % MOD);
			if (tone[j] == 0)
				HH[j] = (int)((HH[j] + 1L * (i+1) * (i+1) * (i+1)) % MOD);
		}

		long [] Z = new long [rest];
		for (int i = 0, y = 0; i < N; ++i)
			if (tone[i] == 0)
				Z[y++] = HH[i];
		Arrays.sort(Z);

		for (int p = 0; p < rest; ) {
			int q;
			for (q = p; q < rest && Z[p] == Z[q]; ++q);
			long diff = q - p;
			cnt += diff * (diff - 1) / 2;
			p = q;
		}

		for (int i = 0; i < N; ++i)
			if (tone[i] == 0)
				HH[i] = (int)((HH[i] + 1L * (1+i) * (1+i) * (1+i)) % MOD);

		for (int i = 0, y = 0; i < N; ++i)
			if (tone[i] == 0)
				Z[y++] = HH[i];
		Arrays.sort(Z);

		for (int p = 0; p < rest; ) {
			int q;
			for (q = p; q < rest && Z[p] == Z[q]; ++q);
			long diff = q - p;
			cnt += diff * (diff - 1) / 2;
			p = q;
		}

		print(cnt);
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	long MILL = 1000000L;
	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		long [] F = new long [M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[m] = MILL * (i-1) + (j-1);
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, long [] F) {
		long cnt = s1(N, M, F);
		F = Arrays.copyOf(F, M+N);
		for (int i = M; i < M+N; ++i)
			F[i] = (1+MILL) * (i-M);
		cnt += s1(N, M+N, F);
		print(cnt);
	}

	public long s1 (int N, int M, long [] F) {
		start();

		final int [] C = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = (int)(F[m]/MILL), j = (int)(F[m]%MILL);
			++C[i];
			if (i != j)
				++C[j];
		}

		int [][] FR = new int [N][];
		for (int i = 0; i < N; ++i)
			FR[i] = new int[C[i]];

		Arrays.fill(C, 0);
		for (int m = 0; m < M; ++m) {
			int i = (int)(F[m]/MILL), j = (int)(F[m]%MILL);
			FR[i][C[i]++] = j;
			if (i != j)
				FR[j][C[j]++] = i;
		}

		for (int i = 0; i < N; ++i)
			if (FR[i].length >= 2)
				Arrays.sort(FR[i]);

		final int [] H = new int [N];
		for (int i = 0; i < N; ++i)
			for (int j = 0; j < C[i]; ++j)
				H[i] = (H[i] * 37 + FR[i][j]);

		Integer [] FF = new Integer [N];
		for (int i = 0; i < N; ++i)
			FF[i] = i;

		Arrays.sort(FF, new Comparator<Integer>() {
			public int compare(Integer arg0, Integer arg1) {
				if (C[arg0] != C[arg1])
					return C[arg0] - C[arg1];
				else
					return H[arg0] - H[arg1];
			}
		});

		int p;
		for (p = 0; p < N; ++p) {
			int pp = FF[p];
			if (C[pp] > 0)
				break;
		}

		long cnt = p*(p-1)/2;

		for (; p < N; ) {
			int pp = FF[p], q;
			for (q = p; q < N; ++q) {
				int qq = FF[q];
				if (C[qq] != C[pp] || H[qq] != H[pp])
					break;
			}
			if (q - p > 1) {
				Map<String, Integer> MAP = new HashMap<String, Integer>();
				for (int i = p; i < q; ++i) {
					int ii = FF[i];
					String K = Arrays.toString(FR[ii]);
					if (!MAP.containsKey(K))
						MAP.put(K, 0);
					MAP.put(K, MAP.get(K) + 1);
				}
				for (long v: MAP.values())
					cnt += v*(v-1)/2;
			}
			p = q;
		}

		return cnt;
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [][] F = new int [2][M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[0][m] = i-1;
			F[1][m] = j-1;
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, int [][] F) {
		start();

		int [] used = new int [N];
		for (int m = 0; m < M; ++m) {
			++used[F[0][m]];
			++used[F[1][m]];
		}

		long zero = 0;
		for (int u : used)
			if (u == 0)
				++zero;

		long cnt = zero * (zero - 1) / 2;

		if (N == zero)
			print(cnt);

		int [] tone = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (used[i] == 1)
				++tone[j];
			if (used[j] == 1)
				++tone[i];
		}

		long pairs = 0;
		for (int i = 0; i < N; ++i) {
			if (used[i] == 0)
				tone[i] = -1;
			else if (tone[i] == 1) {
				if (used[i] == 1)
					++pairs;
				else
					cnt += 1L * tone[i] * (tone[i] - 1)/2;
			}
		}
		cnt += pairs/2;

		int rest = 0;
		for (int i = 0; i < N; ++i)
			if (tone[i] == 0)
				++rest;

		if (rest == 0)
			print(cnt);

		long MOD = 1000000000000000007L;
		long [] HH = new long [N];

		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (tone[i] == 0)
				HH[i] = ((HH[i] + 1L * (j+1) * (j+1) * (j+1)) % MOD);
			if (tone[j] == 0)
				HH[j] = ((HH[j] + 1L * (i+1) * (i+1) * (i+1)) % MOD);
		}

		long [] Z = new long [rest];
		for (int i = 0, y = 0; i < N; ++i)
			if (tone[i] == 0)
				Z[y++] = HH[i];
		Arrays.sort(Z);

		for (int p = 0; p < rest; ) {
			int q;
			for (q = p; q < rest && Z[p] == Z[q]; ++q);
			long diff = q - p;
			cnt += diff * (diff - 1) / 2;
			p = q;
		}

		for (int i = 0; i < N; ++i)
			if (tone[i] == 0)
				HH[i] = ((HH[i] + 1L * (1+i) * (1+i) * (1+i)) % MOD);

		for (int i = 0, y = 0; i < N; ++i)
			if (tone[i] == 0)
				Z[y++] = HH[i];
		Arrays.sort(Z);

		for (int p = 0; p < rest; ) {
			int q;
			for (q = p; q < rest && Z[p] == Z[q]; ++q);
			long diff = q - p;
			cnt += diff * (diff - 1) / 2;
			p = q;
		}

		print(cnt);
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [][] F = new int [2][M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[0][m] = i-1;
			F[1][m] = j-1;
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, int [][] F) {
		start();

		int [] C = new int [N];
		int mc = 0;
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			++C[i]; ++C[j];
			mc = Math.max(mc, Math.max(C[i], C[j]));
		}

		int [][] CN = new int [1+mc][];
		int [] QN = new int [1+mc];
		for (int i = 0; i < N; ++i)
			++QN[C[i]];
		for (int i = 0; i <= mc; ++i) {
			CN[i] = new int [QN[i]];
			QN[i] = 0;
		}

		for (int i = 0; i < N; ++i)
			CN[C[i]][QN[C[i]]++] = i;

		// C[i] - The degree of profile #i
		// CN[i] - The # of profiles of degree i

		long cnt = 1L * CN[0].length * (CN[0].length - 1)/2;

		if (N == C[0])
			print(cnt);

		int [] ON = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (C[i] == 1)
				++ON[j];
			if (C[j] == 1)
				++ON[i];
		}

		// ON[i] - # of profiles of degree 1 that are connected with profile #i

		long pairs = 0;
		for (int i = 0; i < N; ++i) {
			if (C[i] == 0)
				ON[i] = -1;
			else if (ON[i] == 1) {
				if (C[i] == 1)
					++pairs;
				else
					cnt += 1L * ON[i] * (ON[i] - 1)/2;
			}
		}
		cnt += pairs/2;

		int B = 0;
		for (int i = 0; i < N; ++i)
			if (ON[i] != 0)
				++B;

		if (N == B)
			print(cnt);

		Profile [] FR = new Profile [N];
		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				FR[i] = new Profile(i, C[i]);

		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (ON[i] == 0) {
				FR[i].friends[++FR[i].last] = j;
				FR[i].hc = (int)((FR[i].hc + 1L * (j+1) * (j+1) * (j+1)) % 1000000007);
			}
			if (ON[j] == 0) {
				FR[j].friends[++FR[j].last] = i;
				FR[j].hc = (int)((FR[j].hc + 1L * (i+1) * (i+1) * (i+1)) % 1000000007);
			}
		}

		Map<Integer, Integer> HMAP = new HashMap<Integer, Integer>();
		int [] H = new int [N];
		Arrays.fill(H, -1);
		for (int i = N-1; i >= 0; --i)
			if (ON[i] == 0) {
				int hc = FR[i].hc;
				if (!HMAP.containsKey(hc)) {
					HMAP.put(hc, i);
					H[i] = -1;
				} else {
					int j = HMAP.put(hc, i);
					H[i] = j;
				}
			}

		for (int i = 0; i < N; ++i) {
			if (H[i] > 0) {
//				Map<Profile, Integer> MAP = new HashMap<Profile, Integer>();
//				MAP.put(FR[i], 1);
				long nn = 1L;
				int j = i;
				while (H[j] > 0) {
					++nn;
//					int j2 = H[j]; H[j] = -1; j = j2;
//					if (!MAP.containsKey(FR[j]))
//						MAP.put(FR[j], 1);
//					else
//						MAP.put(FR[j], MAP.get(FR[j]) + 1);
				}
//				for (long v : MAP.values())
//					cnt += v * (v - 1) / 2;
				cnt += nn * (nn - 1) / 2;
			}
		}

		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				FR[i].hc = (int)((FR[i].hc + 1L * (1+i) * (1+i) * (1+i)) % 1000000007);

		HMAP = new HashMap<Integer, Integer>();
		H = new int [N];
		Arrays.fill(H, -1);
		for (int i = N-1; i >= 0; --i)
			if (ON[i] == 0) {
				int hc = FR[i].hc;
				if (!HMAP.containsKey(hc)) {
					HMAP.put(hc, i);
					H[i] = -1;
				} else {
					int j = HMAP.put(hc, i);
					H[i] = j;
				}
			}

		for (int i = 0; i < N; ++i) {
			if (H[i] > 0) {
//				Map<Profile, Integer> MAP = new HashMap<Profile, Integer>();
				int j = i;
				int last = ++FR[j].last;
//				if (FR[j].friends[last] == -1)
//					FR[j].friends[last] = j;
//				if (FR[j].friends[0] == -1)
//					for (int k = 1; k <= 1+last; ++k)
//						if (k <= last && FR[j].friends[k] < j)
//							FR[j].friends[k-1] = FR[j].friends[k];
//						else {
//							FR[j].friends[k-1] = j;
//							break;
//						}
//				MAP.put(FR[j], 1);
				long nn = 1L;
				while (H[j] > 0) {
					++nn;
//					int j2 = H[j]; H[j] = -1; j = j2;
//					last = ++FR[j].last;
//					if (FR[j].friends[last] == -1)
//						FR[j].friends[last] = j;
//					if (FR[j].friends[0] == -1)
//						for (int k = 1; k <= last; ++k)
//							if (k <= last && FR[j].friends[k] < j)
//								FR[j].friends[k-1] = FR[j].friends[k];
//							else {
//								FR[j].friends[k-1] = j;
//								break;
//							}
//					if (!MAP.containsKey(FR[j]))
//						MAP.put(FR[j], 1);
//					else
//						MAP.put(FR[j], MAP.get(FR[j]) + 1);
				}
//				for (long v : MAP.values())
//					cnt += v * (v - 1) / 2;
				cnt += nn * (nn - 1) / 2;
			}
		}

		print(cnt);
	}

	class Profile {
		int last = -1;
		final int id;
		final int [] friends;
		Profile (int i, int c) {
			id = i;
			friends = new int [1+c];
			Arrays.fill(friends, -1);
		}

		int hc = 0;
		public int hashCode() {
			return hc;
		}

		boolean sorted = false;
		public boolean equals(Object o) {
			Profile p = (Profile)o;
			if (p.last != last)
				return false;

			if (!sorted) {
				Arrays.sort(friends);
				sorted = true;
			}
			if (!p.sorted) {
				Arrays.sort(p.friends);
				p.sorted = true;
			}

			for (int i = 0; i <= last; ++i)
				if (friends[i] != p.friends[i])
					return false;
			return true;
		}

		public String toString() {
			return "#" + id + ": " + Arrays.toString(friends) + ", hc = " + hc;
		}

	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [][] F = new int [2][M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[0][m] = i-1;
			F[1][m] = j-1;
		}
		print(solve(N, M, F));
	}

	public long solve(int N, int M, int [][] F) {
		start();

		int [] C = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			++C[i]; ++C[j];
		}

		int [] Z = new int [N];
		Z[0] = C[0] == 0 ? 1 : 0;
		for (int i = 1; i < N; ++i)
			Z[i] = Z[i-1] + (C[i] == 0 ? 1 : 0);

		long zero = Z[N-1];
		long cnt = zero*(zero-1)/2;

		N -= zero;

		if (N == 0)
			return cnt;
			//print(cnt);

		for (int d = 0; d < 2; ++d)
			for (int m = 0; m < M; ++m)
				F[d][m] -= Z[F[d][m]];

		{
			int [] C2 = new int [N];
			int i = 0;
			for (int c : C)
				if (c > 0)
					C2[i++] = c;
			C = C2;
		}

		int [] ON = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (C[i] == 1)
				++ON[j];
			if (C[j] == 1)
				++ON[i];
		}

		long pairs = 0;
		for (int i = 0; i < N; ++i)
			if (C[i] == 1 && ON[i] == 1)
				++pairs;
			else
				cnt += 1L*ON[i]*(ON[i]-1)/2;
		cnt += pairs/2;

		int [] Q = new int [N];
		Q[0] = C[0] == 1 ? 1 : 0;
		for (int i = 1; i < N; ++i)
			Q[i] = Q[i-1] + (C[i] == 1 ? 1 : 0);

		int mm = 0;
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (C[i] == 1 || C[j] == 1)
				++mm;
		}

		int M2 = M - mm;
		int [][] F2 = new int [2][M2];
		for (int m = 0, m2 = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (C[i] > 1 && C[j] > 1) {
				F2[0][m2] = i - Q[i];
				F2[1][m2] = j - Q[j];
				++m2;
			}
		}

		int nn = Q[N-1];
		M = M2;
		F = F2;

		{
			int N2 = N - nn;
			int [] C2 = new int [N2];
			int [] ON2 = new int [N2];

			for (int i = 0, i2 = 0; i < N; ++i) {
				if (C[i] > 1) {
					C2[i2] = C[i];
					ON2[i2] = ON[i];
					++i2;
				}
			}

			C = C2;
			ON = ON2;
		}

		N -= nn;

		if (N == 0)
			return cnt;
			//print(cnt);

		int [][] FR = new int [N][];
		for (int i = 0; i < N; ++i) {
			if (ON[i] == 0) {
				FR[i] = new int[1+C[i]];
				Arrays.fill(FR[i], -1);
			}
		}

		Arrays.fill(C, 0);
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (ON[i] == 0)
				FR[i][C[i]++] = j;
			if (ON[j] == 0)
				FR[j][C[j]++] = i;
		}

		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				Arrays.sort(FR[i]);

		Map<String, Integer> MAP = new HashMap<String, Integer>();
		for (int i = 0; i < N; ++i) {
			if (ON[i] == 0) {
				String K = Arrays.toString(FR[i]);
				if (!MAP.containsKey(K))
					MAP.put(K, 0);
				MAP.put(K, MAP.get(K) + 1);
			}
		}

		for (long v: MAP.values())
			cnt += v*(v-1)/2;

		for (int i = 0; i < N; ++i)
			if (ON[i] == 0) {
				for (int j = 1; j <= 1+C[i]; ++j)
					if (j <= C[i] && FR[i][j] < i)
						FR[i][j-1] = FR[i][j];
					else {
						FR[i][j-1] = i;
						break;
					}
			}

		MAP = new HashMap<String, Integer>();
		for (int i = 0; i < N; ++i) {
			if (ON[i] == 0) {
				String K = Arrays.toString(FR[i]);
				if (!MAP.containsKey(K))
					MAP.put(K, 0);
				MAP.put(K, MAP.get(K) + 1);
			}
		}

		for (long v: MAP.values())
			cnt += v*(v-1)/2;

		//print(cnt);
		return cnt;
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	long MILL = 1000000L;

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		long [] F = new long [M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[m] = MILL * (i-1) + (j-1);
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, long [] F) {
		long cnt = s1(N, M, F);
		F = Arrays.copyOf(F, M+N);
		for (int i = 0; i < N; ++i)
			F[M+i] = (1+MILL) * i;
		cnt += s1(N, M+N, F);
		//return cnt;
		print(cnt);
	}

	public long s1 (int N, int M, long [] F) {
		start();

		final int [] C = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = (int)(F[m]/MILL), j = (int)(F[m]%MILL);
			++C[i];
			if (i != j)
				++C[j];
		}

		int [][] FR = new int [N][];
		for (int i = 0; i < N; ++i)
			FR[i] = new int[C[i]];

		Arrays.fill(C, 0);
		for (int m = 0; m < M; ++m) {
			int i = (int)(F[m]/MILL), j = (int)(F[m]%MILL);
			FR[i][C[i]++] = j;
			if (i != j)
				FR[j][C[j]++] = i;
		}

		for (int i = 0; i < N; ++i)
			if (C[i] >= 2)
				Arrays.sort(FR[i]);

		final int [][] H = new int [2][N];
		for (int i = 0; i < N; ++i)
			for (int j = 0; j < C[i]; ++j) {
				H[0][i] = (int)((H[0][i] * 37L + FR[i][j]) % 1000000007L);
				H[1][i] = (int)((H[1][i] * 31L + FR[i][j]) % 1000000009L);
			}

		Integer [] FF = new Integer [N];
		for (int i = 0; i < N; ++i)
			FF[i] = i;

		Arrays.sort(FF, new Comparator<Integer>() {
			public int compare(Integer arg0, Integer arg1) {
				long X = 2000000000 * (H[0][arg0] - H[0][arg1]) + H[1][arg0] - H[1][arg1];
				return X == 0 ? 0 : (X > 0 ? 1 : -1);
			}
		});

		int p;
		for (p = 0; p < N; ++p) {
			int pp = FF[p];
			if (C[pp] > 0)
				break;
		}

		long cnt = 1L*p*(p-1)/2;

		for (; p < N; ) {
			int pp = FF[p], q;
			for (q = p; q < N; ++q) {
				int qq = FF[q];
				if (C[qq] != C[pp] || H[0][qq] != H[0][pp] || H[1][qq] != H[1][pp])
					break;
			}
			if (q - p > 1) {
				long v = q-p;
				cnt += v*(v-1)/2;

//				Map<String, Integer> MAP = new HashMap<String, Integer>();
//				for (int i = p; i < q; ++i) {
//					int ii = FF[i];
//					String K = toString(FR[ii]);
//					if (!MAP.containsKey(K))
//						MAP.put(K, 0);
//					MAP.put(K, MAP.get(K) + 1);
//				}
//				for (long v: MAP.values())
//					cnt += v*(v-1)/2;
			}
			p = q;
		}

		return cnt;
	}

	String toString(int [] FR) {
		StringBuffer b = new StringBuffer();
		for (int f : FR)
			b.append(":" + f);
		return b.toString();
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [][] F = new int [2][M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[0][m] = i-1;
			F[1][m] = j-1;
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, int [][] F) {
		start();

		int [] C = new int [N];
		int mc = 0;
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			++C[i]; ++C[j];
			mc = Math.max(mc, Math.max(C[i], C[j]));
		}

		int [][] CN = new int [1+mc][];
		int [] QN = new int [1+mc];
		for (int i = 0; i < N; ++i)
			++QN[C[i]];
		for (int i = 0; i <= mc; ++i) {
			CN[i] = new int [QN[i]];
			QN[i] = 0;
		}

		for (int i = 0; i < N; ++i)
			CN[C[i]][QN[C[i]]++] = i;

		// C[i] - The degree of profile #i
		// CN[i] - The # of profiles of degree i

		long cnt = 1L * CN[0].length * (CN[0].length - 1)/2;

		if (N == C[0])
			print(cnt);

		int [] ON = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (C[i] == 1)
				++ON[j];
			if (C[j] == 1)
				++ON[i];
		}

		// ON[i] - # of profiles of degree 1 that are connected with profile #i

		long pairs = 0;
		for (int i = 0; i < N; ++i) {
			if (C[i] == 0)
				ON[i] = -1;
			else if (ON[i] == 1) {
				if (C[i] == 1)
					++pairs;
				else
					cnt += 1L * ON[i] * (ON[i] - 1)/2;
			}
		}
		cnt += pairs/2;

		int B = 0;
		for (int i = 0; i < N; ++i)
			if (ON[i] != 0)
				++B;

		if (N == B)
			print(cnt);

		Profile [] FR = new Profile [N];
		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				FR[i] = new Profile(i, C[i]);

		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (ON[i] == 0) {
				FR[i].friends[++FR[i].last] = j;
				FR[i].hc = (int)((FR[i].hc + 1L * (j+1) * (j+1) * (j+1)) % 1000000007);
			}
			if (ON[j] == 0) {
				FR[j].friends[++FR[j].last] = i;
				FR[j].hc = (int)((FR[j].hc + 1L * (i+1) * (i+1) * (i+1)) % 1000000007);
			}
		}

		Map<Integer, Integer> HMAP = new HashMap<Integer, Integer>();
		int [] H = new int [N];
		Arrays.fill(H, -1);
		for (int i = N-1; i >= 0; --i)
			if (ON[i] == 0) {
				int hc = FR[i].hc;
				if (!HMAP.containsKey(hc)) {
					HMAP.put(hc, i);
					H[i] = -1;
				} else {
					int j = HMAP.put(hc, i);
					H[i] = j;
				}
			}

		for (int i = 0; i < N; ++i) {
			if (H[i] > 0) {
//				Map<Profile, Integer> MAP = new HashMap<Profile, Integer>();
//				MAP.put(FR[i], 1);
				long nn = 1L;
				int j = i;
				while (H[j] > 0) {
					++nn;
					int j2 = H[j]; H[j] = -1; j = j2;
//					if (!MAP.containsKey(FR[j]))
//						MAP.put(FR[j], 1);
//					else
//						MAP.put(FR[j], MAP.get(FR[j]) + 1);
				}
//				for (long v : MAP.values())
//					cnt += v * (v - 1) / 2;
				cnt += nn * (nn - 1) / 2;
			}
		}

		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				FR[i].hc = (int)((FR[i].hc + 1L * (1+i) * (1+i) * (1+i)) % 1000000007);

		HMAP = new HashMap<Integer, Integer>();
		H = new int [N];
		Arrays.fill(H, -1);
		for (int i = N-1; i >= 0; --i)
			if (ON[i] == 0) {
				int hc = FR[i].hc;
				if (!HMAP.containsKey(hc)) {
					HMAP.put(hc, i);
					H[i] = -1;
				} else {
					int j = HMAP.put(hc, i);
					H[i] = j;
				}
			}

		for (int i = 0; i < N; ++i) {
			if (H[i] > 0) {
//				Map<Profile, Integer> MAP = new HashMap<Profile, Integer>();
				int j = i;
				int last = ++FR[j].last;
//				if (FR[j].friends[last] == -1)
//					FR[j].friends[last] = j;
//				if (FR[j].friends[0] == -1)
//					for (int k = 1; k <= 1+last; ++k)
//						if (k <= last && FR[j].friends[k] < j)
//							FR[j].friends[k-1] = FR[j].friends[k];
//						else {
//							FR[j].friends[k-1] = j;
//							break;
//						}
//				MAP.put(FR[j], 1);
				long nn = 1L;
				while (H[j] > 0) {
					++nn;
					int j2 = H[j]; H[j] = -1; j = j2;
//					last = ++FR[j].last;
//					if (FR[j].friends[last] == -1)
//						FR[j].friends[last] = j;
//					if (FR[j].friends[0] == -1)
//						for (int k = 1; k <= last; ++k)
//							if (k <= last && FR[j].friends[k] < j)
//								FR[j].friends[k-1] = FR[j].friends[k];
//							else {
//								FR[j].friends[k-1] = j;
//								break;
//							}
//					if (!MAP.containsKey(FR[j]))
//						MAP.put(FR[j], 1);
//					else
//						MAP.put(FR[j], MAP.get(FR[j]) + 1);
				}
//				for (long v : MAP.values())
//					cnt += v * (v - 1) / 2;
				cnt += nn * (nn - 1) / 2;
			}
		}

		print(cnt);
	}

	class Profile {
		int last = -1;
		final int id;
		final int [] friends;
		Profile (int i, int c) {
			id = i;
			friends = new int [1+c];
			Arrays.fill(friends, -1);
		}

		int hc = 0;
		public int hashCode() {
			return hc;
		}

		boolean sorted = false;
		public boolean equals(Object o) {
			Profile p = (Profile)o;
			if (p.last != last)
				return false;

			if (!sorted) {
				Arrays.sort(friends);
				sorted = true;
			}
			if (!p.sorted) {
				Arrays.sort(p.friends);
				p.sorted = true;
			}

			for (int i = 0; i <= last; ++i)
				if (friends[i] != p.friends[i])
					return false;
			return true;
		}

		public String toString() {
			return "#" + id + ": " + Arrays.toString(friends) + ", hc = " + hc;
		}

	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [] F = new int [M], T = new int [M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[m] = i-1;
			T[m] = j-1;
		}
		solve(N, M, F, T);
	}

	public void solve(int N, int M, int [] F, int [] T) {
		start();

		long [] HH = new long [N];
		long [] MM = new  long [N];

		for (int n = 0; n < N; ++n)
			MM[n] = (1L * (n+1) * (n+1) * (n+1));

		for (int m = 0; m < M; ++m) {
			HH[F[m]] += MM[T[m]];
			HH[T[m]] += MM[F[m]];
		}

		long cnt = 0;
		long [] LL = new long [N];
		for (int n = 0; n < N; ++n)
			LL[n] = HH[n] + MM[n];

		for (int m = 0; m < M; ++m)
			if (LL[F[m]] == LL[T[m]])
				++cnt;

		Arrays.sort(HH);
		long sz = 1;
		for (int p = 1; p < N; ++p) {
			if (HH[p] == HH[p-1])
				++sz;
			else {
				cnt += sz * (sz - 1) / 2;
				sz = 1;
			}
		}
		cnt += sz * (sz - 1) / 2;

		print(cnt);
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in), 0x10000);
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [][] F = new int [2][M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[0][m] = i-1;
			F[1][m] = j-1;
		}
		print(solve(N, M, F));
	}

	public long solve(int N, int M, int [][] F) {
		start();

		int [] C = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			++C[i]; ++C[j];
		}

		int [] Z = new int [N];
		Z[0] = C[0] == 0 ? 1 : 0;
		for (int i = 1; i < N; ++i)
			Z[i] = Z[i-1] + (C[i] == 0 ? 1 : 0);

		long zero = Z[N-1];
		long cnt = zero*(zero-1)/2;

		N -= zero;

		if (N == 0)
			return cnt;
			//print(cnt);

		for (int d = 0; d < 2; ++d)
			for (int m = 0; m < M; ++m)
				F[d][m] -= Z[F[d][m]];

		{
			int [] C2 = new int [N];
			int i = 0;
			for (int c : C)
				if (c > 0)
					C2[i++] = c;
			C = C2;
		}

		int [] ON = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (C[i] == 1)
				++ON[j];
			if (C[j] == 1)
				++ON[i];
		}

		long pairs = 0;
		for (int i = 0; i < N; ++i)
			if (C[i] == 1 && ON[i] == 1)
				++pairs;
			else
				cnt += 1L*ON[i]*(ON[i]-1)/2;
		cnt += pairs/2;

		int [] Q = new int [N];
		Q[0] = C[0] == 1 ? 1 : 0;
		for (int i = 1; i < N; ++i)
			Q[i] = Q[i-1] + (C[i] == 1 ? 1 : 0);

		int mm = 0;
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (C[i] == 1 || C[j] == 1)
				++mm;
		}

		int M2 = M - mm;
		int [][] F2 = new int [2][M2];
		for (int m = 0, m2 = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (C[i] > 1 && C[j] > 1) {
				F2[0][m2] = i - Q[i];
				F2[1][m2] = j - Q[j];
				++m2;
			}
		}

		int nn = Q[N-1];
		M = M2;
		F = F2;

		{
			int N2 = N - nn;
			int [] C2 = new int [N2];
			int [] ON2 = new int [N2];

			for (int i = 0, i2 = 0; i < N; ++i) {
				if (C[i] > 1) {
					C2[i2] = C[i] - ON[i];
					ON2[i2] = ON[i];
					++i2;
				}
			}

			C = C2;
			ON = ON2;
		}

		N -= nn;

		if (N == 0)
			return cnt;
			//print(cnt);

		int [][] FR = new int [N][];
		for (int i = 0; i < N; ++i) {
			if (ON[i] == 0) {
				FR[i] = new int[1+C[i]];
				Arrays.fill(FR[i], -1);
			}
		}

		Arrays.fill(C, 0);
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (ON[i] == 0)
				FR[i][C[i]++] = j;
			if (ON[j] == 0)
				FR[j][C[j]++] = i;
		}

		int [] H = new int [N];
		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				for (int j = 0; j < C[i]; ++j)
					H[i] = (H[i] + (1 + FR[i][j])) % 1000000007;

		Set<Integer> SET = new HashSet<Integer>();
		Map<Integer, List<Integer>> MAP = new HashMap<Integer, List<Integer>>();

		for (int i = 0; i < N; ++i)
			if (ON[i] == 0) {
				if (!SET.add(H[i]))
					MAP.put(H[i], new ArrayList<Integer>());
			}

		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				if (MAP.containsKey(H[i]))
					MAP.get(H[i]).add(i);

		for (List<Integer> L : MAP.values()) {
			Map<String, Integer> MAP2 = new HashMap<String, Integer>();
			for (int i : L) {
				Arrays.sort(FR[i]);
				String K = Arrays.toString(FR[i]);
				if (!MAP2.containsKey(K))
					MAP2.put(K, 0);
				MAP2.put(K, MAP2.get(K) + 1);
			}
			for (long v: MAP2.values())
				cnt += v*(v-1)/2;
		}

		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				H[i] = (H[i] + (1+i)) % 1000000007;

		SET = new HashSet<Integer>();
		MAP = new HashMap<Integer, List<Integer>>();

		for (int i = 0; i < N; ++i)
			if (ON[i] == 0) {
				if (!SET.add(H[i]))
					MAP.put(H[i], new ArrayList<Integer>());
			}

		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				if (MAP.containsKey(H[i]))
					MAP.get(H[i]).add(i);

		return 12345678;

//		for (List<Integer> L : MAP.values()) {
//			Map<String, Integer> MAP2 = new HashMap<String, Integer>();
//			for (int i : L) {
//				if (FR[i][0] == -1)
//					FR[i][0] = i;
//				else
//					FR[i][C[i]] = i;
//				Arrays.sort(FR[i]);
//				String K = Arrays.toString(FR[i]);
//				if (!MAP2.containsKey(K))
//					MAP2.put(K, 0);
//				MAP2.put(K, MAP2.get(K) + 1);
//			}
//			for (long v: MAP2.values())
//				cnt += v*(v-1)/2;
//		}
//
//		//print(cnt);
//		return cnt;
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [][] F = new int [2][M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[0][m] = i-1;
			F[1][m] = j-1;
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, int [][] F) {
		start();

		int [] C = new int [N];
		int mc = 0;
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			++C[i]; ++C[j];
			mc = Math.max(mc, Math.max(C[i], C[j]));
		}

		int [][] CN = new int [1+mc][];
		int [] QN = new int [1+mc];
		for (int i = 0; i < N; ++i)
			++QN[C[i]];
		for (int i = 0; i <= mc; ++i) {
			CN[i] = new int [QN[i]];
			QN[i] = 0;
		}

		for (int i = 0; i < N; ++i)
			CN[C[i]][QN[C[i]]++] = i;

		// C[i] - The degree of profile #i
		// CN[i] - The # of profiles of degree i

		long cnt = 1L * CN[0].length * (CN[0].length - 1)/2;

		if (N == C[0])
			print(cnt);

		int [] ON = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (C[i] == 1)
				++ON[j];
			if (C[j] == 1)
				++ON[i];
		}

		// ON[i] - # of profiles of degree 1 that are connected with profile #i

		long pairs = 0;
		for (int i = 0; i < N; ++i) {
			if (C[i] == 0)
				ON[i] = -1;
			else if (ON[i] == 1) {
				if (C[i] == 1)
					++pairs;
				else
					cnt += 1L * ON[i] * (ON[i] - 1)/2;
			}
		}
		cnt += pairs/2;

		int B = 0;
		for (int i = 0; i < N; ++i)
			if (ON[i] != 0)
				++B;

		if (N == B)
			print(cnt);

//		Profile [] FR = new Profile [N];
//		for (int i = 0; i < N; ++i)
//			if (ON[i] == 0)
//				FR[i] = new Profile(i, C[i]);

//		int [][] FR = new int [N][];
//		for (int i = 0; i < N; ++i)
//			if (ON[i] == 0) {
//				FR[i] = new int [1+C[i]];
//				Arrays.fill(FR[i], -1);
//			}

		long MOD = 1000000000000000007L;

//		for (int m = 0; m < M; ++m) {
//		int i = F[0][m], j = F[1][m];
//		if (ON[i] == 0) {
//			FR[i].friends[++FR[i].last] = j;
//			FR[i].hc = (FR[i].hc + 1L * (j+1) * (j+1) * (j+1)) % MOD;
//		}
//		if (ON[j] == 0) {
//			FR[j].friends[++FR[j].last] = i;
//			FR[j].hc = (FR[j].hc + 1L * (i+1) * (i+1) * (i+1)) % MOD;
//		}
//	}

		long [] HH = new long [N];

		Arrays.fill(C, 0);
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (ON[i] == 0) {
//				FR[i][C[i]++] = j;
				HH[i] = (HH[i] + 1L * (j+1) * (j+1) * (j+1)) % MOD;
			}
			if (ON[j] == 0) {
//				FR[j][C[j]++] = i;
				HH[j] = (HH[j] + 1L * (i+1) * (i+1) * (i+1)) % MOD;
		}
	}

		Map<Long, Integer> HMAP = new HashMap<Long, Integer>();
//		int [] H = new int [N];
//		Arrays.fill(H, -1);
		for (int i = N-1; i >= 0; --i)
			if (ON[i] == 0) {
				long hc = HH[i]; // FR[i].hc;
				if (!HMAP.containsKey(hc)) {
					HMAP.put(hc, 1); // i);
					//H[i] = -1;
				} else {
					HMAP.put(hc, HMAP.get(hc) + 1);
//					int j = HMAP.put(hc, i);
//					H[i] = j;
				}
			}
		for (long v : HMAP.values())
			cnt += v * (v-1) / 2;

//		for (int i = 0; i < N; ++i) {
//			if (H[i] > 0) {
////				Map<Profile, Integer> MAP = new HashMap<Profile, Integer>();
////				MAP.put(FR[i], 1);
//				long nn = 1L;
//				int j = i;
//				while (H[j] > 0) {
//					++nn;
//					int j2 = H[j]; H[j] = -1; j = j2;
////					if (!MAP.containsKey(FR[j]))
////						MAP.put(FR[j], 1);
////					else
////						MAP.put(FR[j], MAP.get(FR[j]) + 1);
//				}
////				for (long v : MAP.values())
////					cnt += v * (v - 1) / 2;
//				cnt += nn * (nn - 1) / 2;
//			}
//		}

		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				//FR[i].hc = (FR[i].hc + 1L * (1+i) * (1+i) * (1+i)) % MOD;
				HH[i] = (HH[i] + 1L * (1+i) * (1+i) * (1+i)) % MOD;

		HMAP = new HashMap<Long, Integer>();
//		H = new int [N];
//		Arrays.fill(H, -1);
		for (int i = N-1; i >= 0; --i)
			if (ON[i] == 0) {
				long hc = HH[i]; // FR[i].hc;
				if (!HMAP.containsKey(hc)) {
					HMAP.put(hc, 1); // i);
					//H[i] = -1;
				} else {
					HMAP.put(hc, HMAP.get(hc) + 1);
					//int j = HMAP.put(hc, i);
					//H[i] = j;
				}
			}
		for (long v : HMAP.values())
			cnt += v * (v-1) / 2;

//		for (int i = 0; i < N; ++i) {
//			if (H[i] > 0) {
//				Map<Profile, Integer> MAP = new HashMap<Profile, Integer>();
//				int j = i;
//				int last = ++FR[j].last;
//				if (FR[j].friends[last] == -1)
//					FR[j].friends[last] = j;
//				if (FR[j].friends[0] == -1)
//					for (int k = 1; k <= 1+last; ++k)
//						if (k <= last && FR[j].friends[k] < j)
//							FR[j].friends[k-1] = FR[j].friends[k];
//						else {
//							FR[j].friends[k-1] = j;
//							break;
//						}
//				MAP.put(FR[j], 1);
//				long nn = 1L;
//				while (H[j] > 0) {
//					++nn;
//					int j2 = H[j]; H[j] = -1; j = j2;
//					last = ++FR[j].last;
//					if (FR[j].friends[last] == -1)
//						FR[j].friends[last] = j;
//					if (FR[j].friends[0] == -1)
//						for (int k = 1; k <= last; ++k)
//							if (k <= last && FR[j].friends[k] < j)
//								FR[j].friends[k-1] = FR[j].friends[k];
//							else {
//								FR[j].friends[k-1] = j;
//								break;
//							}
//					if (!MAP.containsKey(FR[j]))
//						MAP.put(FR[j], 1);
//					else
//						MAP.put(FR[j], MAP.get(FR[j]) + 1);
//				}
//				for (long v : MAP.values())
//					cnt += v * (v - 1) / 2;
//				cnt += nn * (nn - 1) / 2;
//			}
//		}

		print(cnt);
	}

//	class Profile {
//		int last = -1;
//		final int id;
//		final int [] friends;
//		Profile (int i, int c) {
//			id = i;
//			friends = new int [1+c];
//			Arrays.fill(friends, -1);
//		}
//
//		long hc = 0;
////		public int hashCode() {
////			return hc;
////		}
//
//		boolean sorted = false;
//		public boolean equals(Object o) {
//			Profile p = (Profile)o;
//			if (p.last != last)
//				return false;
//
//			if (!sorted) {
//				Arrays.sort(friends);
//				sorted = true;
//			}
//			if (!p.sorted) {
//				Arrays.sort(p.friends);
//				p.sorted = true;
//			}
//
//			for (int i = 0; i <= last; ++i)
//				if (friends[i] != p.friends[i])
//					return false;
//			return true;
//		}
//
//		public String toString() {
//			return "#" + id + ": " + Arrays.toString(friends) + ", hc = " + hc;
//		}
//
//	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [][] F = new int [2][M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[0][m] = i-1;
			F[1][m] = j-1;
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, int [][] F) {
		start();

		int [] C = new int [N];
		int mc = 0;
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			++C[i]; ++C[j];
			mc = Math.max(mc, Math.max(C[i], C[j]));
		}

		int [][] CN = new int [1+mc][];
		int [] QN = new int [1+mc];
		for (int i = 0; i < N; ++i)
			++QN[C[i]];
		for (int i = 0; i <= mc; ++i) {
			CN[i] = new int [QN[i]];
			QN[i] = 0;
		}

		for (int i = 0; i < N; ++i)
			CN[C[i]][QN[C[i]]++] = i;

		// C[i] - The degree of profile #i
		// CN[i] - The # of profiles of degree i

		long cnt = 1L * CN[0].length * (CN[0].length - 1)/2;

		if (N == C[0])
			print(cnt);

		int [] ON = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (C[i] == 1)
				++ON[j];
			if (C[j] == 1)
				++ON[i];
		}

		// ON[i] - # of profiles of degree 1 that are connected with profile #i

		long pairs = 0;
		for (int i = 0; i < N; ++i) {
			if (C[i] == 0)
				ON[i] = -1;
			else if (ON[i] == 1) {
				if (C[i] == 1)
					++pairs;
				else
					cnt += 1L * ON[i] * (ON[i] - 1)/2;
			}
		}
		cnt += pairs/2;

		int B = 0;
		for (int i = 0; i < N; ++i)
			if (ON[i] != 0)
				++B;

		if (N == B)
			print(cnt);

		Profile [] FR = new Profile [N];
		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				FR[i] = new Profile(i, C[i]);

		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (ON[i] == 0) {
				FR[i].friends[++FR[i].last] = j;
				FR[i].hc = (int)((FR[i].hc + 1L * (j+1) * (j+1) * (j+1)) % 1000000007);
			}
			if (ON[j] == 0) {
				FR[j].friends[++FR[j].last] = i;
				FR[j].hc = (int)((FR[j].hc + 1L * (i+1) * (i+1) * (i+1)) % 1000000007);
			}
		}

		Map<Integer, Integer> HMAP = new HashMap<Integer, Integer>();
		int [] H = new int [N];
		Arrays.fill(H, -1);
		for (int i = N-1; i >= 0; --i)
			if (ON[i] == 0) {
				int hc = FR[i].hc;
				if (!HMAP.containsKey(hc)) {
					HMAP.put(hc, i);
					H[i] = -1;
				} else {
					int j = HMAP.put(hc, i);
					H[i] = j;
				}
			}

		for (int i = 0; i < N; ++i) {
			if (H[i] > 0) {
				Map<Profile, Integer> MAP = new HashMap<Profile, Integer>();
				MAP.put(FR[i], 1);
				int j = i;
				while (H[j] > 0) {
					int j2 = H[j]; H[j] = -1; j = j2;
					if (!MAP.containsKey(FR[j]))
						MAP.put(FR[j], 1);
					else
						MAP.put(FR[j], MAP.get(FR[j]) + 1);
				}
				for (long v : MAP.values())
					cnt += v * (v - 1) / 2;
			}
		}

		for (int i = 0; i < N; ++i)
			if (ON[i] == 0)
				FR[i].hc = (int)(FR[i].hc + 1L * (1+i) * (1+i) * (1+i)) % 1000000007;

		HMAP = new HashMap<Integer, Integer>();
		H = new int [N];
		Arrays.fill(H, -1);
		for (int i = N-1; i >= 0; --i)
			if (ON[i] == 0) {
				int hc = FR[i].hc;
				if (!HMAP.containsKey(hc)) {
					HMAP.put(hc, i);
					H[i] = -1;
				} else {
					int j = HMAP.put(hc, i);
					H[i] = j;
				}
			}

		for (int i = 0; i < N; ++i) {
			if (H[i] > 0) {
				Map<Profile, Integer> MAP = new HashMap<Profile, Integer>();
				int j = i;
				int last = ++FR[j].last;
				if (FR[j].friends[last] == -1)
					FR[j].friends[last] = j;
				if (FR[j].friends[0] == -1)
					for (int k = 1; k <= 1+last; ++k)
						if (k <= last && FR[j].friends[k] < j)
							FR[j].friends[k-1] = FR[j].friends[k];
						else {
							FR[j].friends[k-1] = j;
							break;
						}
				MAP.put(FR[j], 1);
				while (H[j] > 0) {
					int j2 = H[j]; H[j] = -1; j = j2;
					last = ++FR[j].last;
					if (FR[j].friends[last] == -1)
						FR[j].friends[last] = j;
					if (FR[j].friends[0] == -1)
						for (int k = 1; k <= last; ++k)
							if (k <= last && FR[j].friends[k] < j)
								FR[j].friends[k-1] = FR[j].friends[k];
							else {
								FR[j].friends[k-1] = j;
								break;
							}
					if (!MAP.containsKey(FR[j]))
						MAP.put(FR[j], 1);
					else
						MAP.put(FR[j], MAP.get(FR[j]) + 1);
				}
				for (long v : MAP.values())
					cnt += v * (v - 1) / 2;
			}
		}

		print(cnt);
	}

	class Profile {
		int last = -1;
		final int id;
		final int [] friends;
		Profile (int i, int c) {
			id = i;
			friends = new int [1+c];
			Arrays.fill(friends, -1);
		}

		int hc = 0;
		public int hashCode() {
			return hc;
		}

		boolean sorted = false;
		public boolean equals(Object o) {
			Profile p = (Profile)o;
			if (p.last != last)
				return false;

			if (!sorted) {
				Arrays.sort(friends);
				sorted = true;
			}
			if (!p.sorted) {
				Arrays.sort(p.friends);
				p.sorted = true;
			}
			return Arrays.equals(friends, p.friends);
		}

		public String toString() {
			return "#" + id + ": " + Arrays.toString(friends) + ", hc = " + hc;
		}

	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [][] F = new int [2][M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[0][m] = i-1;
			F[1][m] = j-1;
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, int [][] F) {
		long cnt = s1(N, M, F);
		F[0] = Arrays.copyOf(F[0], M+N);
		F[1] = Arrays.copyOf(F[1], M+N);
		for (int i = 0; i < N; ++i)
			F[0][M+i] = F[1][M+i] = i;
		cnt += s1(N, M+N, F);
		print(cnt);
	}

	public long s1 (int N, int M, int [][] F) {
		start();

		final int [] C = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			++C[i];
			if (i != j)
				++C[j];
		}

		int [][] FR = new int [N][];
		for (int i = 0; i < N; ++i)
			FR[i] = new int[C[i]];

		Arrays.fill(C, 0);
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			FR[i][C[i]++] = j;
			if (i != j)
				FR[j][C[j]++] = i;
		}

		for (int i = 0; i < N; ++i)
			if (C[i] >= 2)
				Arrays.sort(FR[i]);

		final int [] H = new int [N];
		for (int i = 0; i < N; ++i)
			for (int j = 0; j < C[i]; ++j)
				H[i] = (H[i] * 19 + FR[i][j]) % 100000007;

		Integer [] FF = new Integer [N];
		for (int i = 0; i < N; ++i)
			FF[i] = i;

		Arrays.sort(FF, new Comparator<Integer>() {
			public int compare(Integer arg0, Integer arg1) {
				if (C[arg0] != C[arg1])
					return C[arg0] - C[arg1];
				else
					return H[arg0] - H[arg1];
			}
		});

		int p;
		for (p = 0; p < N; ++p) {
			int pp = FF[p];
			if (C[pp] > 0)
				break;
		}

		long cnt = 1L*p*(p-1)/2;

		for (; p < N; ) {
			int pp = FF[p], q;
			for (q = p; q < N; ++q) {
				int qq = FF[q];
				if (C[qq] != C[pp] || H[qq] != H[pp])
					break;
			}
			if (q - p > 1) {
				Map<String, Integer> MAP = new HashMap<String, Integer>();
				for (int i = p; i < q; ++i) {
					int ii = FF[i];
					String K = toString(FR[ii]);
					if (!MAP.containsKey(K))
						MAP.put(K, 0);
					MAP.put(K, MAP.get(K) + 1);
				}
				for (long v: MAP.values())
					cnt += v*(v-1)/2;
			}
			p = q;
		}

		return cnt;
	}

	String toString(int [] FR) {
		StringBuffer b = new StringBuffer();
		for (int f : FR)
			b.append(":" + f);
		return b.toString();
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [][] F = new int [2][M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[0][m] = i-1;
			F[1][m] = j-1;
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, int [][] F) {
		start();

		long MOD = 1000000000000000007L;
		long [] HH = new long [N];
		long [] MM = new  long [N];

		for (int n = 0; n < N; ++n)
			MM[n] = (1L * (n+1) * (n+1) * (n+1)) % MOD;

		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			HH[i] = (HH[i] + MM[j]) % MOD;
			HH[j] = (HH[j] + MM[i]) % MOD;
		}

		long cnt = 0;

		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if ((HH[i] + MM[i]) % MOD == (HH[j] + MM[j]) % MOD)
				++cnt;
		}

		Arrays.sort(HH);

		for (int p = 0; p < N; ) {
			int q;
			for (q = p; q < N && HH[p] == HH[q]; ++q);
			long diff = q - p;
			cnt += diff * (diff - 1) / 2;
			p = q;
		}

		print(cnt);
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	long MILL = 1000000L;

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		long [] F = new long [M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[m] = MILL * (i-1) + (j-1);
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, long [] F) {
		long cnt = s1(N, M, F);
		F = Arrays.copyOf(F, M+N);
		for (int i = 0; i < N; ++i)
			F[M+i] = (1+MILL) * i;
		cnt += s1(N, M+N, F);
		//return cnt;
		print(cnt);
	}

	public long s1 (int N, int M, long [] F) {
		start();

		final int [] C = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = (int)(F[m]/MILL), j = (int)(F[m]%MILL);
			++C[i];
			if (i != j)
				++C[j];
		}

		int [][] FR = new int [N][];
		for (int i = 0; i < N; ++i)
			FR[i] = new int[C[i]];

		Arrays.fill(C, 0);
		for (int m = 0; m < M; ++m) {
			int i = (int)(F[m]/MILL), j = (int)(F[m]%MILL);
			FR[i][C[i]++] = j;
			if (i != j)
				FR[j][C[j]++] = i;
		}

		for (int i = 0; i < N; ++i)
			if (C[i] >= 2)
				Arrays.sort(FR[i]);

		final int [][] H = new int [2][N];
		for (int i = 0; i < N; ++i)
			for (int j = 0; j < C[i]; ++j) {
				H[0][i] = (int)((H[0][i] * 37L + FR[i][j]) % 1000000007L);
				H[1][i] = (int)((H[1][i] * 31L + FR[i][j]) % 1000000009L);
			}

		Integer [] FF = new Integer [N];
		for (int i = 0; i < N; ++i)
			FF[i] = i;

		Arrays.sort(FF, new Comparator<Integer>() {
			public int compare(Integer arg0, Integer arg1) {
				if (C[arg0] != C[arg1])
					return C[arg0] - C[arg1];
				else if (H[0][arg0] != H[0][arg1])
					return H[0][arg0] - H[0][arg1];
				else
					return H[1][arg0] - H[1][arg1];
			}
		});

		int p;
		for (p = 0; p < N; ++p) {
			int pp = FF[p];
			if (C[pp] > 0)
				break;
		}

		long cnt = 1L*p*(p-1)/2;

		for (; p < N; ) {
			int pp = FF[p], q;
			for (q = p; q < N; ++q) {
				int qq = FF[q];
				if (C[qq] != C[pp] || H[0][qq] != H[0][pp] || H[1][qq] != H[1][pp])
					break;
			}
			if (q - p > 1) {
				long v = q-p;
				cnt += v*(v-1)/2;

//				Map<String, Integer> MAP = new HashMap<String, Integer>();
//				for (int i = p; i < q; ++i) {
//					int ii = FF[i];
//					String K = toString(FR[ii]);
//					if (!MAP.containsKey(K))
//						MAP.put(K, 0);
//					MAP.put(K, MAP.get(K) + 1);
//				}
//				for (long v: MAP.values())
//					cnt += v*(v-1)/2;
			}
			p = q;
		}

		return cnt;
	}

	String toString(int [] FR) {
		StringBuffer b = new StringBuffer();
		for (int f : FR)
			b.append(":" + f);
		return b.toString();
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [][] F = new int [2][M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[0][m] = i-1;
			F[1][m] = j-1;
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, int [][] F) {
		start();

		long MOD = 1000000000000000007L;
		long [] HH = new long [N];
		long [] MM = new  long [N];

		for (int n = 0; n < N; ++n)
			MM[n] = (1L * (n+1) * (n+1) * (n+1)) % MOD;

		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			HH[i] = (HH[i] + MM[j]) % MOD;
			HH[j] = (HH[j] + MM[i]) % MOD;
		}

		long cnt = 0;

		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if ((HH[i] + MM[i]) % MOD == (HH[j] + MM[j]) % MOD)
				++cnt;
		}

		Arrays.sort(HH);

		for (int p = 0; p < N; ) {
			int q;
			for (q = p; q < N && HH[p] == HH[q]; ++q);
			long diff = q - p;
			cnt += diff * (diff - 1) / 2;
			p = q;
		}

		print(cnt);
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in), 0x10000);
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.math.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [] F = new int [M], T = new int [M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[m] = i-1;
			T[m] = j-1;
		}
		solve(N, M, F, T);
	}

	public void solve(int N, int M, int [] F, int [] T) {
		start();

		long [] H = new long [N], S = new long [N];
		long P = 3, R = 1; // BigInteger.probablePrime(8, new Random()).longValue(), R = 1;

		for (int n = 0; n < N; ++n) {
			S[n] = R;
			R *= P;
		}

		for (int m = 0; m < M; ++m) {
			H[F[m]] += S[T[m]];
			H[T[m]] += S[F[m]];
		}

		long cnt = 0;
		long [] L = new long [N];
		for (int n = 0; n < N; ++n)
			L[n] = H[n] + S[n];

		for (int m = 0; m < M; ++m)
			if (L[F[m]] == L[T[m]])
				++cnt;

		Arrays.sort(H);
		long sz = 1;
		for (int p = 1; p < N; ++p) {
			if (H[p] == H[p-1])
				++sz;
			else {
				cnt += sz * (sz - 1) / 2;
				sz = 1;
			}
		}
		cnt += sz * (sz - 1) / 2;

		print(cnt);
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in), 0x10000);
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}


import java.io.*;
import java.util.*;

public class C {

	public C () throws IOException {
		String [] NM = r.readLine().split(" ");
		int N = Integer.parseInt(NM[0]);
		int M = Integer.parseInt(NM[1]);
		int [][] F = new int [2][M];
		for (int m = 0; m < M; ++m) {
			String [] ij = r.readLine().split(" ");
			int i = Integer.parseInt(ij[0]);
			int j = Integer.parseInt(ij[1]);
			F[0][m] = i-1;
			F[1][m] = j-1;
		}
		solve(N, M, F);
	}

	public void solve(int N, int M, int [][] F) {
		start();

		int [] used = new int [N];
		for (int m = 0; m < M; ++m) {
			++used[F[0][m]];
			++used[F[1][m]];
		}

		long zero = 0;
		for (int u : used)
			if (u == 0)
				++zero;

		long cnt = zero * (zero - 1) / 2;

		if (N == zero)
			print(cnt);

		int [] tone = new int [N];
		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (used[i] == 1)
				++tone[j];
			if (used[j] == 1)
				++tone[i];
		}

		long pairs = 0;
		for (int i = 0; i < N; ++i) {
			if (used[i] == 0)
				tone[i] = -1;
			else if (tone[i] == 1) {
				if (used[i] == 1)
					++pairs;
				else
					cnt += 1L * tone[i] * (tone[i] - 1)/2;
			}
		}
		cnt += pairs/2;

		int rest = 0;
		for (int i = 0; i < N; ++i)
			if (tone[i] == 0)
				++rest;

		if (rest == 0)
			print(cnt);

		long MOD = 1000000000000000007L;
		long [] HH = new long [N];

		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (tone[i] == 0)
				HH[i] = ((HH[i] + 1L * (j+1) * (j+1) * (j+1)) % MOD);
			if (tone[j] == 0)
				HH[j] = ((HH[j] + 1L * (i+1) * (i+1) * (i+1)) % MOD);
		}

		long [] Z = new long [rest];
		for (int i = 0, y = 0; i < N; ++i)
			if (tone[i] == 0)
				Z[y++] = HH[i];
		Arrays.sort(Z);

		for (int p = 0; p < rest; ) {
			int q;
			for (q = p; q < rest && Z[p] == Z[q]; ++q);
			long diff = q - p;
			cnt += diff * (diff - 1) / 2;
			p = q;
		}

		for (int m = 0; m < M; ++m) {
			int i = F[0][m], j = F[1][m];
			if (HH[i] == HH[j])
				++cnt;
		}

		print(cnt);
	}

	////////////////////////////////////////////////////////////////////////////////////

	static BufferedReader r;
	static long t;

	static void print2 (Object o) {
		System.out.println(o);
	}

	static void print (Object o) {
		print2(o);
		//print2((millis() - t) / 1000.0);
		System.exit(0);
	}

	static void run () throws IOException {
		r = new BufferedReader(new InputStreamReader(System.in));
		new C();
	}

	public static void main(String[] args) throws IOException {
		run();
	}

	static long millis() {
		return System.currentTimeMillis();
	}

	static void start() {
		t = millis();
	}
}