#include <bits/stdc++.h>
using namespace std;

#define FOR(i,a,b) for(int i=int(a);i<int(b);i++)
#define REP(i,b) FOR(i,0,b)
#define MP make_pair
#define PB push_back
#define ALL(x) x.begin(),x.end()
#define REACH cerr<<"reached line "<<__LINE__<<endl
#define DBG(x) cerr<<"line "<<__LINE__<<" "<<#x<<":"<<x<<endl

using uint=unsigned int;
using ll=long long;
using pii=pair<int,int>;
using vi=vector<int>;
using ld=long double;

template<class T,class U>
ostream& operator<<(ostream& os,const pair<T,U>& p){
	os<<"("<<p.first<<","<<p.second<<")";
	return os;
}

template<class T>
ostream& operator <<(ostream& os,const vector<T>& v){
	os<<"[";
	REP(i,(int)v.size()){
		if(i)os<<",";
		os<<v[i];
	}
	os<<"]";
	return os;
}

int read(){
	int i;
	scanf("%d",&i);
	return i;
}

ll readLL(){
	ll i;
	scanf("%lld",&i);
	return i;
}

string readString(){
	static char buf[3341919];
	scanf("%s",buf);
	return string(buf);
}

char* readCharArray(){
	static char buf[3341919];
	static int bufUsed=0;
	char* ret=buf+bufUsed;
	scanf("%s",ret);
	bufUsed+=strlen(ret)+1;
	return ret;
}

template<class T,class U>
void chmax(T& a,U b){
	if(a<b)
		a=b;
}

template<class T,class U>
void chmin(T& a,U b){
	if(a>b)
		a=b;
}

template<class T>
T Sq(const T& t){
	return t*t;
}

const int mod=10007;
template<class T,class U>
void add(T& a,U b){
	a=((ll)a+b)%mod;
}

template<class T,class U>
void sub(T& a,U b){
	a=((ll)a-b%mod+mod)%mod;
}

template<class T,class U>
void mult(T& a,U b){
	a=((ll)a*b)%mod;
}

ll modPow(ll a,ll p){
	ll s=1;
	REP(i,30){
		if((p>>i)&1)
			mult(s,a);
		mult(a,a);
	}
	return s;
}

ll modInv(ll a){
	return modPow(a,mod-2);
}

struct Wafrelka{
	int n,m;
	vector<vi> graph;
	Wafrelka(int _n,int _m):n(_n),m(_m){
		graph.assign(n,vi());
	}
	void AddEdge(int a,int b){
		graph[a].PB(b);
	}
	vi CountMatching(){
		int maxMatch=min(n,m);
		vector<vi> dp(maxMatch+1,vi(1<<m,0));
		dp[0][0]=1;
		REP(i,n)
			for(int j=maxMatch-1;j>=0;j--)
				REP(vis,1<<m)
					for(auto to:graph[i])if(!((vis>>to)&1))
						add(dp[j+1][vis|(1<<to)],dp[j][vis]);
		vi ret(maxMatch+1,0);
		REP(i,maxMatch+1)
			REP(j,1<<m)
				add(ret[i],dp[i][j]);
		return ret;
	}
};

struct Solver{
	int n;
	vector<vi> graph;
	Solver(int _n):n(_n){
		graph.assign(n*2,vi());
	}
	void AddEdge(int a,int b){
		graph[a].PB(b+n);
		graph[b+n].PB(a);
	}
	void dfs(int v,vector<bool>& vis,vi& left,vi& right){
		if(vis[v])
			return;
		if(v<n)
			left.PB(v);
		else
			right.PB(v);
		vis[v]=true;
		for(auto to:graph[v])
			dfs(to,vis,left,right);
	}
	int CountPerfectMatching(){
		vector<bool> vis(n*2,false);
		vi cur(n+1,0),nx(n+1,0);
		cur[0]=1;
		REP(i,n)if(!vis[i]){
			vi left,right;
			dfs(i,vis,left,right);
			Wafrelka w(left.size(),right.size());
			REP(j,left.size())
				for(auto to:graph[left[j]])
					REP(k,right.size())if(to==right[k])
						w.AddEdge(j,k);
			vi t=w.CountMatching();
			fill(ALL(nx),0);
			REP(j,n+1)REP(k,t.size())if(j+k<n+1)
				add(nx[j+k],cur[j]*t[k]);
			swap(cur,nx);
		}
		int c=1,ret=0;
		for(int i=n;i>=0;i--){
			if(i&1)
				sub(ret,cur[i]*c);
			else
				add(ret,cur[i]*c);
			c=c*(n-i+1)%mod;
		}
		return ret;
	}
};

int main(){
	int n=read(),k=read();
	vector<pii> es;
	REP(i,k){
		int x=read(),y=read();
		es.PB(MP(x,y));
	}
	int ans=0;
	{
		vector<vector<bool>> c(n,vector<bool>(n,false));
		for(auto e:es)
			c[e.first][e.second]=true;
		Solver sv(n);
		REP(i,n)REP(j,n)if(c[i][j])
			sv.AddEdge(i,j);
		add(ans,sv.CountPerfectMatching());
	}
	{
		vector<vector<bool>> c(n,vector<bool>(n,false));
		for(auto e:es)
			c[e.first][e.second]=true;
		REP(i,n)
			c[i][i]=true;
		Solver sv(n);
		REP(i,n)REP(j,n)if(c[i][j])
			sv.AddEdge(i,j);
		sub(ans,sv.CountPerfectMatching());
	}
	{
		vector<vector<bool>> c(n,vector<bool>(n,false));
		for(auto e:es)
			c[e.first][e.second]=true;
		REP(i,n)
			c[i][n-1-i]=true;
		Solver sv(n);
		REP(i,n)REP(j,n)if(c[i][j])
			sv.AddEdge(i,j);
		sub(ans,sv.CountPerfectMatching());
	}
	{
		vector<vector<bool>> c(n,vector<bool>(n,false));
		for(auto e:es)
			c[e.first][e.second]=true;
		REP(i,n)
			c[i][i]=true;
		REP(i,n)
			c[i][n-1-i]=true;
		Solver sv(n);
		REP(i,n)REP(j,n)if(c[i][j])
			sv.AddEdge(i,j);
		add(ans,sv.CountPerfectMatching());
	}
	cout<<ans<<endl;
}

Measured memory_bytes: 23432