#include <bits/stdc++.h>
using namespace std;
inline int read() {
  int x = 0;
  bool t = false;
  char ch = getchar();
  while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
  if (ch == '-') t = true, ch = getchar();
  while (ch <= '9' && ch >= '0') x = x * 10 + ch - 48, ch = getchar();
  return t ? -x : x;
}
struct xxj {
  int p[31];
  void insert(int x) {
    for (int i = 30; ~i; --i)
      if (x & (1 << i)) {
        if (!p[i]) {
          p[i] = x;
          break;
        }
        x ^= p[i];
      }
  }
  int Query(int x) {
    for (int i = 30; ~i; --i) x = min(x, x ^ p[i]);
    return x;
  }
} G;
struct Node {
  int u, v, w;
} p[200200 << 1];
pair<int, int> q[200200];
int n, m;
map<pair<int, int>, int> M;
vector<Node> seg[200200 << 2];
void Modify(int now, int l, int r, int L, int R, Node e) {
  if (L > R) return;
  if (L <= l && r <= R) {
    seg[now].push_back(e);
    return;
  }
  int mid = (l + r) >> 1;
  if (L <= mid) Modify((now << 1), l, mid, L, R, e);
  if (R > mid) Modify((now << 1 | 1), mid + 1, r, L, R, e);
}
int tim, cnt, L[200200 << 1], R[200200 << 1];
int f[200200], sz[200200], Xor[200200];
int getf(int x) {
  while (x != f[x]) x = f[x];
  return x;
}
int getxor(int x) {
  int ret = 0;
  while (x != f[x]) ret ^= Xor[x], x = f[x];
  return ret;
}
void Divide(int now, int l, int r, xxj G) {
  vector<Node> c;
  c.clear();
  for (int i = 0, lim = seg[now].size(); i < lim; ++i) {
    int u = seg[now][i].u, v = seg[now][i].v, w = seg[now][i].w;
    int f1 = getf(u), f2 = getf(v);
    if (f1 == f2)
      G.insert(getxor(u) ^ getxor(v) ^ w);
    else {
      if (sz[f1] > sz[f2]) swap(f1, f2), swap(u, v);
      w ^= getxor(v) ^ getxor(u);
      c.push_back((Node){f1, f2, sz[f2]});
      Xor[f1] = w;
      f[f1] = f2;
      sz[f2] += sz[f1];
    }
  }
  if (l == r)
    printf("%d\n", G.Query(getxor(q[l].first) ^ getxor(q[l].second)));
  else {
    int mid = (l + r) >> 1;
    Divide((now << 1), l, mid, G);
    Divide((now << 1 | 1), mid + 1, r, G);
  }
  for (int i = c.size() - 1; ~i; --i) {
    int u = c[i].u, v = c[i].v, w = c[i].w;
    sz[v] = w;
    f[u] = u;
    Xor[u] = 0;
  }
}
int main() {
  n = read();
  m = read();
  for (int i = 1; i <= m; ++i) {
    int x = read(), y = read(), w = read();
    p[++cnt] = (Node){x, y, w};
    L[cnt] = 1;
    M[make_pair(x, y)] = cnt;
    R[cnt] = -1;
  }
  int Q = read();
  for (int i = 1; i <= Q; ++i) {
    int opt = read(), x = read(), y = read();
    if (x > y) swap(x, y);
    if (opt == 1) {
      p[++cnt] = (Node){x, y, read()};
      L[cnt] = tim + 1;
      R[cnt] = -1;
      M[make_pair(x, y)] = cnt;
    } else if (opt == 2)
      R[M[make_pair(x, y)]] = tim;
    else
      q[++tim] = make_pair(x, y);
  }
  for (int i = 1; i <= cnt; ++i)
    if (R[i] == -1) R[i] = tim;
  for (int i = 1; i <= cnt; ++i) Modify(1, 1, tim, L[i], R[i], p[i]);
  for (int i = 1; i <= n; ++i) f[i] = i, sz[i] = 1;
  Divide(1, 1, tim, G);
  return 0;
}
