#include <bits/stdc++.h>
#pragma GCC optimize("O3")
using namespace std;
template <class c>
struct rge {
  c b, e;
};
template <class c>
rge<c> range(c i, c j) {
  return rge<c>{i, j};
}
template <class c>
auto dud(c* x) -> decltype(cerr << *x, 0);
template <class c>
char dud(...);
struct debug {
  template <class c>
  debug& operator<<(const c&) {
    return *this;
  }
};
map<int, int> g;
vector<int> list_compile[500123];
map<int, int> mine;
int nxt;
int main() {
  int q;
  scanf("%d", &q);
  int last = 0;
  while (q--) {
    int type;
    scanf("%d", &type);
    debug() << " ["
            << "mine"
               ": "
            << (mine)
            << "] "
               " ["
            << "g"
               ": "
            << (g)
            << "] "
               " ["
            << "list[0]"
               ": "
            << (list_compile[0])
            << "] "
               " ["
            << "list[2]"
               ": "
            << (list_compile[2])
            << "] "
               " ["
            << "list[4]"
               ": "
            << (list_compile[4]) << "] ";
    if (type == 1) {
      int L, R, x;
      scanf("%d%d%d", &L, &R, &x);
      L ^= last;
      R ^= last;
      x ^= last;
      if (L > R) {
        swap(L, R);
      }
      debug() << " ["
              << "type"
                 ": "
              << (type)
              << "] "
                 " ["
              << "L"
                 ": "
              << (L)
              << "] "
                 " ["
              << "R"
                 ": "
              << (R)
              << "] "
                 " ["
              << "x"
                 ": "
              << (x) << "] ";
      --L;
      auto it_L = g.find(L);
      auto it_R = g.find(R);
      if (it_L == g.end()) {
        g[L] = ++nxt;
        list_compile[nxt].push_back(L);
        it_L = g.find(L);
      }
      if (it_R == g.end()) {
        g[R] = ++nxt;
        list_compile[nxt].push_back(R);
        it_R = g.find(R);
      }
      if (it_L->second == it_R->second) {
        debug() << "ignore";
        continue;
      }
      if (list_compile[it_L->second].size() >
          list_compile[it_R->second].size()) {
        swap(L, R);
        swap(it_L, it_R);
      }
      int L_g = it_L->second;
      int R_g = it_R->second;
      debug() << " ["
              << "x"
                 ": "
              << (x) << "] ";
      x ^= mine[R] ^ mine[L];
      debug() << " ["
              << "x"
                 ": "
              << (x) << "] ";
      for (int a : list_compile[L_g]) {
        list_compile[R_g].push_back(a);
        g[a] = R_g;
        mine[a] ^= x;
      }
      list_compile[L_g].clear();
    } else {
      int L, R;
      scanf("%d%d", &L, &R);
      L ^= last;
      R ^= last;
      if (L > R) {
        swap(L, R);
      }
      debug() << " ["
              << "type"
                 ": "
              << (type)
              << "] "
                 " ["
              << "L"
                 ": "
              << (L)
              << "] "
                 " ["
              << "R"
                 ": "
              << (R) << "] ";
      --L;
      auto it_L = g.find(L);
      auto it_R = g.find(R);
      if (it_L == g.end() || it_R == g.end() || it_L->second != it_R->second) {
        puts("-1");
        last = 1;
        continue;
      }
      int answer = mine[L] ^ mine[R];
      printf("%d\n", answer);
      last = answer;
    }
  }
}
