#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int long long

#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(),(x).end()

#define FOR(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define REP(i,x) for(int i=0;i<(int)(x);i++)
#define REPS(i,x) for(int i=1;i<=(int)(x);i++)
#define RREP(i,x) for(int i=((int)(x)-1);i>=0;i--)
#define RREPS(i,x) for(int i=((int)(x));i>0;i--)

typedef pair<int, int> pint;

#define mp make_pair
#define mt make_tuple
#define pb push_back
#define pf push_front

#define MOD (1000 * 1000 * 1000 + 7)

struct Edge {int to, cost; };
typedef pair<int, int> pint;

#define INF (1000L * 1000L * 1000L * 1000L)
// #define INF (LONG_MAX / 10000)

class Dikstra {
private:
    int N;
    vector<vector<Edge>> edge_list;

public:
    Dikstra(vector< vector<Edge>> &edge_list) {
        this->edge_list = edge_list;
        this->N = edge_list.size();
    }

    Dikstra(int N) {
        this->edge_list = vector< vector< Edge>>(N, vector<Edge>());
        this->N = N;
    }

    void addEdge(int i, Edge e) {
        this->edge_list[i].pb(e);
    }

    vector<int> search(int s) {
        priority_queue<pint, vector<pint>, greater<pint> > que;
        vector<int> d(N, INF);
        d[s] = 0;
        que.push(make_pair(0, s));

        while (!que.empty()) {
            pint p = que.top();
            que.pop();

            int v = p.second;
            if (d[v] < p.first) continue;

            for (Edge e: edge_list[v]) {
                if (d[e.to] > d[v] + e.cost) {
                    d[e.to] = d[v] + e.cost;
                    que.push(make_pair(d[e.to], e.to));
                }
            }
        }

        return d;
    }
};


class WarshallFloyd {
private:
    int N;
    vector<vector<Edge>> edge_list;

public:
    WarshallFloyd(vector< vector<Edge>> &edge_list) {
        this->edge_list = edge_list;
        this->N = edge_list.size();
    }

    WarshallFloyd(int N) {
        this->edge_list = vector< vector< Edge>>(N, vector<Edge>());
        this->N = N;
    }

    void addEdge(int i, Edge e) {
        (this->edge_list[i]).push_back(e);
    }

    vector< vector<int>> search() {
        vector< vector<int>> d(N, vector<int>(N, INF));

        // init
        for (int i=0;i<N;i++) {
            for (Edge e: edge_list[i]) {
                d[i][e.to] = e.cost;
            }
        }

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

        return d;
    }
};

signed main() {
    int N, M, L;
    cin >> N >> M >> L;

    WarshallFloyd d(N);
    REP(i, M) {
        int a, b, c;
        cin >> a >> b >> c;
        a--; b--;

        d.addEdge(a, {b, c});
        d.addEdge(b, {a, c});
    }

    WarshallFloyd d2(N);
    vector<vector<int>> dist = d.search();
    REP(i, N) {
        REP(j, N) {
            if (i == j) continue;

            if (dist[i][j] <= L) {
                d2.addEdge(i, {j, 1});
            }
        }
    }

    vector<vector <int>> ans(N, vector<int>(N, -1));
    vector<vector<int>> dist2 = d2.search();
    REP(i, N) {
        REP(j, N) {
            ans[i][j] = (dist2[i][j] == INF) ? -1 : dist2[i][j] - 1;
        }
    }

    int Q;
    cin >> Q;

    REP(i, Q) {
        int s, t;
        cin >> s >> t;
        s--; t--;

        cout << ans[s][t] << endl;
    }

    return 0;
}

Measured memory_bytes: 7424