Problem: John is playing a famous console game named 'Tales of Algorithmers.' Now he is facing the last dungeon called 'Blue Forest.' To find out the fastest path to run through the very complicated dungeon, he tried to draw up the dungeon map.

The dungeon consists of several floors. Each floor can be described as a connected simple plane graph. Vertices of the graph are identified by X-Y coordinate, and the length of an edge is calculated by Euclidean distance. A vertex may be equipped with a one-way warp gate. If John chooses to use the gate, it brings John to another vertex in a possibly different floor. The distance between a warp gate and its destination is considered as 0.

One vertex has at most one warp gate, though some vertices might be the destination of multiple warp gates.

He believed he made one map for each floor, however after drawing maps of all the floors, he noticed that he might have made a few mistakes. He might have drawn the same floor several times, and might have forgotten to mark some warp gates in the maps. However, he was sure he marked all warp gates at least once. So if the maps of same floor are unified to one map, all the warp gates must be described there. Luckily there are no floors which have the same shape as the other floors, so if two (or more) maps can be unified, they must be the maps of the same floor. Also, there is no floor which is circular symmetric (e.g. a regular triangle and a square).

Map A and map B can be unified if map B can be transformed to map A using only rotation and parallel translation. Since some of the warp gates on maps might be missing, you should not consider the existence of warp gates when checking unification. If it is possible to unify map A and map B, a vertex on map A and the corresponding vertex on map B are considered as 'identical' vertices. In other words, you should treat warp gates on map B as those on map A where the warp gates are located on the corresponding vertices on map A. Destinations of warp gates should be treated similarly. After that you can forget map B. It is guaranteed that if both map A and map B have warp gates which are on the identical vertices, the destinations of them are also identical.

Remember, your task is to find the shortest path from the entrance to the exit of the dungeon, using the unified maps.



Input

The input consists of multiple datasets. Each dataset is in the following format.

n
component1 component2 ...
componentn sl sn
dl dn


n is a positive integer indicating the number of maps. componenti describes the i-th map in the following format.

A
x1 y1
x2 y2
...
xA yA
B
s1 d1
s2 d2
...
sB dB
C sn1 dl1 dn1
sn2 dl2 dn2
...
snC dlC dnC


A denotes the number of vertices in the map. Each of the following A lines contains two integers xi and yi representing the coordinates of the i-th vertex in the 2-dimensional plane. B denotes the number of the edges connecting the vertices in the map. Each of the following B lines contains two integers representing the start and the end vertex of each edge. Vertices on the same map are numbered from 1.

C denotes the number of warp gates. Each of the following C lines has three integers describing a warp gate. The first integer is the vertex where the warp gate is located. The second and the third integer are the indices of the map and the vertex representing the destination of the warp gate, respectively. Similarly to vertices, maps are also numbered from 1.

After the description of all maps, two lines follow. The rst line contains two integers sl and dl , meaning that the entrance of the dungeon is located in the sl-th map, at the vertex dl. The last line has two integers sn and dn, similarly describing the location of the exit.

The values in each dataset satisfy the following conditions:

* 1 ≤ n ≤ 50,
* 3 ≤ A ≤ 20,
* A - 1 ≤ B ≤ A(A - 1)/2,
* 0 ≤ C ≤ A, and
* -10,000 ≤ xi, yi ≤ 10,000.

Output

For each dataset, print the distance of the shortest path from the entrance to the exit. The output should not contain an absolute error greater than 10-1. If there is no route, print -1.

Example

Input

2
5
0 0
10 0
20 0
30 0
30 10
4
1 2
2 3
3 4
4 5
2
1 2 4
3 2 2
5
-10 0
0 0
0 -10
0 -20
0 -30
4
1 2
2 3
3 4
4 5
1
4 1 3
1 1
2 1
4
3
4 3
0 0
5 0
2
1 2
2 3
0
3
0 0
3 4
0 5
2
1 2
1 3
1
2 3 4
4
0 13
0 0
13 0
13 13
4
1 2
1 4
2 3
2 4
0
4
5 12
0 0
-7 17
-12 5
4
1 2
2 3
2 4
4 3
0
1 1
4 1
4
3
0 0
2 0
0 4
2
1 2
1 3
0
3
0 0
-2 0
0 4
2
1 2
1 3
1
1 4 1
3
0 0
1 0
0 2
2
1 2
1 3
1
1 4 1
3
0 0
2 0
0 4
2
1 2
2 3
0
1 1
4 1
0


Output

10.0000000000
41.3847763109
-1.000000000

Solution (in CPP):

Solution:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <assert.h>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <set>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c) for (__typeof((c).begin())it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

#include <complex>
typedef complex<double> Point;
struct Line : public vector<Point> {
  Line() {;}
  Line(Point a, Point b) { push_back(a); push_back(b); }
};
namespace std {
  bool operator<(const Point &lhs, const Point &rhs) {
    if (round(lhs.real()) == round(rhs.real()) &&
        round(lhs.imag()) == round(rhs.imag())) { return false; }
    if (round(lhs.real()) != round(rhs.real())) { return lhs.real() < rhs.real(); }
    return lhs.imag() < rhs.imag();
  }
  bool operator<(const Line &lhs, const Line &rhs) {
    if (lhs[0] < rhs[0] || rhs[0] < lhs[0]) { return lhs[0] < rhs[0]; }
    return lhs[1] < rhs[1];
  }
};

typedef double Weight;
struct Edge {
  int src;
  int dest;
  Weight weight;
  Edge(int src, int dest, Weight weight) : src(src), dest(dest), weight(weight) {;}
  bool operator<(const Edge &rhs) const {
    if (weight != rhs.weight) { return weight > rhs.weight; }
    if (src != rhs.src) { return src < rhs.src; }
    return dest < rhs.dest;
  }
};
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;
typedef vector<Weight> Array;
typedef vector<Array> Matrix;

void PrintMatrix(const Matrix &matrix) {
  for (int y = 0; y < (int)matrix.size(); y++) {
    for (int x = 0; x < (int)matrix[y].size(); x++) {
      printf("%f ", matrix[y][x]);
    }
    puts("");
  }
}

Weight Dijkstra(const Graph &g, int s, int t) {
  const int n = g.size();
  vector<bool> visit(n, false);
  Array dist(n, 2000000000LL);
  priority_queue<Edge> que;
  que.push(Edge(s, s, 0));
  Weight ans = -1;
  dist[s] = 0;
  while (!que.empty()) {
    Edge edge = que.top();
    que.pop();
    int from = edge.dest;
    if (visit[from]) { continue; }
    visit[from] = true;
    if (from == t) {
      ans = edge.weight;
      break;
    }   
    for (int i = 0; i < (int)g[from].size(); i++) {
      int to = g[from][i].dest;
      Weight ncost = edge.weight + g[from][i].weight;
      if (visit[to] || ncost - dist[to] >= -EPS) { continue; }
      dist[to] = ncost;
      que.push(Edge(from, to, ncost));
    }   
  }
  return ans;
}

//============================================

int n, m;
int mapto[60][30];
vector<Point> ps[60];
map<Point, int> pmapto[60];
vector<Line> ls1[60];
set<Line> ls2[60];
vector<int> fs[60];
vector<int> ts[60];

vector<int> wfl;
vector<int> wfn;
vector<int> wtl;
vector<int> wtn;

void Merge(Graph &g, int from, int to) {
  REP(i, ls1[to].size()) {
    Point c = ls1[to][i][0];
    Point vect = ls1[to][i][0] - ls1[from][0][0];
    //cout << from << " " << to << " " << i << " " << vect << endl;
    vector<Line> ls = ls1[from];
    FORIT(it, ls) {
      REP(iter, 2) {
        (*it)[iter] += vect;
        //cout << (*it)[iter] << endl;
      }
    }
    //cout << ls1[to][i][1] << " " << ls[0][1] << endl;
    double angle = arg(ls1[to][i][1] - c) - arg(ls[0][1] - c);
    Point rot = Point(cos(angle), sin(angle));
    FORIT(it, ls) {
      REP(iter, 2) {
        (*it)[iter] = ((*it)[iter] - c) * rot + c;
      }
      if (!ls2[to].count(*it)) { goto next; }
    }
    REP(j, ps[from].size()) {
      Point p = (ps[from][j] + vect - c) * rot + c;
      assert(pmapto[to].count(p));
      int f = mapto[from][j];
      int t = pmapto[to][p];
      //int t = mapto[to][nj];
      g[f].push_back(Edge(f, t, 0));
      g[t].push_back(Edge(t, f, 0));
    }
    return;
next:;
  }
}

int main() {
  while (scanf("%d", &n), n) {
    MEMSET(mapto, 0xdf);
    REP(i, 60) {
      ps[i].clear();
      pmapto[i].clear();
      ls1[i].clear();
      ls2[i].clear();
      fs[i].clear();
      ts[i].clear();
    }
    wfl.clear();
    wfn.clear();
    wtl.clear();
    wtn.clear();
    m = 0;
    REP(i, n) {
      int k;
      scanf("%d", &k);
      REP(j, k) {
        int x, y;
        scanf("%d %d", &x, &y);
        Point p = Point(x, y);
        ps[i].push_back(p);
        mapto[i][j] = m;
        pmapto[i][p] = m;
        m++;
      }
      scanf("%d", &k);
      REP(j, k) {
        int f, t;
        scanf("%d %d", &f, &t);
        f--; t--;
        fs[i].push_back(f);
        ts[i].push_back(t);
      }
      scanf("%d", &k);
      REP(j, k) {
        int f1 = i;
        int f2, t1, t2;
        scanf("%d %d %d", &f2, &t1, &t2);
        f2--; t1--; t2--;
        wfl.push_back(f1);
        wfn.push_back(f2);
        wtl.push_back(t1);
        wtn.push_back(t2);
      }
    }
    Graph g(m);
    REP(i, n) {
      REP(j, fs[i].size()) {
        int f = mapto[i][fs[i][j]];
        int t = mapto[i][ts[i][j]];
        double d = abs(ps[i][fs[i][j]] - ps[i][ts[i][j]]);
        g[f].push_back(Edge(f, t, d));
        g[t].push_back(Edge(t, f, d));
        Line l1 = Line(ps[i][fs[i][j]], ps[i][ts[i][j]]);
        Line l2 = Line(ps[i][ts[i][j]], ps[i][fs[i][j]]);
        ls1[i].push_back(l1);
        ls1[i].push_back(l2);
        ls2[i].insert(l1);
        ls2[i].insert(l2);
      }
    }
    REP(i, wfl.size()) {
      int f = mapto[wfl[i]][wfn[i]];
      int t = mapto[wtl[i]][wtn[i]];
      g[f].push_back(Edge(f, t, 0.0));
    }
    REP(i, n) {
      REP(j, i) {
        Merge(g, i, j);
      }
    }
    int sl, sn, dl, dn;
    scanf("%d %d %d %d", &sl, &sn, &dl, &dn);
    sl--; sn--; dl--; dn--;
    double ans = Dijkstra(g, mapto[sl][sn], mapto[dl][dn]);
    printf("%.8f\n", ans);
  }
}