#include <bits/stdc++.h>
using namespace std;
void __print(int x) { cerr << x; }
void __print(long x) { cerr << x; }
void __print(long long x) { cerr << x; }
void __print(unsigned x) { cerr << x; }
void __print(unsigned long x) { cerr << x; }
void __print(unsigned long long x) { cerr << x; }
void __print(float x) { cerr << x; }
void __print(double x) { cerr << x; }
void __print(long double x) { cerr << x; }
void __print(char x) { cerr << '\'' << x << '\''; }
void __print(const char *x) { cerr << '\"' << x << '\"'; }
void __print(const string &x) { cerr << '\"' << x << '\"'; }
void __print(bool x) { cerr << (x ? "true" : "false"); }
template <typename T, typename V>
void __print(const pair<T, V> &x) {
  cerr << '{';
  __print(x.first);
  cerr << ',';
  __print(x.second);
  cerr << '}';
}
template <typename T>
void __print(const T &x) {
  int f = 0;
  cerr << '{';
  for (auto &i : x) cerr << (f++ ? "," : ""), __print(i);
  cerr << "}";
}
void _print() { cerr << "]\n"; }
template <typename T, typename... V>
void _print(T t, V... v) {
  __print(t);
  if (sizeof...(v)) cerr << ", ";
  _print(v...);
}
inline int max(int a, int b, int c) { return max(max(a, b), c); }
inline int min(int a, int b, int c) { return min(min(a, b), c); }
inline int max(int a, int b) { return (a > b) ? a : b; }
inline int min(int a, int b) { return (a < b) ? a : b; }
inline int mul(int x, int y, int mod_) {
  return ((x % mod_) * 1LL * (y % mod_)) % mod_;
}
int power(int a, int n) {
  int p = 1;
  while (n > 0) {
    if (n % 2) {
      p = p * a;
    }
    n >>= 1;
    a *= a;
  }
  return p;
}
int powm(int a, int n, int mod_) {
  int p = 1;
  while (n) {
    if (n % 2) {
      p = mul(p, a, mod_);
    }
    n >>= 1;
    a = mul(a, a, mod_);
  }
  return p % mod_;
}
int powi(int a, int mod_) { return powm(a, mod_ - 2, mod_); }
const int M = (int)(1e5 + 10), N = (int)(2e5 + 10);
map<int, int> grp[N];
vector<int> par, sz;
void make_set(int v) {
  par[v] = v;
  sz[v] = 1;
}
int find_set(int v) {
  if (par[v] == v) return v;
  return par[v] = find_set(par[v]);
}
void union_sets(int a, int b) {
  a = find_set(a);
  b = find_set(b);
  if (a != b) {
    if (sz[a] < sz[b]) swap(a, b);
    par[b] = a;
    sz[a] += sz[b];
  }
}
void ass(int n) {
  par.resize(n + 1);
  sz.resize(n + 1);
}
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  ;
  int mn, mx;
  int n, m, t, i, j, sum = 0, flag = 0, cnt = 0;
  int x = 0, y = 0, z, l = 0, r = 0, q;
  int TC = 1;
  while (TC--) {
    cin >> n >> m;
    ass(m + 2);
    for (i = 0; i < m + 2; ++i) make_set(i);
    for (i = 0; i < m; ++i) {
      cin >> x >> y >> z;
      int e1 = -1, e2 = -1;
      if (grp[x].count(z))
        e1 = grp[x][z];
      else
        grp[x][z] = i;
      if (grp[y].count(z))
        e2 = grp[y][z];
      else
        grp[y][z] = i;
      if (e1 >= 0) union_sets(i, e1);
      if (e2 >= 0) union_sets(i, e2);
    }
    cin >> q;
    map<pair<int, int>, int> dp;
    while (q--) {
      cin >> x >> y;
      if ((int)grp[x].size() > (int)grp[y].size()) swap(x, y);
      if (dp.find({x, y}) != dp.end()) {
        cout << dp[{x, y}] << '\n';
        continue;
      }
      cnt = 0;
      for (auto &z : grp[x]) {
        auto it = grp[y].find(z.first);
        if (it == grp[y].end()) continue;
        if (find_set(z.second) == find_set(it->second)) ++cnt;
      }
      dp[{x, y}] = cnt;
      if ((int)grp[x].size() == (int)grp[y].size()) dp[{y, x}] = cnt;
      cout << cnt << '\n';
    }
  };
  return 0;
}
