#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <deque>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include <cfloat>

template<typename CostType>
/// \brief 辺の情報
struct Edge{
  int      to;
  CostType cost;

  Edge(int t, CostType c): to(t), cost(c){
  }
};

template<typename CostType>
class Graph{

private:

  /// \brief adjacent_list_[n]=ノードnの隣接リストを表すvector<Edge>
  std::vector<std::vector<Edge<CostType>>> adjacent_list_;

public:

  /// \brief 頂点数
  const int NODE_SIZE_;

  /// \brief コンストラクタ
  /// \param node_size 頂点数
  explicit Graph(const int node_size): NODE_SIZE_(node_size),
                                       adjacent_list_(node_size){
  }

  /// \brief 有向グラフの辺を生やす
  /// \param from 辺の根本の頂点の番号
  /// \param to 辺の先の頂点の番号
  /// \param cost 辺のコスト
  void SetDirectedEdge(const int from, const int to, const CostType cost){
    adjacent_list_[from].push_back(Edge<CostType>(to, cost));
  }

  /// \brief 無向グラフの辺を生やす
  /// \param node_a 一方の頂点の番号
  /// \param node_b もう一方の頂点の番号
  /// \param cost 辺のコスト
  void
  SetUndirectedEdge(const int node_a, const int node_b, const CostType cost){
    SetDirectedEdge(node_a, node_b, cost);
    SetDirectedEdge(node_b, node_a, cost);
  }

  /// \brief ある頂点の隣接リストを取得
  /// \param node_num 頂点の番号
  /// \return 隣接リスト
  std::vector<Edge<CostType>> GetAdjacentList(int node_num) const{
    return adjacent_list_[node_num];
  }
};

/// \brief ワーシャルフロイド法により，全点対の最小コストを求める
/// \tparam CostType 辺のコストの型
/// \param graph グラフ
/// \param INF CostType型で十分大きい値
/// \return hoge[from][to]=from→toの最小コスト(到達できないときはINF)，
///         負の閉路がある場合は0行の二次元配列みたいなvector
template<typename CostType>
std::vector<std::vector<CostType>>
WarshallFloyd(const Graph<CostType>& graph, const CostType INF){
  std::vector<std::vector<CostType>> min_cost;
  for(int                            r = 0; r < graph.NODE_SIZE_; r++){
    std::vector<CostType> rowvec;
    for(int               c = 0; c < graph.NODE_SIZE_; c++){
      rowvec.push_back((r == c) ? 0 : INF);
    }
    min_cost.push_back(rowvec);
  }

  for(int from = 0; from < graph.NODE_SIZE_; from++){
    for(auto e:graph.GetAdjacentList(from)){
      min_cost[from][e.to] = e.cost;
    }
  }

  for(int k = 0; k < graph.NODE_SIZE_; k++){
    for(int i = 0; i < graph.NODE_SIZE_; i++){
      for(int j = 0; j < graph.NODE_SIZE_; j++){
        if(min_cost[i][k] == INF || min_cost[k][j] == INF){ continue; }
        min_cost[i][j] =
            std::min(min_cost[i][j], min_cost[i][k] + min_cost[k][j]);
      }
    }
  }

  for(int i = 0; i < graph.NODE_SIZE_; i++){

    if(min_cost[i][i] < 0){
      std::vector<std::vector<CostType>> result(0);
      return result;
    }

  }

  return min_cost;
}

int n,m,l;

struct State{
        int refill;
        int gas;
        State(int l,int g):refill(l),gas(g){}
        State(){
          refill=INT32_MAX/2;
          gas=-1;
        }
        State(State const &st){
          refill=st.refill;
          gas=st.gas;
        }
        bool operator<(const State& another)const{
          if(refill!=another.refill){
            return refill<another.refill;
          }else{
            return gas>another.gas;
          }
        }
  bool operator>(const State& another)const{
    if(refill!=another.refill){
      return refill>another.refill;
    }else{
      return gas<another.gas;
    }
  }
  bool operator!=(const State& another)const{
          if(refill==another.refill&&gas==another.gas){
            return false;
          }else{
            return true;
          }
        }
      };

struct pq_state{
  int node;
  State state_;
  pq_state(int nd,State s):node(nd),state_(s){}
  bool operator>(const pq_state& another)const{
    return state_>another.state_;
  }
  bool operator!=(const pq_state& another)const{
    return state_!=another.state_;
  }
};

using std::cerr;
using std::cin;
using std::cout;
using std::endl;

int main(void){
  cout << std::fixed << std::setprecision(16);
  cin.tie(0);
  std::ios::sync_with_stdio(false);


  cin>>n>>m>>l;
  Graph<int> graph(n+1);
  for(int i=0;i<m;i++){
    int a,b,c;
    cin>>a>>b>>c;
    if(l>=c){
      graph.SetUndirectedEdge(a,b,c);
    }
  }



  int q;
  cin>>q;

  State state_log[301][301];
  bool log_can_use[301][301]={};
  for(int i=0;i<q;i++){
    int s,t;
    cin>>s>>t;

    if(log_can_use[s][t]){
      cout<<state_log[s][t].refill<<endl;
      continue;
    }

    std::vector<State> min_state(n+1);
    std::priority_queue<pq_state,std::vector<pq_state>,std::greater<pq_state>> pq;
    for(int j=1;j<min_state.size();j++){
      if(j==s){
        min_state[j]=State(0,l);
      }else{

      }
    }
    pq.push(pq_state(s,State(0,l)));
    state_log[s][s]=State(0,l);
    log_can_use[s][s]=true;

    while(!pq.empty()){
      pq_state curr=pq.top();
      pq.pop();
      if(min_state[curr.node]!=curr.state_){
        continue;
      }else{
        state_log[s][curr.node]=curr.state_;
        log_can_use[s][curr.node]=true;
      }

      const std::vector<Edge<int>>& list=graph.GetAdjacentList(curr.node);
      for(auto e:list){
        pq_state next_state(e.to,State(curr.state_.refill,-1));

        if(curr.state_.gas-e.cost>=0){
          next_state.state_.gas=curr.state_.gas-e.cost;
        }else{
          next_state.state_.refill++;
          next_state.state_.gas=l-e.cost;
        }
        if(min_state[e.to]>next_state.state_){

          min_state[e.to]=next_state.state_;
          pq.push(next_state);
        }
      }
    }



    if(log_can_use[s][t]){
      cout<<min_state[t].refill<<endl;
    }else{
      cout<<-1<<endl;
    }






  }






  return 0;
}


Measured memory_bytes: 3244