#include <bits/stdc++.h>

#define rep(i, n) for (int i = 0; i < (n); i++)
#define repr(i, n) for (int i = (n) - 1; i >= 0; i--)
#define rep2(i, l, r) for (int i = (l); i < (r); i++)
#define rep2r(i, l, r) for (int i = (r) - 1; i >= (l); i--)
#define range(a) a.begin(), a.end()

using namespace std;
using ll = long long;

template<class A, class B>
ostream &operator<<(ostream &o, pair<A, B> a) {
  return o << "(" << a.first << "," << a.second << ")";
}

template<class T>
ostream &operator<<(ostream &o, vector<T> a) {
  o << '[';
  for (size_t i = 0; i < a.size(); i++) {
    if (i > 0) o << ',';
    o << a[i];
  }
  o << ']';
  return o;
}

template<class T>
struct fibonacci_heap {
  int mn;

  struct node {
    int l; // left
    int r; // right
    int p; // parent
    int c; // children
    int d; // degree
    T key; // value
    bool mark;
  };

  int root;
  vector<node> dat;

  fibonacci_heap(int n, T inf) : dat(n) {
    root = 0;
    mn = 0;
    for (int i = 0; i < n; i++) {
      dat[i].l = (i + n - 1) % n;
      dat[i].r = (i + 1) % n;
      dat[i].p = -1;
      dat[i].c = -1;
      dat[i].d = 0;
      dat[i].key = inf;
      dat[i].mark = false;
    }
  }

  void insert_list(int *z, int x, int p) {
    dat[x].p = p;
    if (p != -1) dat[p].d++;
    if (*z == -1) {
      *z = x;
      dat[x].l = x;
      dat[x].r = x;
      return;
    }
    int y = dat[*z].r;
    dat[*z].r = x;
    dat[y].l = x;
    dat[x].l = *z;
    dat[x].r = y;
  }

  void remove_list(int *z, int x) {
    int p = dat[x].p;
    if (p != -1) dat[p].d--;
    if (*z == x) {
      *z = dat[x].r;
      if (*z == x) {
        *z = -1;
        return;
      }
    }
    int l = dat[x].l;
    int r = dat[x].r;
    dat[l].r = r;
    dat[r].l = l;
  }

  vector<int> make_list(int x) {
    if (x == -1) return {};
    vector<int> res;
    int y = x;
    do {
      res.push_back(y);
      y = dat[y].r;
    } while (y != x);
    return res;
  }

  pair<T, int> extract_min() {
    int z = mn;
    pair<T, int> res(dat[mn].key, mn);
    int c = dat[z].c;
    vector<int> children = make_list(c);
    for (int c : children) {
      insert_list(&root, c, -1);
    }
    mn = dat[z].r;
    remove_list(&root, z);
    if (root == -1) mn = -1;
    if (z == root) root = dat[z].r;
    else consolidate();
    return res;
  }

  void consolidate() {
    vector<int> A(40, -1);
    int w = root;
    vector<int> children = make_list(root);
    for (int w : children) {
      if (dat[w].p != -1) continue;
      int x = w;
      int d = dat[x].d;
      while (A[d] != -1) {
        int y = A[d];
        if (dat[x].key > dat[y].key) {
          swap(x, y);
        }
        fib_heap_link(y, x);
        A[d] = -1;
        d++;
      }
      A[d] = x;
    }
    mn = -1;
    root = -1;
    for (int i = 0; i < A.size(); i++) {
      if (A[i] != -1) {
        insert_list(&root, A[i], -1);
        if (mn == -1 || dat[A[i]].key < dat[mn].key) {
          mn = A[i];
        }
      }
    }
  }

  void fib_heap_link(int y, int x) {
    remove_list(&root, y);
    insert_list(&dat[x].c, y, x);
    dat[y].mark = false;
  }

  void decrease_key(int x, T v) {
    assert(dat[x].key >= v);
    dat[x].key = v;
    int y = dat[x].p;
    if (y != -1 && dat[x].key < dat[y].key) {
      cut(x, y);
      cascading_cut(y);
    }
    if (dat[x].key < dat[mn].key) {
      mn = x;
    }
  }

  void cut(int x, int y) {
    remove_list(&dat[y].c, x);
    insert_list(&root, x, -1);
    dat[x].mark = false;
  }

  void cascading_cut(int y) {
    int z = dat[y].p;
    if (z != -1) {
      if (!dat[y].mark) {
        dat[y].mark = true;
      } else {
        cut(y, z);
        cascading_cut(z);
      }
    }
  }
};

template<class T>
struct binary_heap {
  vector<T> key;
  vector<int> hv;
  vector<int> vh;

  binary_heap(int n, T inf) : key(n, inf), hv(n), vh(n) {
    for (int i = 0; i < n; i++) {
      hv[i] = i;
      vh[i] = i;
    }
  }

  void exchange(int x, int y) {
    swap(key[x], key[y]);
    int X = hv[x];
    int Y = hv[y];
    swap(vh[X], vh[Y]);
    swap(hv[x], hv[y]);
  }

  pair<T, int> extract_min() {
    pair<T, int> res(key[0], hv[0]);
    exchange(0, key.size() - 1);
    key.pop_back();
    const int n = key.size();
    int k = 0;
    for (;;) {
      int l = k;
      if (k * 2 + 1 < n && key[k * 2 + 1] < key[l]) l = k * 2 + 1;
      if (k * 2 + 2 < n && key[k * 2 + 2] < key[l]) l = k * 2 + 2;
      if (l == k) break;
      exchange(k, l);
      k = l;
    }
    return res;
  }

  void decrease_key(int x, T v) {
    x = vh[x];
    assert(key[x] >= v);
    key[x] = v;
    while (x > 0) {
      int p = (x - 1) >> 1;
      if (key[p] > key[x]) {
        exchange(p, x);
        x = p;
      } else break;
    }
  }
};

struct edge {
  int v;
  ll w;
};

int main() {
  cin.tie(nullptr);
  ios::sync_with_stdio(false);
  cout << fixed << setprecision(15);
  int N, M; ll L; cin >> N >> M >> L;
  vector<vector<edge>> G(N);
  rep(i, M) {
    int a, b, c; cin >> a >> b >> c; a--; b--;
    G[a].push_back((edge){b, c});
    G[b].push_back((edge){a, c});
  }
  vector<vector<ll>> dist(N);
  rep(s, N) {
    constexpr ll INF = 1e18;
    vector<ll> d(N, INF);
    binary_heap<ll> hp(N, INF);
    hp.decrease_key(s, 0);
    d[s] = 0;
    for (int ii = 0; ii < N; ii++) {
      int u = hp.extract_min().second;
      if (d[u] == INF) break;
      for (edge e : G[u]) {
        if (d[e.v] > d[u] + e.w) {
          d[e.v] = d[u] + e.w;
          hp.decrease_key(e.v, d[e.v]);
        }
      }
    }
    dist[s] = d;
  }
  vector<vector<int>> ans(N, vector<int>(N, 1e9));
  rep(i, N) rep(j, N) if (dist[i][j] <= L) ans[i][j] = 1;
  rep(i, N) ans[i][i] = 1;
  rep(k, N) rep(i, N) rep(j, N) ans[i][j] = min(ans[i][j], ans[i][k] + ans[k][j]);
  int Q; cin >> Q;
  while (Q--) {
    int s, t; cin >> s >> t; s--; t--;
    assert(s != t);
    if (ans[s][t] == 1e9) {
      cout << -1 << '\n';
    } else {
      cout << ans[s][t] - 1 << '\n';
    }
  }
}


Measured memory_bytes: 3968