#include <bits/stdc++.h>
using namespace std;
inline int read() {
  int f = 1, x = 0;
  char ch;
  do {
    ch = getchar();
    if (ch == '-') f = -1LL;
  } while (ch < '0' || ch > '9');
  do {
    x = x * 10 + ch - '0';
    ch = getchar();
  } while (ch >= '0' && ch <= '9');
  return f * x;
}
template <class T>
inline void chmax(T &a, T b) {
  if (a < b) a = b;
}
template <class T>
inline void chmin(T &a, T b) {
  if (a > b) a = b;
}
inline void swap(int &a, int &b) {
  int c = a;
  a = b;
  b = c;
}
using namespace std;
const int N = 2e5 + 10;
int n, m;
vector<int> base;
inline void add(int x) {
  vector<int>::iterator it = base.begin();
  for (; it != base.end(); ++it) x = min(x, x ^ (*it));
  if (x) {
    it = base.begin();
    for (; it != base.end(); ++it) *it = min(*it, (*it) ^ x);
    base.push_back(x);
  }
}
inline int query(int x) {
  vector<int>::iterator it = base.begin();
  for (; it != base.end(); ++it) x = min(x, x ^ *it);
  return x;
}
struct DSU {
  int fa[N], ra[N], w[N];
  stack<pair<int *, int> > s;
  inline void init(int n) {
    for (int i = (1); i <= (n); ++i) fa[i] = i, ra[i] = w[i] = 0;
  }
  inline int find(int x) {
    while (x != fa[x]) x = fa[x];
    return x;
  }
  inline int get(int x) {
    int ret = 0;
    while (x != fa[x]) ret = ret ^ w[x], x = fa[x];
    return ret;
  }
  inline int merge(int x, int y, int z) {
    int fx = find(x), fy = find(y);
    if (fx == fy)
      return 0;
    else {
      if (ra[fx] < ra[fy]) {
        s.push(make_pair(&w[fx], w[fx]));
        w[fx] = get(x) ^ get(y) ^ z;
        s.push(make_pair(&fa[fx], fa[fx]));
        fa[fx] = fy;
      } else {
        s.push(make_pair(&w[fy], w[fy]));
        w[fy] = get(x) ^ get(y) ^ z;
        s.push(make_pair(&fa[fy], fa[fy]));
        fa[fy] = fx;
        if (ra[fx] == ra[fy]) {
          s.push(make_pair(&ra[fx], ra[fx]));
          ++ra[fx];
        }
      }
    }
    return 1;
  }
  inline void rollback(int x) {
    while (s.size() > x) {
      *s.top().first = s.top().second;
      s.pop();
    }
  }
} dsu;
int x[N], y[N], d[N], op[N];
vector<vector<int> > sm[N << 2];
inline void cover(int cur, int L, int R, int l, int r, int x, int y, int d) {
  if (l <= L && r >= R) {
    vector<int> tmp;
    tmp.push_back(x);
    tmp.push_back(y);
    tmp.push_back(d);
    sm[cur].push_back(tmp);
    return;
  }
  int mid = (L + R) >> 1;
  if (l <= mid) cover(cur << 1, L, mid, l, r, x, y, d);
  if (r > mid) cover(cur << 1 | 1, mid + 1, R, l, r, x, y, d);
}
inline void solve(int cur, int l, int r) {
  int mid = (l + r) >> 1, sz = (int)dsu.s.size();
  vector<int> tbase = base;
  for (int i = (0); i <= ((int)(sm[cur].size()) - 1); ++i) {
    int x = sm[cur][i][0], y = sm[cur][i][1], w = sm[cur][i][2];
    if (!dsu.merge(x, y, w)) add(dsu.get(x) ^ dsu.get(y) ^ w);
  }
  if (l == r) {
    if (op[l] == 3) printf("%d\n", query(dsu.get(x[l]) ^ dsu.get(y[l])));
  } else {
    solve(cur << 1, l, mid);
    solve(cur << 1 | 1, mid + 1, r);
  }
  dsu.rollback(sz);
  base = tbase;
}
int main() {
  n = read();
  m = read();
  map<pair<int, int>, pair<int, int> > t;
  for (int i = (1); i <= (m); ++i) {
    int u = read(), v = read(), w = read();
    t[make_pair(u, v)] = make_pair(w, 0);
  }
  int q = read();
  for (int i = (1); i <= (q); ++i) {
    op[i] = read();
    if (op[i] == 1) {
      x[i] = read(), y[i] = read(), d[i] = read();
      t[make_pair(x[i], y[i])] = make_pair(d[i], i);
    } else if (op[i] == 2) {
      x[i] = read(), y[i] = read();
      pair<int, int> tt = t[make_pair(x[i], y[i])];
      cover(1, 0, q, tt.second, i - 1, x[i], y[i], tt.first);
      t.erase(make_pair(x[i], y[i]));
    } else {
      x[i] = read(), y[i] = read();
    }
  }
  map<pair<int, int>, pair<int, int> >::iterator it = t.begin();
  for (; it != t.end(); ++it) {
    cover(1, 0, q, it->second.second, q, it->first.first, it->first.second,
          it->second.first);
  }
  dsu.init(n);
  solve(1, 0, q);
  return 0;
}
