#include <bits/stdc++.h>
using namespace std;
const int MAXE = 100000;
const int LARGESZ = 450;
int from[MAXE], to[MAXE], clr[MAXE];
struct DSU {
  int n;
  int *p;
  DSU(int n) : n(n) {
    p = (int *)malloc(sizeof(int) * n);
    for (int i = 0; i < (n); i++) p[i] = i;
  }
  ~DSU() {}
  int get(int i) {
    assert(0 <= i && i < n);
    if (p[i] == i) return i;
    return p[i] = get(p[i]);
  }
  void unite(int a, int b) {
    a = get(a);
    b = get(b);
    if (rand() % 2) swap(a, b);
    p[a] = b;
  }
};
int isLarge[MAXE];
vector<int> sets[MAXE];
vector<int> sid[MAXE];
vector<int> cur[MAXE];
DSU *dsu[MAXE];
vector<int> large;
vector<vector<unsigned> > largeInfo;
int res[MAXE / LARGESZ + 1][MAXE / LARGESZ + 1];
const int SZ = 16;
char bitcnt[1 << SZ];
int _bitcnt(int n) {
  int res = 0;
  while (n) {
    res += n & 1;
    n >>= 1;
  }
  return res;
}
int main() {
  for (int i = 0; i < (1 << SZ); i++) bitcnt[i] = _bitcnt(i);
  int n, m;
  scanf("%d%d", &n, &m);
  for (int i = 0; i < (m); i++) {
    scanf("%d%d%d", &from[i], &to[i], &clr[i]);
    from[i]--;
    to[i]--;
    clr[i]--;
  }
  for (int i = 0; i < (m); i++) {
    cur[clr[i]].push_back(from[i]);
    cur[clr[i]].push_back(to[i]);
  }
  for (int i = 0; i < (m); i++) {
    if (cur[i].empty()) continue;
    sort(cur[i].begin(), cur[i].end());
    cur[i].erase(unique(cur[i].begin(), cur[i].end()), cur[i].end());
    dsu[i] = new DSU(cur[i].size());
  }
  for (int i = 0; i < (m); i++) {
    int a = from[i];
    int b = to[i];
    int c = clr[i];
    a = lower_bound(cur[c].begin(), cur[c].end(), a) - cur[c].begin();
    b = lower_bound(cur[c].begin(), cur[c].end(), b) - cur[c].begin();
    assert(0 <= a && a < (int)cur[c].size());
    assert(0 <= b && b < (int)cur[c].size());
    dsu[c]->unite(a, b);
  }
  int top = 0;
  for (int i = 0; i < (m); i++) {
    if (cur[i].empty()) continue;
    int maxv = 0;
    for (int j = 0; j < (cur[i].size()); j++) {
      sets[cur[i][j]].push_back(i);
      sid[cur[i][j]].push_back(top + dsu[i]->get(j));
    }
    top += cur[i].size();
  }
  for (int i = 0; i < (n); i++)
    if (sets[i].size() >= LARGESZ) {
      isLarge[i] = true;
      large.push_back(i);
    }
  largeInfo.resize(large.size());
  int bucketCnt = (top + 31) / 32;
  for (int i = 0; i < (large.size()); i++) {
    largeInfo[i].resize(bucketCnt);
    for (int j = 0; j < (sets[large[i]].size()); j++) {
      int id = sid[large[i]][j];
      largeInfo[i][id / 32] |= (1U << (id % 32));
    }
  }
  for (int i = 0; i < (large.size()); i++)
    for (int j = 0; j < (i); j++) {
      int cnt = 0;
      for (int k = 0; k < (bucketCnt); k++) {
        unsigned val = largeInfo[i][k] & largeInfo[j][k];
        cnt += bitcnt[val & ((1 << 16) - 1)] + bitcnt[((unsigned)val) >> 16];
      }
      res[i][j] = res[j][i] = cnt;
    }
  int q;
  scanf("%d", &q);
  while (q--) {
    int u, v;
    scanf("%d%d", &u, &v);
    u--;
    v--;
    if (!isLarge[u] || !isLarge[v]) {
      if (isLarge[u]) swap(u, v);
      int curRes = 0;
      for (int i = 0; i < sets[u].size(); i++) {
        int id = sets[u][i];
        int tu =
            lower_bound(cur[id].begin(), cur[id].end(), u) - cur[id].begin();
        int tv =
            lower_bound(cur[id].begin(), cur[id].end(), v) - cur[id].begin();
        if (tv < cur[id].size() && cur[id][tv] == v &&
            dsu[id]->get(tu) == dsu[id]->get(tv))
          curRes++;
      }
      printf("%d\n", curRes);
    } else {
      u = lower_bound(large.begin(), large.end(), u) - large.begin();
      v = lower_bound(large.begin(), large.end(), v) - large.begin();
      printf("%d\n", res[u][v]);
    }
  }
  return 0;
}
