#include <iostream>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
using namespace std;


#define REP(i, s) for (int i = 0; i < s; ++i)
#define ALL(v) (v.begin(), v.end())
#define COUT(x) cout << #x << " = " << (x) << " (L" << __LINE__ << ")" << endl
#define EACH(i, s) for (__typeof__((s).begin()) i = (s).begin(); i != (s).end(); ++i)

template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
template<class T1, class T2> ostream& operator << (ostream &s, pair<T1,T2> P)
{ return s << '<' << P.first << ", " << P.second << '>'; }
template<class T> ostream& operator << (ostream &s, vector<T> P)
{ for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; }
template<class T> ostream& operator << (ostream &s, vector<vector<T> > P)
{ for (int i = 0; i < P.size(); ++i) { s << endl << P[i]; } return s << endl; }



struct UnionFind {
    vector<int> par, rank, sz;
    
    UnionFind(int n) : par(n), rank(n, 0), sz(n, 1) {
        for (int i = 0; i < n; ++i) par[i] = i;
    }
    void init(int n) {
        par.resize(n); rank.resize(n); sz.resize(n);
        for (int i = 0; i < n; ++i) par[i] = i, rank[i] = 0, sz[i] = 1;
    }
    
    int root(int x) {
        if (par[x] == x) return x;
        else return par[x] = root(par[x]);
    }
    
    bool issame(int x, int y) {
        return root(x) == root(y);
    }
    
    int size(int x) {
        return sz[root(x)];
    }
    
    bool merge(int x, int y) {
        x = root(x); y = root(y);
        if (x == y) return false;
        if (rank[x] < rank[y]) swap(x, y);
        if (rank[x] == rank[y]) ++rank[x];
        par[y] = x;
        sz[x] += sz[y];
        return true;
    }
};

typedef pair<int, int> Edge; // to, cost
typedef pair<int, int> pint;
const int INF = 1<<29;
vector<pint> edges;
vector<int> xs, ys;
vector<int> dist;

inline int calc(pint p) {
    return min(dist[p.first], dist[p.second]);
}

inline bool cmp(pint p, pint q) {
    return calc(p) > calc(q);
}

int main() {
    int N, M, K, Q; cin >> N >> M >> K >> Q;
    vector<vector<Edge> > G(N);
    for (int i = 0; i < M; ++i) {
        int x, y, w; cin >> x >> y >> w; --x, --y;
        G[x].push_back(Edge(y, w));
        G[y].push_back(Edge(x, w));
        edges.push_back(pint(x, y));
    }
    
    // Dijkstra
    priority_queue<pair<int,int>, vector<pair<int,int> >, greater<pair<int,int> > > que;
    dist.assign(N, INF);
    for (int k = 0; k < K; ++k) {
        int fes; cin >> fes; --fes;
        dist[fes] = 0;
        que.push(pair<int,int>(0, fes));
    }
    while (!que.empty()) {
        auto p = que.top(); que.pop();
        int v = p.second;
        if (dist[v] < p.first) continue;
        for (auto e : G[v]) {
            if (dist[e.first] > dist[v] + e.second) {
                dist[e.first] = dist[v] + e.second;
                que.push(make_pair(dist[e.first], e.first));
            }
        }
    }
    
    // queries
    xs.resize(Q); ys.resize(Q);
    for (int q = 0; q < Q; ++q) {
        cin >> xs[q] >> ys[q];
        --xs[q], --ys[q];
    }
    
    
    // parallel binary search
    sort(edges.begin(), edges.end(), cmp);
    
    //COUT(dist);
    //COUT(edges);

    vector<int> left(Q, 0), right(Q, INF);
    UnionFind uf(N);
    while (true) {
        map<int, vector<int> > distToQueries;
        bool update = false;
        for (int q = 0; q < Q; ++q) {
            if (right[q] - left[q] > 1) {
                update = true;
                int mid = (left[q] + right[q]) / 2;
                distToQueries[-mid].push_back(q);
            }
        }
        if (!update) break;
        uf.init(N);
        int iter = 0;
        for (auto it = distToQueries.begin(); it != distToQueries.end(); ++it) {
            int mid = -(it->first);
            while (calc(edges[iter]) >= mid) {
                int u = edges[iter].first;
                int v = edges[iter].second;
                uf.merge(u, v);
                ++iter;
            }
            for (auto q : it->second) {
                if (!uf.issame(xs[q], ys[q])) right[q] = mid;
                else left[q] = mid;
            }
        }
    }
    for (int q = 0; q < Q; ++q) cout << left[q] << endl;
}






















Measured memory_bytes: 17312