Problem: Kotoko, a housewife, was enthusiastic about keeping food costs down during this recession. Be sure to check the newspaper advertisement every morning. Make a good list of what to buy and the cheapest-selling shops, and go shopping by riding a bicycle in a combat style called apron sandals while walking through the shops.

So, as a husband, you decided to create a housekeeping book program with your favorite programming in order to help Kotoko even a little. The program inputs the name and price (yen) of the items sold to each supermarket, the items that Kotoko needs, and outputs the minimum amount to collect all the items.

Kotoko has to leave the house, collect the necessary items, and return home. Therefore, you who care about Kotoko decided to add a function to report the distance of the route with the shorter distance, considering that there are multiple shopping routes with the same minimum amount. Therefore, the program also inputs information on the road connecting the supermarket and the house.

Let the number of supers be n, and each super is assigned a number from 1 to n. Furthermore, Kotoko's house is number 0. Road information is given by these number pairs and their distances (integers).



Input

Multiple datasets are given as input. The format of each dataset is as follows:

n (number of supermarkets: integer)
k1 name1 value1 name2 value2 ... namek1 valuek1 (number of item types in the first supermarket, first item name and price, second item name and price ,,,: integer and string blanks Separation)
k2 name1 value1 name2 value2 ... namek2 valuek2 (number of item types in the second supermarket, first item name and price, second item name and price ,,,: integer and string blanks Separation)
..
..
kn name1 value1 name2 value2 ... namekn valuekn (number of item types in the nth supermarket, first item name and price, second item name and price ,,,: integer and string blanks Separation)
q (Number of items required: Integer)
name1 (Name of the first required item: string)
name2 (name of the second required item: string)
..
..
nameq (name of the qth required item: string)
m (number of roads: integer)
s1 t1 d1 (Information on the first road: Blank-separated integers)
s2 t2 d2 (Second road information: space-separated integer)
..
..
sm tm dm (mth road information: blank-separated integer)


si ti di indicates that the sith supermarket (or house) and the tith supermarket (or house) can move back and forth in both directions, and the distance is di.

You will be given a way to get to all the supermarkets from your house (via the supermarket).

n is less than or equal to 10 and q is less than or equal to 15. ki is 100 or less, the string of the item name does not exceed 20 characters, and the price of the item does not exceed 10000. Also, the length of the road does not exceed 1000.

When n is 0, it is the end of input.

Output

For each dataset, separate the minimum amount and distance with a single space and output on one line. However, if you cannot collect all the necessary items, output "impossible".

Example

Input

3
3 apple 100 banana 200 egg 300
3 apple 150 banana 100 cola 200
3 apple 100 banana 150 cola 200
3
apple
banana
cola
5
0 2 4
0 1 3
0 3 3
1 2 3
2 3 5
3
3 apple 100 banana 200 egg 300
3 apple 150 banana 100 cola 200
3 apple 100 banana 150 cola 200
4
apple
banana
cola
jump
5
0 2 4
0 1 3
0 3 3
1 2 3
2 3 5
0


Output

400 10
impossible

Solution (in CPP):

Solution:
#include <stdio.h>
#include <iostream>
#include <vector>
#include <list>
#include <cmath>
#include <fstream>
#include <algorithm>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <complex>
#include <iterator>
#include <cstdlib>
#include <sstream>
#include <climits>

using namespace std;

#define EPS (1e-10)
#define EQ(a,b) (abs((a) - (b)) < EPS)
#define EQV(a,b) (EQ((a).real(),(b).real()) && EQ((a).imag(),(b).imag()))

typedef long long ll;

const int MAX_SIZE = 10000;

struct edge{
	int to;
	int cost;
};

class Situation{
public:
    int sumCost;
    int sit;
    int sumDist;
    int node;

	Situation(int sumCost_,int node_,int sit_,int sumDist_){
        sumCost=sumCost_;
        node=node_;
        sit=sit_;
        sumDist=sumDist_;
	}
	Situation();
    // Å¬ïpÔÉ\[g
	bool operator<(const Situation &s)const{
        return s.sumDist < this->sumDist;
	}
};

//typedef pair<int,int> P;
int V;
const int MAX_V = 15;
vector<edge> G[MAX_V];
int d[MAX_V][1<<15];
int minDist[MAX_V][1<<15];

const int INF = 1000000000;
int n;int idx;
int q;

string obj[20];
map<string,int> sellInfo[20];
map<string,int> dict;

void dijkstra2(int s){
	priority_queue<Situation> que;
    for(int i = 0; i < MAX_V; i++){
        fill(d[i],d[i]+(1<<15),INF);
        fill(minDist[i],minDist[i]+(1<<15),INF);
    }
    d[s][(1<<q)-1] = 0;
    minDist[s][(1<<q)-1]=0;
	que.push(Situation(0,s,(1<<q)-1,0));
	while(!que.empty()){
		Situation p = que.top();
		que.pop();
        int v = p.node;
        int sit=p.sit;
        if(d[v][sit] < p.sumCost)
			continue;
        if(d[v][sit]==p.sumCost&&minDist[v][sit]<p.sumDist){
            continue;
        }
        // Ü¾ÁÄ¢È¢¤iðæèÉs­
        for(map<string,int>::iterator it=sellInfo[v].begin();it!=sellInfo[v].end();it++){
            string name=it->first;
            int value=it->second;
            // ÖWÈ¢¤i
            if(dict.find(name)==dict.end())
                continue;
            // idðmÛ
            int id=dict[name];
            // rbgªÜ¾§ÁÄ¢éÈçÎA§ÄÄL[ÉÇÁ
            if((sit>>id)&1){
                int nsit=sit;
                nsit&=~(1<<id);
                int ncost=p.sumCost+value;
                // Å¬RXgðÇÁÅ«éÈçÎ
                if(d[v][nsit]>d[v][sit]+value){
                    // XV
                    d[v][nsit]=d[v][sit]+value;
                    que.push(Situation(ncost,v,nsit,p.sumDist));
                    minDist[v][nsit]=p.sumDist;
                }
                else if(d[v][nsit]==d[v][sit]+value){
                    if(minDist[v][nsit] > minDist[v][sit]){
                        minDist[v][nsit] = minDist[v][sit];
                    }
                }
            }
        }
		for(int j = 0; j < G[v].size(); j++){
            edge e = G[v][j];
            // àzªXVÅ«éÈçXV
            if(d[e.to][sit]>d[v][sit]){
                // XV
                d[e.to][sit]=d[v][sit];
                minDist[e.to][sit]=p.sumDist+e.cost;
                que.push(Situation(p.sumCost,e.to,sit,minDist[e.to][sit]));
            }
            // Ú®æÌRXgª¯¶ê
            else if(d[e.to][sit]==d[v][sit]){
                // Å¬RXgðXVÅ«éÈçAÚ®
                if(minDist[e.to][sit] > minDist[v][sit] + e.cost){
                    minDist[e.to][sit] = minDist[v][sit] + e.cost;
                    que.push(Situation(p.sumCost,e.to,sit,minDist[e.to][sit]));
                }
            }
        }
    }
}

int main(){
    while(cin>>n&&n!=0){
        idx=0;
        dict.clear();
        for(int i = 0; i <= n; i++){
            G[i].clear();
            sellInfo[i].clear();
        }
        for(int i = 0; i < 20; i++)
            obj[i].clear();
        for(int i = 0; i < n; i++){
            int k;
            scanf("%d",&k);
            for(int j = 0; j < k; j++){
                string name;
                int value;
                cin>>name;
                scanf("%d",&value);
                sellInfo[i+1][name]=value;
            }
        }
        cin>>q;
        for(int i = 0; i < q; i++){
            string name;
            cin>>name;
            obj[i]=name;
            dict[name]=i;
        }
        int m;
        scanf("%d",&m);
        V=n;
        for(int i = 0; i < m; i++){
            int s,t,d;
            scanf("%d %d %d",&s,&t,&d);
            edge e;
            e.to=t;e.cost=d;
            G[s].push_back(e);
            e.to=s;
            G[t].push_back(e);
        }
        dijkstra2(0);
        int minv=d[0][0];
        int mind=minDist[0][0];
        if(minv==INF)
            printf("impossible\n");
        else
            printf("%d %d\n",minv,mind);
    }

    return 0;
}