Author has gone out of the stories about Vasiliy, so here is just a formal task description.

You are given q queries and a multiset A, initially containing only integer 0. There are three types of queries:

  1. "+ x" — add integer x to multiset A.
  2. "- x" — erase one occurrence of integer x from multiset A. It's guaranteed that at least one x is present in the multiset A before this query.
  3. "? x" — you are given integer x and need to compute the value <image>, i.e. the maximum value of bitwise exclusive OR (also know as XOR) of integer x and some integer y from the multiset A.



Multiset is a set, where equal elements are allowed.

Input

The first line of the input contains a single integer q (1 ≤ q ≤ 200 000) — the number of queries Vasiliy has to perform.

Each of the following q lines of the input contains one of three characters '+', '-' or '?' and an integer xi (1 ≤ xi ≤ 109). It's guaranteed that there is at least one query of the third type.

Note, that the integer 0 will always be present in the set A.

Output

For each query of the type '?' print one integer — the maximum value of bitwise exclusive OR (XOR) of integer xi and some integer from the multiset A.

Example

Input

10
+ 8
+ 9
+ 11
+ 6
+ 1
? 3
- 8
? 3
? 8
? 11


Output

11
10
14
13

Note

After first five operations multiset A contains integers 0, 8, 9, 11, 6 and 1.

The answer for the sixth query is integer <image> — maximum among integers <image>, <image>, <image>, <image> and <image>.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

	public static class Trie {

		TrieNode rootNode;
		final int max = 31;
		int gIndex = 0;

		class TrieNode {
			long val;
			int occurence;
			int index;
			TrieNode parent;
			TrieNode[] edges;

			public TrieNode() {
				val = -1;
				occurence = 0;
				edges = new TrieNode[2];
				edges[0] = edges[1] = null;
				index = gIndex++;
			}

			public TrieNode(TrieNode parent) {
				this();
				this.parent = parent;
			}
		}

		public Trie() {
			rootNode = new TrieNode();
		}

		public void addVertex(int number) {
			TrieNode temp = rootNode;

			int[] A = new int[max + 1];
			int curr = number;

			for (int i = 0; i <= max; i++) {
				A[i] = curr % 2;
				curr /= 2;
			}

			for (int i = max; i >= 0; i--) {

				if (temp.edges[A[i]] == null)
					temp.edges[A[i]] = new TrieNode(temp);

				temp = temp.edges[A[i]];
			}
			temp.val = number;
			temp.occurence++;
		}

		public long query(int number) {
			TrieNode temp = rootNode;
			int[] A = new int[max + 1];
			int curr = number;

			for (int i = 0; i <= max && curr != 0; i++) {
				A[i] = curr % 2;
				curr /= 2;
			}

			for (int i = max; i >= 0; i--) {
				int moveTo = A[i] ^ 1;

				if (temp.edges[moveTo] == null)
					moveTo ^= 1;

				temp = temp.edges[moveTo];
			}

			return number ^ temp.val;
		}

		public void removeVertex(int number) {
			TrieNode temp = rootNode;
			int[] A = new int[max + 1];
			int curr = number;

			for (int i = 0; i <= max; i++) {
				A[i] = curr % 2;
				curr /= 2;
			}

			for (int i = max; i >= 0; i--)
				temp = temp.edges[A[i]];

			temp.occurence--;
			if (temp.occurence != 0)
				return;

			TrieNode parent = temp.parent;
			int currBit = 0;

			while (parent.index != rootNode.index) {

				parent.edges[A[currBit]] = null;

				if (parent.edges[A[currBit++] ^ 1] != null)
					return;

				temp = parent;
				parent = parent.parent;
			}

		}
	}

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int n = Integer.parseInt(br.readLine());

		Trie trie = new Trie();
		trie.addVertex(0);
		while (n-- > 0) {

			String[] parts = br.readLine().split(" ");
			if (parts[0].charAt(0) == '+') {
				trie.addVertex(Integer.parseInt(parts[1]));
			} else if (parts[0].charAt(0) == '-') {
				trie.removeVertex(Integer.parseInt(parts[1]));
			} else if (parts[0].charAt(0) == '?') {
				System.out.println(trie.query(Integer.parseInt(parts[1])));
			}
		}
	}
}
