//libraries{{{
//include{{{
#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
#include<set>
#include<map>
#include<cmath>
#include<bitset>
#include<cstdio>
#include<iomanip>
#include<climits>
#include<string>
#include<sstream>
#include<numeric>
//}}}
//define{{{
#define MOD 1000000007
#define PI 3.14159265358979
//}}}
//macro{{{
#define in2d(i,j,H,W)(0<=(i)&&(i)<(H)&&0<=(j)&&(j)<(W))
#define rep(i,n) for(int i=0;i<(int)(n);i++)
#define chmin(x,y) (x)=min((x),(y));
#define chmax(x,y) (x)=max((x),(y));
//}}}
//namespace{{{
using namespace std;
//}}}
//typedef,struct{{{
typedef pair<int,int> pii;
typedef long long ll;

struct edge{
	int from,to,d,c;
	edge(int _from=0,int _to=0,int _d=0,int _c=0){
		from=_from;
		to=_to;
		d=_d;
		c=_c;
	}
	bool operator<(const edge &rhs)const{
		return (d==rhs.d)?(c<rhs.c):(d<rhs.d);
	}
};
typedef vector<edge> edges;
typedef vector<edges> graph;
//}}}
//const{{{
const int di[4]={-1,0,1,0};
const int dj[4]={0,-1,0,1};
const int ci[5]={0,-1,0,1,0};
const int cj[5]={0,0,-1,0,1};
//}}}
//math{{{
ll gcd(ll a,ll b){
	if(b==0)return a;
	else return gcd(b,a%b);
}
ll factorial(ll x){
	if(x==1)return 1;
	else return x*factorial(x-1);
}
ll pow(ll x,int n){
	if(n==0)return 1;
	ll ret=(n&1)?x:1;
	ll a=pow(x,n/2);
	return ret*a*a;
}
//}}}
//UFT{{{
struct UFT{
	vector<int>par;
	int getpar(int i){
		if(par[i]==i)return i;
		return par[i]=getpar(par[i]);
	}
	void unite(int i,int j){
		int t=getpar(i);
		par[t]=getpar(j);
	}
	bool uf(int i,int j){
		return getpar(i)==getpar(j);
	}
	UFT(int n){
		par=vector<int>(n);
		for(int i=0;i<n;i++)par[i]=i;
	}
};
//}}}
//SegT{{{
struct SegT{
	vector<ll>container;
	int n;
	void update(int i,ll x){
		int ii=i+n-1;
		container[ii]=x;
		while(ii>0){
			ii=(ii-1)/2;
			//////////////////////////////////////////
			container[ii]=max(container[2*ii+1],container[2*ii+2]);
			//////////////////////////////////////////
		}
	}
	ll get(int l,int r,int l2=0,int r2=-1,int k=0){
		if(r2==-1)r2=n;
		///////////////////////////////////
		if(r2<=l||r<=l2)return 0;
		///////////////////////////////////
		if(l<=l2&&r2<=r)return container[k];
		ll vl=get(l,r,l2,(l2+r2)/2,2*k+1);
		ll vr=get(l,r,(l2+r2)/2,r2,2*k+2);
		///////////////////////////
		return max(vl,vr);
		///////////////////////////
	}
	////////////////new///////////////////////
	SegT(vector<int> &A){
		n=pow(2,(int)log2(A.size())+1);
		container=vector<ll>(2*n,0);
		for(int i=0;i<A.size();i++)update(i,A[i]);
	}
};
//}}}
//BIT{{{
struct BIT{
	vector<int>container;
	BIT(int n){
		container=vector<int>(n+1,0);
	}
	void add(int i,int x){
		if(i>container.size())return;
		container[i]+=x;
		add(i+(i&-i),x);
	}
	int sum(int i){
		if(i==0)return 0;
		return container[i]+sum(i-(i&-i));
	}
};
//}}}
int N,M,L,s,t;
struct stat{
	int kai,tank,p;
	bool operator<(const stat &rhs)const{
		if(kai==rhs.kai)return tank>rhs.tank;
		else return kai<rhs.kai;
	}
	bool operator>(const stat &rhs)const{
		if(kai==rhs.kai)return tank<rhs.tank;
		else return kai>rhs.kai;
	}
};
//dijkstra{{{
void dijkstra(graph &G,vector<stat>&d,int s){
	priority_queue<stat,vector<stat>,greater<stat> >q;
	stat start;start.kai=0;start.tank=L;start.p=s;
	d[s]=start;q.push(start);
	while(!q.empty()){
		stat p=q.top();q.pop();
		if(d[p.p]<p)continue;
		for(int i=0;i<G[p.p].size();i++){
			stat p2=p;
	//		cout<<p2.kai<<" "<<p2.tank<<" "<<p2.p<<endl;
			edge e=G[p.p][i];
			p2.p=e.to;
			if(e.d>L)continue;
			if(p2.tank-e.d<0){p2.kai++;p2.tank=L;}
			p2.tank-=e.d;
		//	cout<<p2.kai<<" "<<p2.tank<<" "<<p2.p<<endl;
			if(p2<d[e.to]){
				d[e.to]=p2;
				q.push(p2);
			}
		}
	}
}
//}}}
//minT{{{
int minT(edges &es,int n){
	sort(es.begin(),es.end());
	int ret=0;
	UFT *u=new UFT(n);
	for(int i=0;i<es.size();i++){
		edge e=es[i];
		if(u->uf(e.from,e.to))continue;
		ret+=e.d;
		u->unite(e.from,e.to);
	}
	for(int i=1;i<n;i++)if(!u->uf(0,i))return -1;
	return ret;
}
//}}}
//{{{compress
int compress(vector<int>&x1,vector<int>&x2,int W){
	vector<int>xs;
	int N=x1.size();
	for(int i=0;i<N;i++){
		for(int d=-1;d<=1;d++){
			int tx1=x1[i]+d,tx2=x2[i]+d;
			if(0<=tx1&&tx1<W)xs.push_back(tx1);
			if(0<=tx2&&tx2<W)xs.push_back(tx2);
		}
	}
	sort(xs.begin(),xs.end());
	xs.erase(unique(xs.begin(),xs.end()),xs.end());
	for(int i=0;i<N;i++){
		x1[i]=find(xs.begin(),xs.end(),x1[i])-xs.begin();
		x2[i]=find(xs.begin(),xs.end(),x2[i])-xs.begin();
	}
	return xs.size();
}
//}}}
//init{{{
struct initializer{
	initializer(){
		cout<<fixed<<setprecision(11);
	}
};
initializer _____;
//}}}
//}}}
int main(){
	cin>>N>>M>>L;
	graph G(N);
	stat tmp;tmp.kai=INT_MAX/2;tmp.tank=1;tmp.p=0;
	rep(i,M){
		int A,B,C;scanf("%d%d%d",&A,&B,&C);--A;--B;
		G[A].push_back(edge(A,B,C));
		G[B].push_back(edge(B,A,C));
	}
	int Q;cin>>Q;
	vector<vector<stat> >dd(N,vector<stat>(N,tmp));
	rep(i,N){
		dijkstra(G,dd[i],i);
	}
	while(Q--){
		scanf("%d%d",&s,&t);--s;--t;
		int ans;
		//if(dd[s].size()!=0)ans=(dd[s][t].kai==INT_MAX/2)?-1:dd[s][t].kai;
		//else{
		//	ans=dijkstra(G,d,s);
		//	dd[s]=d;
		//}
		ans=(dd[s][t].kai==INT_MAX/2)?-1:dd[s][t].kai;
		cout<<ans<<endl;
	}
	return 0;
}



Measured memory_bytes: 3968