#include <cstdio>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <algorithm>
#include <climits>

#define MAX_N (100000)
#define LOG_N (17)

using namespace std;

struct Edge {
	int from, to, cost;
	Edge(int from = -1, int to = -1, int cost = -1) : from(from), to(to), cost(cost){}
};

bool operator < (const Edge &a, const Edge &b)
{
	return (a.cost < b.cost);
}

bool operator > (const Edge &a, const Edge &b)
{
	return (b < a);
}

vector<Edge> G[MAX_N], G2[MAX_N], mem;

struct UnionFind {
	int N;
	int par[MAX_N];
	
	UnionFind(int N) : N(N){}
	
	void init(){
		for (int i = 0; i < N; i++) par[i] = i;
	}
	
	int find(int x){
		if (x == par[x]) return (x);
		return (par[x] = find(par[x]));
	}
	
	void merge(int x, int y){
		x = find(x); y = find(y);
		
		if (x == y) return;
		if (rand() & 1) par[x] = y;
		else par[y] = x;
	}
	
	bool same(int x, int y)
	{
		return (find(x) == find(y));
	}
	
};

int N, M, K, Q;
int dist[MAX_N];
int X[MAX_N];

void dijkstra()
{
	priority_queue<Edge, vector<Edge>, greater<Edge> > pq;
	
	for (int i = 0; i < K; i++) pq.push(Edge(-1, X[i], 0));
	
	for (; pq.size(); pq.pop()){
		Edge x = pq.top();
		
		if (x.cost > dist[x.to]) continue;
		dist[x.to] = x.cost;
		
		for (int i = 0; i < G[x.to].size(); i++){
			Edge e = G[x.to][i];
			pq.push(Edge(-1, e.to, x.cost + e.cost));
		}
	}
}

int depth[MAX_N];
int par[LOG_N][MAX_N];
int minCost[LOG_N][MAX_N];

void dfs(int v, int p, int d)
{
	par[0][v] = p;
	minCost[0][v] = min(dist[v], ~p ? dist[p] : INT_MAX);
	depth[v] = d;
	
	for (int i = 0; i < G2[v].size(); i++){
		if (G2[v][i].to != p){
			dfs(G2[v][i].to, v, d + 1);
		}
	}
}

void initTree(int root)
{
	memset(par, -1, sizeof(par));
	
	dfs(root, -1, 0);
	
	for (int i = 1; i < LOG_N; i++){
		for (int j = 0; j < N; j++){
			if (~par[i - 1][j]){
				par[i][j] = par[i - 1][par[i - 1][j]];
				minCost[i][j] = min(minCost[i - 1][j], minCost[i - 1][par[i - 1][j]]);
			}
		}
	}
}

int howFar(int u, int v)
{
	int res = min(dist[u], dist[v]);
	if (depth[u] > depth[v]) swap(u, v);
	
	for (int i = LOG_N - 1; i >= 0; i--){
		if ((depth[v] - depth[u]) >> i & 1){
			res = min(res, minCost[i][v]);
			v = par[i][v];
		}
	}
	
	if (u == v) return (res);
	
	for (int i = LOG_N - 1; i >= 0; i--){
		if (par[i][u] != par[i][v]){
			res = min(res, min(minCost[i][u], minCost[i][v]));
			u = par[i][u]; v = par[i][v];
		}
	}
	res = min(res, minCost[0][u]);
	return (res);
}

int main()
{
	scanf("%d %d %d %d", &N, &M, &K, &Q);
	
	for (int i = 0; i < M; i++){
		int from, to, cost;
		scanf("%d %d %d", &from, &to, &cost);
		G[from - 1].push_back(Edge(-1, to - 1, cost));
		G[to - 1].push_back(Edge(-1, from - 1, cost));
	}
	
	fill(dist, dist + N, INT_MAX);
	
	for (int i = 0; i < K; i++){
		scanf("%d", X + i);	
		X[i]--;
	}
	dijkstra();
	
	for (int i = 0; i < N; i++){
		for (int j = 0; j < G[i].size(); j++){
			mem.push_back(Edge(i, G[i][j].to, min(dist[i], dist[G[i][j].to])));
		}
	}
	
	UnionFind check(N);
	check.init();
	
	sort(mem.rbegin(), mem.rend());
	
	for (int i = 0; i < mem.size(); i++){
		Edge e = mem[i];
		if (!check.same(e.from, e.to)){
			check.merge(e.from, e.to);
			G2[e.from].push_back(Edge(-1, e.to, e.cost));
			G2[e.to].push_back(Edge(-1, e.from, e.cost));
		}
	}
	
	initTree(rand() % N);
	
	for (int i = 0; i < Q; i++){
		int s, t;
		scanf("%d %d", &s, &t);
		
		printf("%d\n", howFar(--s, --t));
	}
	
	return (0);
}

Measured memory_bytes: 36968