#include<string>
#include<vector>
#include<cstring>
#include<iostream>

#define rep(i,n) for(int i=0;i<(n);i++)

using namespace std;

const int M=1000000007;

struct edge{
	int u,v,id;
	string s;
};

int n1,n2;
edge E1[600],E2[600];
vector<int> adj1[500],adj2[500];

int dp[600][600][6];
int dfs(int i1,int i2,int p1,int p2){
	int dummy,&res=(p1==0?dp[i1][i2][p2]:dummy);
	if(p1==0 && ~res) return res;

	// 2 ÂÌ|C^ª¯É DAG ÌI[É½
	if(p1==E1[i1].s.length() && p2==E2[i2].s.length()){
		int v1=E1[i1].v,v2=E2[i2].v;
		if(v1==n1-1 && v2==n2-1) return res=1;
	}

	// |C^ 1 ª¶ñI[É½
	if(p1==E1[i1].s.length()){
		int v=E1[i1].v,cnt=0;
		rep(k,adj1[v].size()) cnt=(cnt+dfs(adj1[v][k],i2,0,p2))%M;
		return res=cnt;
	}

	// |C^ 2 ª¶ñI[É½
	if(p2==E2[i2].s.length()){
		int v=E2[i2].v,cnt=0;
		rep(k,adj2[v].size()) cnt=(cnt+dfs(i1,adj2[v][k],p1,0))%M;
		return res=cnt;
	}

	// wµÄ¢é¶ªá¤ÈçTõÅ¿Øè
	if(E1[i1].s[p1]!=E2[i2].s[p2]) return res=0;

	return res=dfs(i1,i2,p1+1,p2+1);
}

int main(){
	int T; cin>>T;
	while(T--){
		memset(dp,-1,sizeof dp);
		int m1; cin>>n1>>m1;
		rep(u,n1) adj1[u].clear();
		rep(j,m1){
			int u,v;
			string s; cin>>u>>v>>s;
			adj1[u].push_back(j);
			E1[j]=(edge){u,v,j,s};
		}
		int m2; cin>>n2>>m2;
		rep(u,n2) adj2[u].clear();
		rep(j,m2){
			int u,v;
			string s; cin>>u>>v>>s;
			adj2[u].push_back(j);
			E2[j]=(edge){u,v,j,s};
		}

		int ans=0;
		rep(i,adj1[0].size()) rep(j,adj2[0].size()) {
			ans=(ans+dfs(adj1[0][i],adj2[0][j],0,0))%M;
		}
		printf("%d\n",ans);
	}

	return 0;
}