#include<queue>
#include<cstdio>
#include<algorithm>

#define rep(i,n) for(int i=0;i<(n);i++)

using namespace std;

const int INF=1<<29;

const int V_MAX=100000,LG_V_MAX=17;

template<class T>
struct edge{
	int v;
	T cost;
};

template<class cost_t>
class static_tree_query_solver{
	int par[LG_V_MAX][V_MAX],dep[V_MAX];
	cost_t mini[LG_V_MAX][V_MAX];

	int lca(int u,int v)const{
		if(dep[u]>dep[v]) swap(u,v);
		rep(i,LG_V_MAX) if((dep[v]-dep[u])>>i&1) v=par[i][v];
		if(u==v) return u;

		for(int i=LG_V_MAX-1;i>=0;i--){
			if(par[i][u]!=par[i][v]){
				u=par[i][u];
				v=par[i][v];
			}
		}
		return par[0][u];
	}

	cost_t up(int u,int t)const{ // u から t 個上の頂点までの min をとる
		cost_t res=INF;
		rep(i,LG_V_MAX) if(t>>i&1) {
			res=min(res,mini[i][u]);
			u=par[i][u];
		}
		return res;
	}

public:
	void build(int n,const vector<int> *T,const cost_t *val){
		struct info{ int u,pre,d; };
		static info S[V_MAX];
		int head=0,tail=0;
		S[tail++]=(info){0,-1,0};
		while(head<tail){
			int u=S[head].u,pre=S[head].pre,d=S[head].d; head++;
			par[0][u]=pre;
			dep[u]=d;
			rep(i,T[u].size()){
				int v=T[u][i];
				if(v!=pre){
					mini[0][v]=min(val[u],val[v]);
					S[tail++]=(info){v,u,d+1};
				}
			}
		}

		rep(i,LG_V_MAX-1) rep(u,n) {
			par[i+1][u]=(par[i][u]==-1?-1:par[i][par[i][u]]);
			mini[i+1][u]=(par[i][u]==-1?-1:min(mini[i][u],mini[i][par[i][u]]));
		}
	}

	cost_t query(int u,int v)const{
		int w=lca(u,v);
		return min(up(u,dep[u]-dep[w]),up(v,dep[v]-dep[w]));
	}
};

class union_find{
	vector<int> a;
public:
	union_find(int n):a(n,-1){}
	int find(int x){
		if(a[x]<0) return x;
		return a[x]=find(a[x]);
	}
	void unite(int x,int y){
		x=find(x),y=find(y);
		if(x!=y){ a[x]+=a[y]; a[y]=x; }
	}
	int size(int x){ return -a[find(x)]; }
};

int main(){
	int n,m,k,q; scanf("%d%d%d%d",&n,&m,&k,&q);
	static vector< edge<int> > G[V_MAX];
	rep(i,m){
		int u,v,cost; scanf("%d%d%d",&u,&v,&cost); u--; v--;
		G[u].push_back((edge<int>){v,cost});
		G[v].push_back((edge<int>){u,cost});
	}
	static int matsuri[V_MAX];
	rep(i,k) scanf("%d",matsuri+i), matsuri[i]--;

	// Dijkstra
	static int d[V_MAX]; // d[u] := ( 頂点 u から一番近いお祭りまでの距離 )
	{
		priority_queue< pair<int,int> > Q;
		rep(u,n) d[u]=INF;
		rep(i,k) d[matsuri[i]]=0, Q.push(make_pair(0,matsuri[i]));
		while(!Q.empty()){
			int d_now=-Q.top().first,u=Q.top().second; Q.pop();
			if(d[u]<d_now) continue;
			rep(i,G[u].size()){
				int v=G[u][i].v,cost=G[u][i].cost;
				if(d[v]>d[u]+cost){
					d[v]=d[u]+cost;
					Q.push(make_pair(-d[v],v));
				}
			}
		}
	}

	// Kruskal
	static vector<int> MST[V_MAX];
	{
		static pair< pair<int,int>,pair<int,int> > E[200000];
		int idx=0;
		rep(u,n) rep(i,G[u].size()) {
			int v=G[u][i].v;
			if(u<v) E[idx++]=make_pair(make_pair(min(d[u],d[v]),max(d[u],d[v])),make_pair(u,v));
		}
		sort(E,E+m);

		union_find U(n);
		for(int i=m-1;i>=0;i--){
			int u=E[i].second.first,v=E[i].second.second;
			if(U.find(u)!=U.find(v)){
				U.unite(u,v);
				MST[u].push_back(v);
				MST[v].push_back(u);
			}
		}
	}

	// query
	static static_tree_query_solver<int> L;
	L.build(n,MST,d);
	while(q--){ int s,t; scanf("%d%d",&s,&t); s--; t--; printf("%d\n",L.query(s,t)); }

	return 0;
}

Measured memory_bytes: 33588