// よくないダイクストラ ; heap使用
#include <stdio.h>
#include <vector>
#include <queue>
#include <tuple>

#define FOR(i, a, b) for(int (i) = (a); (i) < (b); ++(i))
#define REP(i, n) FOR(i, 0, n)

// Dijkstra 法 を行うクラス : updated : doubleも可能
template <class DistanceType = int, class AnsType = long long int>
class Dijkstra{
private:
    // 無限大 の距離
    const DistanceType infinity_cost;
    const AnsType      zero;
    const int V; // 枝の数, 頂点数
    // (指し示す頂点, コスト)
    using edge = std::pair<int, DistanceType>;
    using edgeSet = std::vector<edge>; // 1つの頂点からでる枝の集合
    std::vector<edgeSet> Edges; // 枝全体
    std::vector<AnsType> Distances; // 距離を表す
    std::vector<bool> hasVisited;
public:
    // コンストラクタ
    Dijkstra(int edgeSize, DistanceType theInf, AnsType ZERO): V(edgeSize), infinity_cost(theInf), zero(ZERO){
        Edges.resize(edgeSize, edgeSet(0)); hasVisited.resize(edgeSize);
        Distances.resize(edgeSize, infinity_cost);
    }
    // デコンストラクタ
    ~Dijkstra(void){}
    // 頂点 u -> v へ 重み cost を追加
    void add(int u, int v, DistanceType cost){
        Edges[u].emplace_back(std::pair<int, DistanceType>(v, cost));
    }
    // 頂点 vertex 中心の計算を行う
    using Info__Type_ = std::pair<AnsType, int>;
    void computeAround(int vertex){
        std::fill(Distances.begin(), Distances.end(), infinity_cost);
        std::fill(hasVisited.begin(), hasVisited.end(), false);
        std::priority_queue<Info__Type_, std::vector<Info__Type_>,
            std::greater<Info__Type_>> undoneEdge;
        undoneEdge.push(Info__Type_(zero, vertex));
        int vtx; AnsType dist;
        while(not undoneEdge.empty()){
            std::tie(dist, vtx) = undoneEdge.top(); undoneEdge.pop();
            
            if(hasVisited[vtx]) continue;
            hasVisited[vtx] = true; Distances[vtx] = dist;
            for(edge element : Edges[vtx]){
                AnsType nextDistance = dist + element.second;
                if(nextDistance < Distances[element.first])
                        undoneEdge.push(Info__Type_(nextDistance, element.first));
            }
        }
    }
    AnsType distance(int vertex){
        return Distances.at(vertex);
    }
};


constexpr int inf = 1e9;
static int L;
struct myDist{
    int time;
    int gas;
    myDist(int t = 0, int g = L): time(t), gas(g){}
    ~myDist(void){}

    bool operator < (const myDist& d) const{
        if(this->time != d.time) return this->time < d.time;
        return this->gas > d.gas;
    }
    bool operator > (const myDist& d) const {
        if(time != d.time) return time > d.time;
        return gas < d.gas;
    }
    myDist operator +(myDist d){
        if(gas + d.gas >= 0) return myDist(time+d.time, gas+d.gas);
        if(L + d.gas < 0) return myDist(inf, 0);
        return myDist(time+d.time+1, L+d.gas);
    }
};

std::vector<std::vector<int>> Res;


int main(void){
    int n, m; scanf("%d%d%d", &n, &m, &L);
    const myDist Inf = myDist(inf, -1);
    const myDist zero = myDist(0, L);
    Dijkstra<myDist, myDist> D(n, Inf, zero);
    REP(i, m){
        int a, b, c; scanf("%d%d%d", &a, &b, &c); a--; b--;
        D.add(a, b, myDist(0, -c));
        D.add(b, a, myDist(0, -c));
    }
    Res.resize(n, std::vector<int>(n));
    REP(i, n){
        D.computeAround(i);
        REP(j, n) Res[i][j] = D.distance(j).time;
    }
    int Q; scanf("%d", &Q);
    while(Q--){
        int s, t; scanf("%d%d", &s, &t); s--; t--;
        if(Res[s][t] == inf) puts("-1");
        else printf("%d\n", Res[s][t]);
    }
    
    return 0;
}


Measured memory_bytes: 3772