#include <algorithm>  
#include <iostream>  
#include <sstream>  
#include <string>  
#include <cstring>
#include <vector>  
#include <queue>  
#include <set>  
#include <map>  
#include <cstdio>  
#include <cstdlib>  
#include <cctype>  
#include <cmath>  
#include <list>  
#include <cassert>
#include <ctime>
#include <climits>
using namespace std;

#define PB push_back  
#define MP make_pair  
#define SZ(v) ((int)(v).size())  
#define FOR(i,a,b) for(int i=(a);i<(b);++i)  
#define REP(i,n) FOR(i,0,n)  
#define FORE(i,a,b) for(int i=(a);i<=(b);++i)  
#define REPE(i,n) FORE(i,0,n)  
#define FORSZ(i,a,v) FOR(i,a,SZ(v))  
#define REPSZ(i,v) REP(i,SZ(v))  
typedef long long ll;
typedef unsigned long long ull;
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a%b); }

const int MAXN=20;
const int MAXM=MAXN*(MAXN-1)/2;
const int MAXT=MAXN-1;
const int MOD=1000000007;
void inc(int &a,int b) { if((a+=b)>=MOD) a-=MOD; }

int n,m;
int e[MAXM][2];
vector<pair<int,int>> tadj[MAXN];

// mask indicates which tree-edges have values, a component is a maximal set of nodes connected by tree-edges without values
int nt;
int ways[1<<MAXT]; // ways[mask] = number of ways to give values to all edges connecting different components, assuming all tree-edges within a component get lower values
int sum[1<<MAXT]; // sum[mask] = sum of tree edges over all ways

int q[MAXN],qhead,qtail;
int cntnontree[1<<MAXT];
int prod[MAXM+1][MAXM+1];

int solve() {
	nt=n-1;
	REP(mask,1<<nt) cntnontree[mask]=0;
	FOR(i,nt,m) {
		qtail=qhead=0; vector<int> pathmask(n,-1);
		int s=e[i][0],t=e[i][1]; pathmask[s]=0,q[qhead++]=s;
		while(qtail<qhead) { int at=q[qtail++]; REPSZ(j,tadj[at]) { int to=tadj[at][j].first,id=tadj[at][j].second; if(pathmask[to]==-1) pathmask[to]=pathmask[at]|(1<<id),q[qhead++]=to; } }
		++cntnontree[(1<<nt)-1-pathmask[t]];
	}
	REP(j,nt) REP(mask,1<<nt) if((mask&(1<<j))!=0) cntnontree[mask-(1<<j)]+=cntnontree[mask];
	REP(mask,1<<nt) cntnontree[mask]=m-nt-cntnontree[mask];
	
	REPE(i,MAXM) { prod[i][i]=i; FORE(j,i+1,MAXM) prod[i][j]=(ll)prod[i][j-1]*j%MOD; }
	
	ways[0]=1,sum[0]=0;
	FOR(mask,1,1<<nt) {
		ways[mask]=0,sum[mask]=0;
		int treecnt=0; REP(i,nt) if((mask&(1<<i))!=0) ++treecnt;
		REP(i,nt) if(mask&(1<<i)) { // i is the tree edge in mask with the lowest value
			int nmask=mask^(1<<i),cways=ways[nmask],csum=sum[nmask];
			// we also need to assign the non-tree-edges that will be in different components
			int nontreecnt=cntnontree[nmask],deltanontreecnt=cntnontree[mask]-cntnontree[nmask];
			if(deltanontreecnt>=1) {
				csum=(ll)csum*prod[treecnt+nontreecnt+1][treecnt+nontreecnt+deltanontreecnt]%MOD;
				cways=(ll)cways*prod[treecnt+nontreecnt][treecnt+nontreecnt+deltanontreecnt-1]%MOD;
			}
			csum=(csum+(ll)cways*(1+treecnt-1))%MOD;
			inc(ways[mask],cways); inc(sum[mask],csum);
			//printf("%x %d-%d: %d %d (%d,%d,%d)\n",mask,e[i][0]+1,e[i][1]+1,cways,csum,treecnt,nontreecnt,deltanontreecnt);
		}
	}
	return sum[(1<<nt)-1];
}

void run() {
	scanf("%d%d",&n,&m);
	REP(i,m) { int a,b; scanf("%d%d",&a,&b); --a,--b; e[i][0]=a,e[i][1]=b; if(i<n-1) tadj[a].PB(MP(b,i)),tadj[b].PB(MP(a,i)); }
	printf("%d\n",solve());
}

void stress() {
	REP(rep,100) {
		n=MAXN,m=MAXM;
		REP(i,n-1) e[i][0]=0,e[i][1]=i+1;
		set<pair<int,int>> seen; FOR(i,n-1,m) while(true) { int a=rand()%(n-1)+1,b=rand()%(n-1)+1; if(a>b) swap(a,b); if(seen.count(MP(a,b))) continue; e[i][0]=a,e[i][1]=b; seen.insert(MP(a,b)); break; }
		REP(i,n) tadj[i].clear(); REP(i,n-1) { int a=e[i][0],b=e[i][1]; tadj[a].PB(MP(b,i)); tadj[b].PB(MP(a,i)); }
		int have=solve();
		printf(".");
	}
}

int main() {
	run();
	//stress();
	return 0;
}

Measured memory_bytes: 6528