#include <bits/stdc++.h>
#define SIZE 300005
#define MOD 1000000007LL
#define EPS 1e-10
#define INF 2147483647
#define LLINF 9223372036854775807
#define REP(i,n) for(int i=0;i<n;i++)
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define DOWN(i,b,a) for(int i=b;i>=a;i--)
#define SET(a,c) memset(a,c,sizeof a)
#define BIT(i,j) ((i)>>(j))&1
#define ALL(o) (o).begin(), (o).end()
#define ERASE(o) (o).erase(unique((o).begin(),(o).end()), (o).end())
#define SQ(x) ((x)*(x))
using namespace std;
typedef long long ll;
typedef pair<ll,ll> Pll;
typedef pair<int, int> Pii;
typedef pair<double, double> Pdd;
typedef complex<double> dcomplex;
template<typename T> inline void priv(vector<T>a){REP(i,a.size()){cerr<<a[i]<<((i==a.size()-1)?"\n":" ");}}
inline void fastio(){cin.tie(nullptr); cout.tie(nullptr); ios::sync_with_stdio(false); cout << fixed << setprecision(15);}
ll gcd(ll a,ll b){int c=max(a,b);int d=min(a,b);return c==0||d==0?c:gcd(c%d,d);}
ll lcm(ll a,ll b){return a==0||b==0?0:a*b/gcd(a,b);}
ll modfact(ll a){ll b=1;FOR(i,2,a)b=b*i%MOD;return b;}
ll modpow(ll a, ll n){ll b=1;while (n>0){if(n&1)b=b*a%MOD;a=a*a%MOD;n>>=1;}return b;}
ll modcomb(ll n, ll k){ll b=1;k=min(n-k,k);DOWN(i,n,n-k+1)b=b*i%MOD;return b*modpow(modfact(k),MOD-2)%MOD;}

template<typename T> 
struct Edge {
    int src, dst; T w;
    Edge() {};
    Edge(int src, int dst): src(src), dst(dst) {}
    Edge(int src, int dst, T w): src(src), dst(dst), w(w){}
    bool operator<(const Edge &e)const{return w != e.w ? w < e.w : (src != e.src ? src < e.src : dst < e.dst);}
    bool operator>(const Edge &e)const{return w != e.w ? w > e.w : (src != e.src ? src > e.src : dst > e.dst);}
    bool operator==(const Edge &e)const{return src == e.src && dst == e.dst && w == e.w;}
};

template<typename T> 
class Graph : public vector<vector<Edge<T>>> {
private:
    pair<T,int> _farthest(int p, int v) {
        pair<T,int> r(0, v);
        for(auto e : (*this)[v]) if(e.dst != p) {
            auto t = farthest(v, e.dst);
            t.first += e.w;
            if(t.first > r.first) r=t;
        }
        return r;
    }
    void _backward(
            Graph &h, int v, int s, int r,
            vector<int> &no, vector<vector<int>> &cmp,
            vector<int> &prev, vector<vector<int>> &next, vector<T> &mcost,
            vector<int> &mark, T &cost, bool &found) {
        const int n = h.size();
        if(mark[v]) {
            vector<int> tmp = no;
            found = true;
            do {
                cost += mcost[v];
                v = prev[v];
                if (v != s){
                    while (cmp[v].size() > 0) {
                        no[cmp[v].back()] = s;
                        cmp[s].push_back(cmp[v].back());
                        cmp[v].pop_back();
                    }
                }
            } while (v != s);
            for(auto j : cmp[s]) if(j != r) for(int l=0; l<h[j].size(); l++)
                if(no[h[j][l].src] != s) h[j][l].w -= mcost[tmp[j]];
        }
        mark[v] = true;
        for(auto i : next[v]) if(no[i] != no[v] && prev[no[i]] == v)
            if (!mark[no[i]] || i==s)
                _backward(h, i, s, r, no, cmp, prev, next, mcost, mark, cost, found);
    }
    void _subaps(
            int current, int prev, int &timer,
            vector<bool> &visited, vector<int> &prenum,
            vector<int> &parent, vector<int> &lowest) {
        prenum[current] = lowest[current] = timer++;
        visited[current] = true;
        for(auto e : (*this)[current]) {
            int next = e.dst;
            if(!visited[next]) {
                parent[next]=current;
                _subaps(next, current, timer, visited, prenum, parent, lowest);
                lowest[current] = min(lowest[current], lowest[next]);
            } else if(next != prev) lowest[current] = min(lowest[current], prenum[next]);
        }
    }
    void _subbrs(
            int current, int prev, int &timer,
            vector<int>&prenum, vector<int>&lowest, set<Edge<T>>&bridges) {
        prenum[current] = lowest[current] = timer++;
        for(auto e : (*this)[current]) if(e.dst != prev) {
            if(prenum[e.dst] == -1) {
                _subbrs(e.dst, current, timer, prenum, lowest, bridges);
                lowest[current] = min(lowest[current], lowest[e.dst]);
                if(prenum[current] < lowest[e.dst])
                    bridges.insert(Edge<T>(min(e.dst, e.src), max(e.dst, e.src)));
            }
            lowest[current] = min(lowest[current], prenum[e.dst]);
        }
    }

public:
    T inf;
    Graph(int n, T inf): inf(inf) {(*this).resize(n);}
    void direct(int s, int t, T w){(*this)[s].push_back(Edge<T>(s, t, w));}
    void undirect(int s, int t, T w){direct(s, t, w); direct(t, s, w);}
    /* 
    cost : O(|V|)
    */
    T diameter(void) {
        auto r = _farthest(-1, 0);
        auto t = _farthest(-1, r.second);
        return t.first;
    }

    /*
    s : start point
    cost : O(|E|+|V|log(|V|))
    dist : distances
    */
    vector<T> dijkstra(int s=0) {
        using Pi = typename std::pair<T, int>;
        const int n = (*this).size();
        priority_queue<Pi, vector<Pi>, greater<Pi>> Q;
        vector<T> dist(n, inf);
        dist[s] = 0;
        Q.push(Pi(0, s));
        while (!Q.empty()) {
            auto p = Q.top(); Q.pop();
            int v = p.second;
            if (dist[v] < p.first) continue;
            for (int i=0; i<(*this)[v].size(); i++) {
                auto e = (*this)[v][i];
                if (dist[e.dst] > dist[v] + e.w) {
                    dist[e.dst] = dist[v] + e.w;
                    Q.push(Pi(dist[e.dst], e.dst));
                }
            }
        }
        return dist;
    }

    /*
    s : start point
    cost : O(N^3)
    */
    vector<vector<T>> warshall_floyd(void){
        const int n = (*this).size();
        vector<vector<T>> dist(n, vector<T>(n, inf));
        for(int v = 0; v < n; v++) {
            dist[v][v] = 0;
            for(auto e : (*this)[v])
                dist[v][e.dst] = e.w;
        }
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                for(int k = 0; k < n; k++)
                    dist[j][k] = min(dist[j][k], dist[j][i] + dist[i][k]);
        return dist;
    }

    /*
    s : start point
    cost : O(|V||E|)
    first : is negative cycle ?
    second : distances
    */
    pair<bool, vector<T>> bellman_ford(int s = 0){
        const int n = (*this).size();
        vector<T> dist(n, inf);
        dist[s] = 0;
        for(int i = 0; i < n; i++) {
            bool update = false;
            for(int v = 0; v < n; v++) for(auto e : (*this)[v]) {
                if (dist[v] != inf && dist[e.dst] > dist[v] + e.w) {
                    dist[e.dst] = dist[v] + e.w;
                    update = true;
                    if(i==n-1) return make_pair(true, dist);
                }
            }
            if(!update) break;
        }
        return make_pair(false, dist);
    }

    /*
    Minimum Spanning Tree (Prim's algorithm)
    r : root
    cost : O(|E|+|V|log|V|) (because priority_queue use pairing sort)
    first : total cost
    second : edges
    */
    pair<T, vector<Edge<T>>> prim(int r = 0) {
        const int n = (*this).size();
        vector<Edge<T>> U;
        T total = 0;
        vector<bool> visited(n, false);
        priority_queue<Edge<T>, vector<Edge<T>>, greater<>> Q;
        Q.push(Edge<T>(-1, r, 0));
        while (!Q.empty()) {
            auto e = Q.top(); Q.pop();
            if (visited[e.dst]) continue;
            U.push_back(e);
            total += e.w;
            visited[e.dst] = true;
            for(auto f : (*this)[e.dst]) if (!visited[f.dst]) Q.push(f);
        }
        return make_pair(total, U);
    }

    /*
    Minimum Spanning Arborescence(Chu-Liu/Edmonds)
    r : root
    cost : O(|V||E|)
    */
    T edmonds(int r = 0) {
        const int n = (*this).size();
        Graph<T> h(n, inf);
        for(int i = 0; i < n; i++) for(auto e : (*this)[i]) h[e.dst].push_back(e);
        vector<int> no(n);
        vector<vector<int>> cmp(n);
        for(int i = 0; i < n; i++) cmp[i].push_back(no[i] = i);
        for (T cost=0;;) {
            vector<int> prev(n, -1);
            vector<T> mcost(n,inf);
            for(int j = 0; j < n; j++) if(j != r) for(auto e : h[j])
                if (no[e.src] != no[j])
                    if (e.w < mcost[no[j]])
                        mcost[no[j]] = e.w, prev[no[j]] = no[e.src];
            vector<vector<int>> next(n);
            for(int i = 0; i < n; i++) if(prev[i] >= 0)
                next[prev[i]].push_back(i);
            bool stop = true;
            vector<int> mark(n);
            for(int i = 0; i < n; i++) if(i!=r && !mark[i] && !cmp[i].empty()) {
                bool found = false;
                _backward(h, i, i, r, no, cmp, prev, next, mcost, mark, cost, found);
                if (found) stop = false;
            }
            if (stop) {
                for(int i = 0; i < n; i++) if(prev[i] >= 0) cost += mcost[i];
                return cost;
            }
        }
    }

    /*
    articulation points
    costs O(|E|log|V|)
    only undirect graph
    */
    set<int> articulations(void) {
        const int n = (*this).size();
        set<int> ap;
        if(n == 1) return ap;
        int timer = 1;
        vector<bool> visited(n, false);
        vector<int> prenum(n), parent(n), lowest(n);
        _subaps(0, -1, timer, visited, prenum, parent, lowest);
        int np = 0;
        for(int i = 1; i < n; i++) {
            int p = parent[i];
            if(p == 0) np++;
            else if(prenum[p] <= lowest[i]) ap.insert(p);
        }
        if(np > 1) ap.insert(0);
        return ap;
    }

    /*
    bridges
    only undirect graph
    */
    set<Edge<T>> bridges(void) {
        const int n = (*this).size();
        set<Edge<T>> bridges;
        vector<int> prenum(n, -1), lowest(n, inf);
        int timer = 0;
        for(int i = 0; i < n; i++) if(prenum[i] == -1)
            _subbrs(i, -1, timer, prenum, lowest, bridges);
        return bridges;
    }
};

int main() {
    fastio();
    ll N, M, L;
    ll A, B, C;
    ll Q, s, t;
    ll inf = 1LL<<60;
    cin >> N >> M >> L;
    Graph<ll> g1(N, inf);
    REP(i, M) {
        cin >> A >> B >> C;
        g1.undirect(--A, --B, C);
    }
    auto d1 = g1.warshall_floyd();
    Graph<ll> g2(N, inf);
    REP(i, N) FOR(j, i+1, N-1)
        if(d1[i][j] <= L) g2.undirect(i, j, 1);
    auto d2 = g2.warshall_floyd();
    cin >> Q;
    REP(i, Q) {
        cin >> s >> t;
        s--; t--;
        if(d2[s][t] == inf)
            cout << -1 << "\n";
        else
            cout << d2[s][t] - 1 << "\n";
    }
	return 0;
}

Measured memory_bytes: 6784