#include <bits/stdc++.h>

using namespace std;

#define rep(i,x) for(int i=0;i<x;++i)
#define rrep(i,x) for(int i=x-1;i>=0;--i)
#define rep1(i,x) for(int i=1;i<=x;++i)
#define PB push_back
#define PPB pop_back
#define fst first
#define scd second

using vi = vector<int>;
using vvi = vector<vi>;
using pii = pair<int, int>;
using vpii = vector<pii>;

struct edge {int to, cost;};
using Graph = vector<edge>;

const int inf = 1e9;

struct UF {
	vi data;
	UF(int n) {
		data.resize(n, -1);
	}
	int root(int i) {
		return data[i] < 0 ? i : data[i] = root(data[i]);
	}
	int size(int x) {
		x = root(x);
		return -data[x];
	}
	void unite(int x, int y) {
		x = root(x), y = root(y);
		if (x == y) return;
		if (size(x) < size(y)) swap(x, y);
		data[x] += data[y];
		data[y] = x;
	}
	bool same(int x, int y) {
		x = root(x), y = root(y);
		return x == y;
	}
};

Graph G[100010];
int d[100010];
int N, M, K, Q;
int F[100010];

// LCA??¨
constexpr int max_log_n = log2(100010);
vi tr[100010];
int parent[100010][max_log_n + 5];
int minimum[100010][max_log_n + 5];
int depth[100010];

void lca_dfs(int cur = 0, int par = -1, int dep = 0)
{
	parent[cur][0] = par;
	minimum[cur][0] = min(d[cur], par == -1 ? inf : d[par]);
	depth[cur] = dep;

	for (int nx : tr[cur]) {
		if (nx == par) continue;
		lca_dfs(nx, cur, dep + 1);
	}
}

void lca_init()
{
	lca_dfs();

	rep(i, max_log_n) {
		rep(j, N) {
			if (~parent[j][i]) {
				parent[j][i + 1] = parent[parent[j][i]][i];
				minimum[j][i + 1] = min(minimum[j][i], minimum[parent[j][i]][i]);
			} else {
				parent[j][i + 1] = -1;
				minimum[j][i + 1] = inf;
			}
		}
	}
}

int lca(int u, int v)
{
	if (depth[u] > depth[v]) swap(u, v);

	int diff = depth[v] - depth[u];

    int res = min(d[u], d[v]);

	rep(i, max_log_n + 1) {
		if (diff >> i & 1) {
            res = min(res, minimum[v][i]);
            v = parent[v][i];
        }
	}

	if (u == v) return min(res, d[u]);

	rrep(i, max_log_n + 1) {
		if (parent[u][i] != parent[v][i]) {
            res = min(res, minimum[v][i]);
            res = min(res, minimum[u][i]);
			u = parent[u][i];
			v = parent[v][i];
		}
	}

	return min(res, minimum[u][0]);
}

void dijkstra()
{
	priority_queue<pii, vpii, greater<pii>> q;
	rep(i, K) {
		d[F[i]] = 0;
		q.push(pii(0, F[i]));
	}
	while (q.size()) {
		pii p = q.top(); q.pop();
		int v = p.scd;
		if (d[v] < p.fst) continue;
		for (edge &e : G[v]) {
			if (d[e.to] > d[v] + e.cost) {
				d[e.to] = d[v] + e.cost;
				q.push(pii(d[e.to], e.to));
			}
		}
	}
}

void build_tree()
{
	using EdgeInfo = pair<int, pii>;
	vector<EdgeInfo> E;

	rep(i, N) {
		for (edge& e : G[i]) {
			E.PB(EdgeInfo{min(d[i], d[e.to]), pii(i, e.to)});
		}
	}

	sort(begin(E), end(E), greater<EdgeInfo>());

	UF uf(N);

	int n = E.size();
	rep(i, n) {
		int from = E[i].scd.fst, to = E[i].scd.scd;
		
		if (uf.same(from, to)) continue;
		uf.unite(from, to);

		tr[from].PB(to);
		tr[to].PB(from);
	}
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);

	cin >> N >> M >> K >> Q;

	rep(i, M) {
		int a, b, l; cin >> a >> b >> l;
		--a, --b;

		G[a].PB(edge{b, l});
		G[b].PB(edge{a, l});
	}

	rep(i, K) {
		cin >> F[i];
		--F[i];
	}

	fill_n(d, N + 1, inf);
	dijkstra();

	build_tree();

	lca_init();

	rep(i, Q) {
		int s, t; cin >> s >> t;
		--s, --t;
		cout << lca(s, t) << endl;
	}
}

Measured memory_bytes: 34552