#include <bits/stdc++.h>
using namespace std;
struct edge {
  int u, v, w;
};
struct Node {
  int x, y, r;
};
struct query {
  int u, v;
};
const int N = 4e5 + 10;
struct rollbackDSU {
  int p[N], rankk[N], dist[N];
  stack<Node> st;
  void init(int n) {
    for (int i = 1; i <= n; i++) p[i] = i, rankk[i] = 0, dist[i] = 0;
    while (!st.empty()) st.pop();
  }
  int find(int x) {
    while (x != p[x]) x = p[x];
    return x;
  }
  bool same(int x, int y) { return find(x) == find(y); }
  int getdist(int x) {
    int d = 0;
    while (x != p[x]) d ^= dist[x], x = p[x];
    return d;
  }
  void unite(int x, int y, int val) {
    int fx = find(x), fy = find(y);
    if (rankk[fx] > rankk[fy]) swap(fx, fy);
    st.push((Node){fx, fy, rankk[fy]});
    if (rankk[fx] == rankk[fy]) rankk[fy]++;
    dist[fx] = getdist(x) ^ getdist(y) ^ val;
    p[fx] = fy;
  }
  void rollback(int x) {
    for (int i = 1; i <= x; i++) {
      Node y = st.top();
      st.pop();
      p[y.x] = y.x;
      rankk[y.y] = y.y;
      dist[y.x] = 0;
    }
  }
};
struct Basis {
  int d[32];
  void init() {
    for (int i = 0; i < 31; i++) d[i] = 0;
  }
  void insert(int x) {
    for (int i = 30; ~i; i--) {
      if (x & (1 << i)) {
        if (d[i])
          x ^= d[i];
        else {
          d[i] = x;
          return;
        }
      }
    }
  }
  int query(int x = 0) {
    int ans = x;
    for (int i = 30; ~i; i--) {
      if ((ans ^ d[i]) < ans) ans ^= d[i];
    }
    return ans;
  }
};
edge E[N];
vector<int> rec[N << 2];
query Q[N];
int ans[N];
rollbackDSU dsu;
Basis bs;
map<pair<int, int>, int> sav;
map<pair<int, int>, int> wt;
void update(int ql, int qr, int id, int rt, int l, int r) {
  if (ql <= l && r <= qr) {
    rec[rt].push_back(id);
    return;
  }
  int mid = (l + r) >> 1;
  if (ql <= mid) update(ql, qr, id, rt << 1, l, mid);
  if (qr > mid) update(ql, qr, id, rt << 1 | 1, mid + 1, r);
}
void dfs(int rt, int l, int r, Basis bs) {
  int sz = (int)rec[rt].size(), id, cnt = 0, u, v, w;
  for (int i = 0; i < sz; i++) {
    id = rec[rt][i];
    u = E[id].u;
    v = E[id].v;
    w = E[id].w;
    if (dsu.same(u, v))
      bs.insert(dsu.getdist(u) ^ dsu.getdist(v) ^ w);
    else {
      dsu.unite(u, v, w);
      cnt++;
    }
  }
  if (l == r)
    ans[l] = bs.query(dsu.getdist(Q[l].u) ^ dsu.getdist(Q[l].v));
  else {
    int mid = (l + r) >> 1;
    dfs(rt << 1, l, mid, bs);
    dfs(rt << 1 | 1, mid + 1, r, bs);
  }
  dsu.rollback(cnt);
}
int main() {
  int n, m, q, tot, tim, u, v, w, ty;
  scanf("%d %d", &n, &m);
  dsu.init(n);
  bs.init();
  tot = 0;
  tim = 0;
  for (int i = 1; i <= m; i++) {
    scanf("%d %d %d", &u, &v, &w);
    sav[{u, v}] = 1;
    wt[{u, v}] = w;
  }
  scanf("%d", &q);
  for (int i = 1; i <= q; i++) {
    scanf("%d", &ty);
    if (ty == 1) {
      scanf("%d %d %d", &u, &v, &w);
      sav[{u, v}] = tim + 1;
      wt[{u, v}] = w;
    } else if (ty == 2) {
      scanf("%d %d", &u, &v);
      if (sav[{u, v}] <= tim) {
        w = wt[{u, v}];
        E[++tot] = (edge){u, v, w};
        update(sav[{u, v}], tim, tot, 1, 1, q);
      }
      sav.erase({u, v});
    } else {
      scanf("%d %d", &u, &v);
      Q[++tim] = (query){u, v};
    }
  }
  for (auto it : sav) {
    u = it.first.first;
    v = it.first.second;
    w = wt[{u, v}];
    E[++tot] = (edge){u, v, w};
    update(it.second, q, tot, 1, 1, q);
  }
  dfs(1, 1, q, bs);
  for (int i = 1; i <= tim; i++) printf("%d\n", ans[i]);
  return 0;
}
