#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <sstream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <numeric>
#include <cctype>
#include <tuple>
#include <array>
#include <climits>
#include <bitset>
#include <cassert>

// BEGIN CUT HERE
#ifdef _MSC_VER
#include <agents.h>
#endif
// END CUT HERE 

#define FOR(i, a, b) for(ll i = (a); i < (int)(b); ++i)
#define rep(i, n) FOR(i, 0, n)
#define ALL(v) v.begin(), v.end()
#define REV(v) v.rbegin(), v.rend()
#define MEMSET(v, s) memset(v, s, sizeof(v))
#define UNIQUE(v) (v).erase(unique(ALL(v)), (v).end())
#define MP make_pair
#define MT make_tuple

using namespace std;

typedef long long ll;
typedef pair<int, int> P;

const int N = 1e5 + 10;
const int M = 2e5 + 10;

vector<P> G[N], G2[N];
P edge[M];

template<class T>
struct doublingLCA{
	struct edge{
		int to;
		T dist;
		edge(int t, T d) :to(t), dist(d){}
	};

	bool init;
	int ln;	// log n
	int n, root;
	vector<vector<int>> par;
	vector<vector<T>> pard;
	vector<int> depth;
	vector<T> dist;
	vector<vector<edge>> G;

	doublingLCA(int _n, int _root) :n(_n), root(_root){
		G.resize(n);
		depth.resize(n);
		dist.resize(n);
		pard.resize(n);
		ln = 1;
		while (n >= (1 << ln)) ++ln;
		par.assign(ln, vector<int>(n));
		pard.assign(ln, vector<T>(n));
		init = false;
	}

	void add_edge(int s, int t, int w = 1){
		G[s].push_back(edge(t, w));
		G[t].push_back(edge(s, w));
	}

	void dfs(int p, int v, int _depth, T _dist){
		dist[v] = _dist;
		depth[v] = _depth;
		par[0][v] = p;
		for (auto e : G[v]){
			if (e.to == p) continue;
			dfs(v, e.to, _depth + 1, _dist + e.dist);
			pard[0][e.to] = e.dist;
		}
	}

	void build(){
		init = true;
		dfs(-1, root, 0, 0);

		for (int k = 0; k + 1 < ln; ++k){
			for (int v = 0; v < n; ++v){
				if (par[k][v] < 0){
					par[k + 1][v] = -1;
					pard[k + 1][v] = -1;
				}
				else{
					par[k + 1][v] = par[k][par[k][v]];
					pard[k + 1][v] = min(pard[k][v], pard[k][par[k][v]]);
				}
			}
		}
	}

	pair<int, T> lca(int u, int v){
		if (!init) build();

		if (depth[u] < depth[v]) swap(u, v);

		T dist = 1e9;
		for (int k = 0; k < ln; ++k){
			if ((depth[u] - depth[v]) >> k & 1){
				dist = min(dist, pard[k][u]);
				u = par[k][u];
			}
		}
		if (u == v) return make_pair(u, dist);

		for (int k = ln - 1; k >= 0; --k){
			if (par[k][u] != par[k][v]){
				dist = min({ dist, pard[k][u], pard[k][v] });
				u = par[k][u];
				v = par[k][v];
			}
		}
		dist = min({ dist, pard[0][u], pard[0][v] });
		u = par[0][u];
		return make_pair(u, dist);
	}

	T get_dist(int u, int v){
		return lca(u, v).second;
	}
};



struct UnionFind{
	vector<int> par, sz;
	UnionFind(int n){
		par = sz = vector<int>(n);
		for (int i = 0; i < n; ++i) par[i] = i, sz[i] = 1;
	}
	int find(int x){
		if (x == par[x]) return x;
		return par[x] = find(par[x]);
	}
	void unite(int x, int y){
		x = find(x), y = find(y);
		if (x == y) return;
		par[x] = y;
		sz[y] += sz[x];
	}
	bool same(int x, int y){
		return find(x) == find(y);
	}
	int size(int x){
		return sz[find(x)];
	}
};


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

	int n, m, k, query;
	cin >> n >> m >> k >> query;
	rep(i, m){
		int a, b, l;
		cin >> a >> b >> l;
		--a, --b;
		G[a].push_back(MP(b, l));
		G[b].push_back(MP(a, l));
		edge[i] = MP(a, b);
	}

	priority_queue<P, vector<P>, greater<P>> q;
	vector<int> dist(n, 1e9);
	rep(i, k){
		int f;
		cin >> f;
		--f;
		dist[f] = 0;
		q.push(MP(0, f));
	}

	while (!q.empty()){
		P p = q.top();
		q.pop();

		int d = p.first;
		int v = p.second;

		if (dist[v] < d) continue;

		for (auto &e : G[v]){
			int to = e.first;
			int cost = e.second;
			if (dist[to] <= d + cost) continue;
			dist[to] = d + cost;
			q.push(MP(dist[to], to));
		}
	}

	vector<tuple<int, int, int>> edge2;
	rep(i, m){
		int a, b;
		tie(a, b) = edge[i];
		edge2.emplace_back(min(dist[a], dist[b]), a, b);
	}

	doublingLCA<int> lca(n, 0);

	sort(REV(edge2));
	UnionFind uf(n);
	rep(i, m){
		int w, a, b;
		tie(w, a, b) = edge2[i];
		if (uf.same(a, b)) continue;
		uf.unite(a, b);
		lca.add_edge(a, b, w);
	}

	while (query--){
		int s, t;
		cin >> s >> t;
		--s, --t;
		cout << lca.lca(s, t).second << '\n';
	}


	return 0;
}

Measured memory_bytes: 40156