#include <bits/stdc++.h>
using namespace std;
int Input() {
  char c = getchar();
  int x = 0, z = 1;
  for (; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
  for (; c >= '0' && c <= '9'; c = getchar())
    x = (x << 1) + (x << 3) + (c ^ 48);
  return x * z;
}
const int maxn(4e5 + 5);
struct Edge {
  int u, v, w;
} edge[maxn];
struct Qry {
  int u, v;
} qry[maxn];
vector<int> mdy[maxn << 2];
int n, m, q, top, tot, add[maxn], del[maxn], pw[31];
map<pair<int, int>, int> lst;
struct Info {
  int x, y, fa, dis, deep;
} sta[maxn];
struct Union {
  int fa[maxn], dis[maxn], deep[maxn];
  void Init() {
    for (int i = 1; i <= n; ++i) fa[i] = i;
  }
  pair<int, int> Find(int x) {
    int ret = 0;
    while (x != fa[x]) ret ^= dis[x], x = fa[x];
    return make_pair(x, ret);
  }
  int Merge(int x, int y, int w) {
    pair<int, int> u = Find(x), v = Find(y);
    if (u.first == v.first) return u.second ^ v.second ^ w;
    if (deep[u.first] > deep[v.first]) swap(u, v);
    sta[++top] =
        (Info){u.first, v.first, fa[u.first], dis[u.first], deep[v.first]};
    fa[u.first] = v.first;
    dis[u.first] = u.second ^ v.second ^ w;
    if (deep[u.first] == deep[v.first]) ++deep[v.first];
    return -1;
  }
} dsu;
struct Base {
  int x[31], num;
  void Insert(int v) {
    if (num == 31) return;
    for (int i = 30; ~i; --i)
      if (v & pw[i]) {
        if (!x[i]) {
          x[i] = v, ++num;
          return;
        }
        v ^= x[i];
      }
  }
  int Calc(int v) {
    for (int i = 30; ~i; --i) v = min(v, v ^ x[i]);
    return v;
  }
} base;
void Undo(int tp) {
  for (; top > tp; --top) {
    int x = sta[top].x, y = sta[top].y;
    dsu.fa[x] = sta[top].fa, dsu.dis[x] = sta[top].dis;
    dsu.deep[y] = sta[top].deep;
  }
}
void Modify(int o, int l, int r, int ql, int qr, int id) {
  if (ql > qr) return;
  if (ql <= l && qr >= r)
    mdy[o].push_back(id);
  else {
    int mid = (l + r) >> 1;
    if (ql <= mid) Modify(o << 1, l, mid, ql, qr, id);
    if (qr > mid) Modify(o << 1 | 1, mid + 1, r, ql, qr, id);
  }
}
void Solve(int o, int l, int r, Base bs) {
  int tp = top;
  for (int i = 0, l = mdy[o].size(); i < l; ++i) {
    int id = mdy[o][i], w;
    w = dsu.Merge(edge[id].u, edge[id].v, edge[id].w);
    if (w != -1) bs.Insert(w);
  }
  if (l == r) {
    int x = qry[l].u, y = qry[l].v, w = dsu.Merge(x, y, 0);
    printf("%d\n", bs.Calc(w));
  } else {
    int mid = (l + r) >> 1;
    Solve(o << 1, l, mid, bs), Solve(o << 1 | 1, mid + 1, r, bs);
  }
  Undo(tp);
}
int main() {
  pw[0] = 1;
  for (int i = 1; i < 31; ++i) pw[i] = pw[i - 1] << 1;
  n = Input(), m = Input(), dsu.Init();
  for (int i = 1; i <= m; ++i) {
    edge[i] = (Edge){Input(), Input(), Input()};
    if (edge[i].u > edge[i].v) swap(edge[i].u, edge[i].v);
    add[i] = 1, del[i] = -1;
    lst[make_pair(edge[i].u, edge[i].v)] = i;
  }
  q = Input();
  for (int i = 1; i <= q; ++i) {
    int op = Input();
    if (op == 1) {
      edge[++m] = (Edge){Input(), Input(), Input()};
      if (edge[m].u > edge[m].v) swap(edge[m].u, edge[m].v);
      add[m] = tot + 1, del[m] = -1;
      lst[make_pair(edge[m].u, edge[m].v)] = m;
    } else if (op == 2) {
      int u = Input(), v = Input(), id = lst[make_pair(u, v)];
      del[id] = tot;
    } else
      qry[++tot] = (Qry){Input(), Input()};
  }
  for (int i = 1; i <= m; ++i) {
    if (del[i] < 0) del[i] = tot;
    Modify(1, 1, tot, add[i], del[i], i);
  }
  Solve(1, 1, tot, base);
  return 0;
}
