#include<iostream>
#include<vector>
#include<queue>
#include<tuple>
#include<functional>
#include<map>
#include<set>
using namespace std;

enum Direction {NORTH, EAST, SOUTH, WEST};
int dy[4] = {-1, 0, 1, 0};
int dx[4] = {0, 1, 0, -1};
enum {RED, BLUE};

class Point {
    int y_value, x_value;
public:
    Point() {}
    Point(int y, int x) :y_value(y), x_value(x) {
    }
    explicit Point(const string& s) {
        y_value = s[0] - 'a';
        x_value = 0;
        for(const auto& c: s.substr(2)) x_value = x_value * 10 + c - '0';
        --x_value;
    }
    int x() const {return x_value;}
    int y() const {return y_value;}
    bool operator<(const Point& p) const {return y() != p.y() ? y() < p.y() : x() < p.x();}
    bool operator>(const Point& p) const {return y() != p.y() ? y() > p.y() : x() > p.x();}
    bool operator==(const Point& p) const {return y() == p.y() && x() == p.x();}
};

class Vertex {
    Point point_value;
    int direction_value;
    int minute_value;
public:
    Vertex(const Point& p, int d, int m) :point_value(p), direction_value(d), minute_value(m) {}
    const Point point() const {return point_value;}
    int y() const {return point_value.y();}
    int x() const {return point_value.x();}
    int direction() const {return direction_value;}
    int minute() const {return minute_value;}
    void minute(int m) {minute_value = m;}
    bool operator<(const Vertex& v) const {
        if(minute() != v.minute()) return minute() < v.minute();
        if(direction() != v.direction()) return direction() < v.direction();
        return point() < v.point();
    }
    bool operator>(const Vertex& v) const {
        if(minute() != v.minute()) return minute() > v.minute();
        if(direction() != v.direction()) return direction() > v.direction();
        return point() > v.point();
    }
};

typedef tuple<Point, Point> Edge;

int M, N, D;
map<Point, int> signal;
set<Edge> construction;
map<Edge, int> jam;

int Dijkstra(const Point& start, const Point& goal) {
    set<Vertex> visited;
    priority_queue<Vertex, vector<Vertex>, greater<Vertex>> q;
    q.push(Vertex(start, EAST, 0));
    while(!q.empty()) {
        Vertex current = q.top();
        q.pop();
        if(current.point() == goal) return current.minute();
        if(visited.count(current)) continue;
        visited.insert(current);
        for(int d = 0; d < 4; ++d) {
            if(current.direction() == (d + 2) % 4) continue;
            Vertex next(Point(current.y() + dy[d], current.x() + dx[d]), d, current.minute());
            if(next.y() < 0 || M <= next.y() || next.x() < 0 || N <= next.x()) continue;
            Edge edge(Point(current.point()), Point(next.point()));
            if(construction.count(edge)) continue;
            int add = D;
            if(jam.count(edge)) add += jam[edge];
            next.minute(current.minute() + add);
            if(signal.count(next.point())) {
                int we = (next.minute() / signal[next.point()]) & 1;
                if((next.direction() == NORTH || next.direction() == SOUTH) && we == BLUE) continue;
                if((next.direction() == EAST || next.direction() == WEST) && we == RED) continue;
            }
            q.push(next);
        }
    }
    return -1;
}

int main() {
    while(cin >> M >> N, M | N) {
        int ns, nc, nj, k, d;
        string p, p1, p2;
        cin >> D;
        signal.clear();
        for(cin >> ns; ns > 0; --ns) {
            cin >> p >> k;
            signal[Point(p)] = k;
        }
        construction.clear();
        for(cin >> nc; nc > 0; --nc) {
            cin >> p1 >> p2;
            construction.insert(Edge(Point(p1), Point(p2)));
            construction.insert(Edge(Point(p2), Point(p1)));
        }
        jam.clear();
        for(cin >> nj; nj > 0; --nj) {
            cin >> p1 >> p2 >> d;
            jam[Edge(Point(p1), Point(p2))] = jam[Edge(Point(p2), Point(p1))] = d;
        }
        cin >> p1 >> p2;
        Point start(p1), goal(p2);

        cout << Dijkstra(start, goal) << endl;
    }
}

Measured memory_bytes: 5112