#include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define NUM 100000

struct Edge{
	Edge(int arg_from,int arg_to,int arg_dist){
		from = arg_from;
		to = arg_to;
		dist = arg_dist;
		festival_dist = BIG_NUM;
	}
	bool operator<(const struct Edge &arg) const{
		return festival_dist > arg.festival_dist; //祭りまでの最短距離の降順
	}
	int from,to,dist,festival_dist;
};

struct Info{
	Info(int arg_node_id,int arg_sum_dist){
		node_id = arg_node_id;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info &arg) const{
		return sum_dist > arg.sum_dist; //総移動距離の昇順(PQ)
	}
	int node_id,sum_dist;
};

vector<Edge> EDGE,G[NUM];
vector<int> QUERY[NUM];
int min_dist[NUM];
int ans[NUM],boss[NUM];

int get_boss(int id){
	if(id == boss[id])return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

void unite(int x,int y,int festival_dist){

	int x_boss = get_boss(x);
	int y_boss = get_boss(y);

	if(x_boss == y_boss)return;

	//x_bossの方を大きくする
	if(QUERY[y_boss].size() > QUERY[x_boss].size())swap(x_boss,y_boss);

	bool FLG;

	//クエリ番号が出会うかどうか調べる
	for(int i = 0; i < QUERY[y_boss].size(); i++){
		FLG = true;
		for(int k = 0; k < QUERY[x_boss].size(); k++){
			if(QUERY[y_boss][i] == QUERY[x_boss][k]){ //★SとTが出会った場合★
				ans[QUERY[y_boss][i]] = festival_dist;
				FLG = false;
				QUERY[x_boss].erase(QUERY[x_boss].begin()+k);
				break;
			}
		}
		if(FLG){
			QUERY[x_boss].push_back(QUERY[y_boss][i]);
		}
	}

	boss[y_boss] = x_boss; //y_bossをx_bossに併合
}

int main(){

	int N,M,K,num_query;
	scanf("%d %d %d %d",&N,&M,&K,&num_query);

	int from,to,dist;
	for(int loop = 0; loop < M; loop++){
		scanf("%d %d %d",&from,&to,&dist);
		from--;
		to--;
		EDGE.push_back(Edge(from,to,dist));
		G[from].push_back(Edge(from,to,dist));
		G[to].push_back(Edge(to,from,dist));
	}

	int node_id;
	stack<int> S;

	for(int loop = 0; loop < K; loop++){
		scanf("%d",&node_id);
		node_id--;
		S.push(node_id);
	}

	//クエリ情報を取得
	int start,goal;
	for(int loop = 0; loop < num_query; loop++){
		scanf("%d %d",&start,&goal);
		start--;
		goal--;
		QUERY[start].push_back(loop); //ノードに、クエリ番号の集合を作る
		QUERY[goal].push_back(loop);
	}

	//各ノードの、祭りノードまでの最短距離を求める
	for(int i = 0; i < N; i++)min_dist[i] = BIG_NUM;
	priority_queue<Info> Q;

	int next_node,next_cost;

	while(!S.empty()){
		node_id = S.top();
		S.pop();

		min_dist[node_id] = 0;
		Q.push(Info(node_id,0));

		while(!Q.empty()){

			if(Q.top().sum_dist > min_dist[Q.top().node_id]){

				Q.pop();
			}else{

				for(int i = 0; i < G[Q.top().node_id].size(); i++){
					next_node = G[Q.top().node_id][i].to;
					next_cost = Q.top().sum_dist+G[Q.top().node_id][i].dist;

					if(min_dist[next_node] > next_cost){
						min_dist[next_node] = next_cost;
						Q.push(Info(next_node,next_cost));
					}
				}
				Q.pop();
			}
		}
	}

	//エッジを、祭りノードとの距離の降順にsortする
	for(int i = 0; i < M; i++){
		EDGE[i].festival_dist = min(min_dist[EDGE[i].from],min_dist[EDGE[i].to]); //近い方の値を採用
	}
	sort(EDGE.begin(),EDGE.end());

	for(int i = 0; i < N; i++){
		boss[i] = i;
	}

	for(int i = 0; i < M; i++){
		unite(EDGE[i].from,EDGE[i].to,EDGE[i].festival_dist);
	}

	for(int i = 0; i < num_query; i++){
		printf("%d\n",ans[i]);
	}

	return 0;
}



Measured memory_bytes: 25800