#include <bits/stdc++.h>
using namespace std;
int n;
int m;
struct query {
  int ty;
  int x;
  int y;
  int cs;
};
vector<query> Q;
int q;
struct uf {
  int dist[400002];
  int belong[400002];
  int sz[400002];
  vector<pair<int *, int> > ev;
  void change_xor(int &a, int val) {
    ev.push_back(make_pair(&a, a));
    a ^= val;
  }
  void change(int &a, int val) {
    ev.push_back(make_pair(&a, a));
    a = val;
  }
  uf() {
    memset(dist, 0, sizeof(dist));
    memset(belong, -1, sizeof(belong));
    memset(sz, 0, sizeof(sz));
    for (int i = 0; i < 400002; i++) sz[i] = 1;
  }
  inline int root(int b) {
    while (belong[b] != -1) {
      b = belong[b];
    }
    return b;
  }
  inline int dist2(int a) {
    int fa = a;
    int ret = 0;
    while (belong[a] != -1) {
      ret ^= dist[a];
      a = belong[a];
    }
    if (dist[a] != 0) {
      exit(fa);
    }
    return ret;
  }
  bool merge(int a, int b, int cost) {
    int lef = a;
    int rig = b;
    a = root(a);
    b = root(b);
    if (dist[a] != 0) {
      exit(dist[a]);
    }
    if (dist[b] != 0) {
      exit(dist[b]);
    }
    if (a == b) return false;
    if (sz[a] < sz[b]) {
      swap(a, b);
      swap(lef, rig);
    }
    int wf = dist2(rig) ^ dist2(lef);
    wf ^= cost;
    change_xor(dist[b], wf);
    change(belong[b], a);
    change(sz[a], sz[a] + sz[b]);
    if (dist[a] != 0) {
      exit(114);
    }
    return true;
  }
  inline void roll_back() {
    (*ev.back().first) = ev.back().second;
    ev.pop_back();
  }
};
map<tuple<int, int, int>, int> mp;
struct st {
  int from;
  int to;
  int cost;
  int star;
  int en;
};
vector<st> ed;
vector<st> seg[400002 * 10];
inline void add(int b, int l, int r, int ll, int rr, st ede) {
  if (r <= ll || rr <= l) return;
  if (ll <= l && r <= rr) {
    seg[b].push_back(ede);
    return;
  }
  add(b * 2 + 1, l, (l + r) >> 1, ll, rr, ede);
  add(b * 2 + 2, (l + r) >> 1, r, ll, rr, ede);
}
uf uff;
vector<int> g[400002 * 10];
void ins(vector<int> &v, int val) {
  for (int i = 0; i < v.size(); i++) {
    val = min(val, val ^ v[i]);
  }
  if (val) {
    v.push_back(val);
    sort(v.begin(), v.end(), greater<int>());
  }
}
int mini(vector<int> &v, int val) {
  for (int i = 0; i < v.size(); i++) {
    val = min(val, val ^ v[i]);
  }
  return val;
}
pair<int, int> know[400002 * 2];
vector<int> ans;
inline void dfs(int b, int l, int r, vector<int> &gs) {
  int pv = uff.ev.size();
  g[b] = gs;
  for (auto el : seg[b]) {
    bool ok = uff.merge(el.from, el.to, el.cost);
    if (ok == false) {
      int cyc = uff.dist2(el.from) ^ uff.dist2(el.to);
      cyc ^= el.cost;
      ins(g[b], cyc);
    }
  }
  if (l + 1 == r) {
    if (know[l].first != know[l].second) {
      int tmp = uff.dist2(know[l].first) ^ uff.dist2(know[l].second);
      ans.push_back(mini(g[b], tmp));
    }
  } else {
    dfs(b * 2 + 1, l, (l + r) >> 1, g[b]);
    dfs(b * 2 + 2, (l + r) >> 1, r, g[b]);
  }
  while (uff.ev.size() > pv) {
    uff.roll_back();
  }
}
int main() {
  cin >> n >> m;
  for (int i = 0; i < m; i++) {
    int x, y, d;
    scanf("%d%d%d", &x, &y, &d);
    x--;
    y--;
    if (x > y) swap(x, y);
    mp[make_tuple(x, y, d)] = 0;
  }
  cin >> q;
  int tim = 0;
  while (q--) {
    tim++;
    int ty, a, b, c;
    c = -1;
    scanf("%d%d%d", &ty, &a, &b);
    a--;
    b--;
    if (a > b) swap(a, b);
    if (ty == 1) {
      scanf("%d", &c);
      mp[make_tuple(a, b, c)] = tim;
    }
    if (ty == 2) {
      c = -1;
      auto it = mp.lower_bound(make_tuple(a, b, -1));
      int A, B, C;
      tie(A, B, C) = it->first;
      ed.push_back({A, B, C, it->second, tim});
      mp.erase(it);
    }
    if (ty == 3) {
      know[tim] = make_pair(a, b);
    }
    Q.push_back({ty, a, b, c});
  }
  tim++;
  for (auto it : mp) {
    int A, B, C;
    tie(A, B, C) = it.first;
    ed.push_back({A, B, C, it.second, tim});
  }
  for (int i = 0; i < ed.size(); i++) {
    add(0, 0, tim, ed[i].star, ed[i].en, ed[i]);
  }
  vector<int> emp;
  dfs(0, 0, tim, emp);
  for (int i = 0; i < ans.size(); i++) {
    printf("%d\n", ans[i]);
  }
  return 0;
}
