#include <bits/stdc++.h>
using namespace std;
#define repr(i,a,b) for(int i=a;i<b;i++)
#define rep(i,n) for(int i=0;i<n;i++)
#define reprrev(i,a,b) for(int i=b-1;i>=a;i--) // [a, b)
#define reprev(i,n) reprrev(i,0,n)
typedef long long ll;
typedef unsigned long long ull;
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return true; } return false; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return true; } return false; }

/* attention
    long longのシフト演算には気をつけよう
    タイポした時のデバッグが死ぬほどきつくなるので変数名は最低3字くらい使った方がいいかも
    sizeは(int)とキャストしよう
    cin.tie(0);
    ios::sync_with_stdio(false);<- これら、printfとかと併用しない方が良さそう

*/

const ll mod = 1e9+7;

void chmod(ll &M){
    if(M >= mod) M %= mod;
    else if(M < 0){
        M += (abs(M)/mod + 1)*mod;
        M %= mod;
    }
}

ll modpow(ll x, ll n){
    if(n==0) return 1;
    ll res=modpow(x, n/2);

    if(n%2==0) return res*res%mod;
    else return res*res%mod*x%mod;
}

int getl(int i, int N) { return i==0? N-1:i-1; };
int getr(int i, int N) { return i==N-1? 0:i+1; };


// 線分 ab の偏角 返り値は[-π, π]
double argument(const pair<double, double> &a, const pair<double, double> &b){
    double ax=a.first, ay=a.second, bx=b.first, by=b.second;
    return atan2(by-ay, bx-ax);
}

/* <-----------------------------------------------------------------------------------> */
/* <-----------------------------------------------------------------------------------> */
/* <-----------------------------------------------------------------------------------> */
/* <-----------------------------------------------------------------------------------> */


struct S{
    ll charge, gasoline;

    S(ll _charge, ll _gasoline)
        : charge(_charge), gasoline(_gasoline){}

    bool operator < (S const &s) const {
        if(charge < s.charge) return true;
        else if(charge > s.charge) return false;
        else{
            if(gasoline > s.gasoline) return true;
            else return false;
        }
    }

    bool operator > (S const &s) const {
        if(charge > s.charge) return true;
        else if(charge < s.charge) return false;
        else{
            if(gasoline < s.gasoline) return true;
            else return false;
        }
    }

};

const ll inf = 1LL<<60;
int N, M, L;

vector<vector<S>> optimal(330, vector<S>(330, S{inf, 0}));
vector<pair<int, ll>> edges[330];

void dijkstra(int s){
    priority_queue< pair<S, int>, vector<pair<S, int>>, greater<pair<S, int>>> pq;
    pq.push(make_pair(S{0, L}, s));
    optimal[s][s] = S{0, L};

    while(!pq.empty()){
        auto p = pq.top(); pq.pop();
        S node = p.first;
        int now = p.second;
        if(optimal[s][now] < node) continue;//<- ここが常に真で評価される
        for(auto edge : edges[now]){
            int nxt = edge.first; ll cost = edge.second;
            S nxtnode{node.charge, node.gasoline};
            if(node.gasoline-cost >= 0) nxtnode.gasoline -= cost;
            else nxtnode.charge += 1, nxtnode.gasoline = L-cost;
            if(optimal[s][nxt] > nxtnode){
                optimal[s][nxt] = nxtnode;
                pq.push(make_pair(nxtnode, nxt));
            }
        }
    }
}

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

    cin >> N >> M >> L;
    rep(i, M){
        int a, b, c; cin >> a >> b >> c;
        if(c > L) continue;
        --a; --b;
        edges[a].push_back(make_pair(b, c));
        edges[b].push_back(make_pair(a, c));
    }

    rep(i, N) dijkstra(i);
    int Q; cin >> Q;
    while(Q--){
        int s, t; cin >> s >> t;
        --s; --t;
        cout << (optimal[s][t].charge == inf? -1:optimal[s][t].charge) << endl;
    }

    return 0;
}

Measured memory_bytes: 5992