//includes
#include<iostream>
#include<vector>
#include<set>
#include<tuple>
#include<algorithm>
#include<cmath>
#include<string>
#include<stack>
#include<map>
#include<queue>
#include<iomanip>
#include<numeric>
#include<assert.h>
#include<cstring>
#include<unordered_map>
#include<bitset>


template<class T> inline bool chmin(T& a, T b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template<class T> inline bool chmax(T& a, T b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}

//macros and consts
#define REP(i, n) for(int i = 0; i < (int)(n); i++)
#define all(a) (a).begin(),(a).end()
#define FOR(i,a,b) for(int i = (a); i < (b); i++)
#define FORE(i,a) for(auto &i : a)
#define pb push_back
#define mp make_pair
#define eb emplace_back
#define accm accumulate
#define Fi first
#define Se second
#define INF 1e9
#define llINF (1LL<<60)
#define mINF -1e9
#define mllINF -(1LL<<60)
#define endl "\n"
#define CONT continue
#define BRK break
#define modulo(n, m) (((n)%(m)+(m))%m)

//shorter types
using namespace std;
using ll = long long;
using vi = std::vector<int>;
using vc = std::vector<char>;
using vll = std::vector<long long>;
using vs = std::vector<string>;
using Mi = map<int,int>;
using Mll = map<ll,ll>;
using UMi = unordered_map<int,int>;
using UMll = unordered_map<ll,ll>;
using Pi = pair<int,int>;
using Pll = pair<ll,ll>;
using vPi = vector<Pi>;
using vPll = vector<Pll>;
using vvi = vector<vector<int>>;
using vvll = vector<vector<ll>>;
using vvc = vector<vector<char>>;
using vvs = vector<vector<string>>;
using pqgi = priority_queue<int,vector<int>,greater<int>>;
using pqsi = priority_queue<int,vector<int>,less<int>>;
using pqgll = priority_queue<int,vector<int>,greater<int>>;
using pssll = priority_queue<int,vector<int>,less<int>>;
template<class T>
using vec = vector<T>;
#define int long long

struct Edge{
	int src;
	int dst;
	int cost;
	Edge(int src = -1, int dst = -1, int cost = 1)
	: src(src), dst(dst),cost(cost){};
	bool operator<(const Edge &e) const {
		return this -> cost < e.cost;
	}
	bool operator>(const Edge &e) const{
		return this -> cost > e.cost;
	}
};
using Graph = vector<vector<Edge>>;

int N,M,L;
//here begins your code
signed main(){
  std::ios::sync_with_stdio(false);
  std::cin.tie(0);
  cin >> N >> M >> L;

  int dis[300][300];

  for(int i = 0; i < 300; i++){
  	for(int j = 0; j < 300; j++){
  		dis[i][j] = llINF;
  	}
  	dis[i][i] = 0;
  }



  REP(i,M){
  	int a,b,c;
  	cin >> a >> b >> c;
  	a--;
  	b--;
  	dis[a][b] = c;
  	dis[b][a] = c;
  }
  int Q;
  cin >> Q;


  for(int k = 0; k < N; k++){
  	for(int i = 0 ; i < N; i++){
  		for(int j = 0; j < N; j++){
  			dis[i][j] = min(dis[i][j],dis[i][k] + dis[k][j]);
  		}
  	}
  }

  for(int i = 0; i < N; i++){
  	for(int j = 0; j < N; j++){
  		if(dis[i][j] == 0){
  			dis[i][j] = 0;
  		}
  		else if(dis[i][j] <= L){
  			dis[i][j] = 1;
  		}
  		else{
  			dis[i][j] = llINF;
  		}
  	}
  }

  for(int k = 0; k < N; k++){
  	for(int i = 0 ; i < N; i++){
  		for(int j = 0; j < N; j++){
  			dis[i][j] = min(dis[i][j],dis[i][k] + dis[k][j]);
  		}
  	}
  }


  REP(i,Q){
  	int s,t;
  	cin >> s >> t;
  	s--;
  	t--;
  	if(dis[s][t] == llINF){
  		cout << -1 << endl;
  	}
  	else{
	  	cout << dis[s][t] - 1 << endl;
  	}
  }
  //check types
  //do not eb if you resize
  //resize before you access by idx
  return 0;
}

Measured memory_bytes: 1280