#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline", "fast-math", "unroll-loops", "no-stack-protector")
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-funsafe-loop-optimizations"
#include<cstdio>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<cstring>
#define ll long long
using namespace std;
namespace io {
	const int SIZE = (1 << 21) + 1;
	char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55];
	int f, qr;
#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
	inline void flush () {
		fwrite (obuf, 1, oS - obuf, stdout);
		oS = obuf;
	}
	inline void putc (char x) {
		*oS ++ = x;
		if (oS == oT) flush ();
	}
	template<class T>
	inline void getc(T &x)
	{
		for(c=gc();!((c>='a'&&c<='z')||(c>='A'&&c<='Z'));c=gc());
		x=c;
	}
	template <class I>
	inline void rd (I &x) {
		for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
		for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15);
		x *= f;
	}
	template <class I>
	inline void print (I x) {
		if (!x) putc ('0');
		if (x < 0) putc ('-'), x = -x;
		while (x) qu[++ qr] = x % 10 + '0',  x /= 10;
		while (qr) putc (qu[qr --]);
	}
	struct Flusher_ {
		~Flusher_() {
			flush();
		}
	} io_flusher_;
}
using io :: rd;
using io :: putc;
using io :: print;
using io :: getc;

const int MOD=1e9+7;
int mo(int x,int y)
{
	return x+y>=MOD?x+y-MOD:x+y;
}
int mu(int x,int y)
{
	return (ll)x*y%MOD;
}
int sub(int x,int y)
{
	return x<y?x-y+MOD:x-y;
}
int ksm(int x,int y)
{
	int res=1;
	for(;y;y>>=1,x=mu(x,x))
	if(y&1) res=mu(res,x);
	return res;
}
const int MAXN=200+5;
pair<int,int>e[MAXN];
vector<int>g[MAXN];
int dp[2][(1<<20)|1],n,m;
int sum[2][(1<<20)|1],SL[MAXN];
int els[(1<<20)|1],bin[(1<<20)|1],dep[MAXN],fa[MAXN],id[(1<<20)|1];
void dfs(int x,int ff)
{
	dep[x]=dep[ff]+1;fa[x]=ff;
	for(int i=0;i<g[x].size();i++)
	{
		int v=g[x][i];
		if(v==ff) continue;
		dfs(v,x);
	}
}
/*
int jc[MAXN],jcn[MAXN];
int C(int n,int m)
{
	return (n<m)?0:mu(jc[n],mu(jcn[m],jcn[n-m]));
}
*/
int ADD(int x,int y)
{
	return x<=0?0:(ll)x*y%MOD;
}
int main()
{
//	freopen("B.in","r",stdin);
//	freopen("B.out","w",stdout);
	rd(n);rd(m);
	for(int i=1,x,y;i<=m;i++)
	{
		rd(x);rd(y);
		e[i]=make_pair(x,y);
		if(i<=n-1)
		{
			g[x].push_back(y);
			g[y].push_back(x);
		}
		
	}
	dfs(1,0);
	for(int i=n,x,y;i<=m;i++)
	{
			x=e[i].first,y=e[i].second;
			while(x!=y)
			{
				if(dep[x]>dep[y])
				{
					SL[i]|=(1<<x-1);
					x=fa[x];
				}
				else
				{	
					SL[i]|=(1<<y-1);
					y=fa[y];
				}
			}
	}
	int es=n-1;
	for(int S=1;S<(1<<es);S++)
		bin[S]=bin[S-(S&(-S))]+1;
	for(int i=1;i<=es;i++)
	id[(1<<(i-1))]=i;
	for(int S=0;S<(1<<es);S++)
	{
		int nowS=0;
		for(int j,i=S,x,y;i;i-=i&(-i))
		{
			j=id[i&(-i)];
			x=e[j].first;y=e[j].second;
			nowS|=(dep[x]<dep[y])?(1<<y-1):(1<<x-1);
		}
		for (int i=n;i<=m;i++)
		 els[S]+=((SL[i]&nowS)==SL[i]);
	//	if(cnt) fprintf(stderr,"%d %d\n",S,els[S]);
	}
/*	for(int i=jc[0]=1;i<=m;i++) jc[i]=mu(jc[i-1],i);
	jcn[m]=ksm(jc[m],MOD-2);
	for(int i=m;i;i--)
	jcn[i-1]=mu(jcn[i],i);
	*/
	dp[0][0]=1;int cur=0,nxt=1;
	for(int i=1;i<=m;i++)
	{
		for(register int S=0;S<(1<<es);++S)
		if(dp[cur][S]||sum[cur][S])
		{
				dp[nxt][S]=mo(dp[nxt][S],ADD(els[S]-(i-1-bin[S]),dp[cur][S]));
				sum[nxt][S]=mo(sum[nxt][S],ADD(els[S]-(i-1-bin[S]),sum[cur][S]));
				
			for(register int  j=(1<<es)-1-S;j;j^=j&(-j))
			{
				int t=id[j&(-j)];
				dp[nxt][S|(1<<(t-1))]=mo(dp[nxt][S|(1<<(t-1))],dp[cur][S]);
				sum[nxt][S|(1<<(t-1))]=(1ll*dp[cur][S]*i+sum[nxt][S|(1<<(t-1))]+sum[cur][S])%MOD;
			}
			dp[cur][S]=sum[cur][S]=0;
		}
		cur^=1;nxt^=1;
	}
	print(sum[cur][(1<<es)-1]);
	putc('\n');
				
	return 0;	
}