Let's define a forest as a non-directed acyclic graph (also without loops and parallel edges). One day Misha played with the forest consisting of n vertices. For each vertex v from 0 to n - 1 he wrote down two integers, degreev and sv, were the first integer is the number of vertices adjacent to vertex v, and the second integer is the XOR sum of the numbers of vertices adjacent to v (if there were no adjacent vertices, he wrote down 0). 

Next day Misha couldn't remember what graph he initially had. Misha has values degreev and sv left, though. Help him find the number of edges and the edges of the initial graph. It is guaranteed that there exists a forest that corresponds to the numbers written by Misha.

Input

The first line contains integer n (1 ≤ n ≤ 216), the number of vertices in the graph.

The i-th of the next lines contains numbers degreei and si (0 ≤ degreei ≤ n - 1, 0 ≤ si < 216), separated by a space.

Output

In the first line print number m, the number of edges of the graph.

Next print m lines, each containing two distinct numbers, a and b (0 ≤ a ≤ n - 1, 0 ≤ b ≤ n - 1), corresponding to edge (a, b).

Edges can be printed in any order; vertices of the edge can also be printed in any order.

Examples

Input

3
2 3
1 0
1 0


Output

2
1 0
2 0


Input

2
1 1
1 0


Output

1
0 1

Note

The XOR sum of numbers is the result of bitwise adding numbers modulo 2. This operation exists in many modern programming languages. For example, in languages C++, Java and Python it is represented as "^", and in Pascal — as "xor".
import java.io.*;
import java.util.*;

import static java.lang.Math.*;
import static java.util.Arrays.*;

// 12:59.292 + 9:14.413 + 3:10.261 + ?

public class ladders501c {
    static BufferedReader __in;
    static PrintWriter __out;
    static StringTokenizer input;

    public static void main(String[] args) throws IOException {
        __in = new BufferedReader(new InputStreamReader(System.in));
        __out = new PrintWriter(new OutputStreamWriter(System.out));

        int n = readInt();
        P2[] v = new P2[n];
//        Map<Integer, P> map = new HashMap<>();
        Queue<P2> q = new LinkedList<>();
        for(int i = 0; i < n; ++i) {
            read();
            v[i] = P2.mk(i, P.mk(nextInt(), nextInt()));
            if(v[i].b.a == 1) {
                q.offer(v[i]);
            }
//            map.put(i, v[i]);
        }
        List<P> ans = new ArrayList<>();
        while(!q.isEmpty()) {
            P2 p = q.poll();
            if(p.b.a == 0) {
                continue;
            }
//            println(p.a);
            ans.add(P.mk(p.a, p.b.b));
            v[p.b.b].b.b ^= p.a;
            if(--v[p.b.b].b.a == 1) {
                q.offer(v[p.b.b]);
            }
        }
        println(ans.size());
        for(P p : ans) {
            println(p.a, p.b);
        }


        close();
    }

    static List<Integer> toposort(List<List<Integer>> adjList, int[] indeg) {
        assert adjList.size() == indeg.length;
        int n = adjList.size();
        List<Integer> sorted = new ArrayList<>(n);
        Queue<Integer> q = new LinkedList<>();
        for(int i = 0; i < n; ++i) {
            if(indeg[i] == 0) {
                q.offer(i);
            }
        }
        while(!q.isEmpty()) {
            int i = q.poll();
            sorted.add(i);
            for(int j : adjList.get(i)) {
                if(--indeg[j] == 0) {
                    q.offer(j);
                }
            }
        }
        return sorted;
    }

    static List<Integer> toposort_full(List<List<Integer>> adjList, int[] indeg) {
        assert adjList.size() == indeg.length;
        int n = adjList.size();
        List<Integer> sorted = new ArrayList<>(n);
        Queue<Integer> q = new LinkedList<>();
        for(int i = 0; i < n; ++i) {
            if(indeg[i] == 0) {
                q.offer(i);
            }
        }
        while(!q.isEmpty()) {
            int i = q.poll();
            sorted.add(i);
            List<Integer> edges = adjList.get(i);
            for(int j = edges.size() - 1; j >= 0; --j) {
                int k = edges.get(j);
                if(--indeg[k] == 0) {
                    q.offer(k);
                }
                edges.remove(j);
            }
        }
        for(int i = 0; i < n; ++i) {
            if(adjList.size() > 0) {
                return null;
            }
        }
        return sorted;
    }

    static boolean toposort_check(List<List<Integer>> adjList, int[] indeg) {
        return toposort_full(adjList, indeg) != null;
    }

    static class P2 {
        int a;
        P b;

        P2(int a_, P b_) {
            a = a_;
            b = b_;
        }

        @Override
        public String toString() {
            return "Pair{" + "a = " + a + ", b = " + b.toString() + '}';
        }

        public static P2 mk(int a, P b) {
            return new P2(a, b);
        }

        public boolean equalsSafe(Object o) {
            if(this == o) return true;
            if(o == null || getClass() != o.getClass()) return false;
            P2 p = (P2)o;
            return a == p.a && Objects.equals(b, p.b);
        }

        public boolean equalsUnchecked(Object o) {
            P2 p = (P2)o;
            return a == p.a && b.equals(p.b);
        }

        @Override
        public boolean equals(Object o) {
            return equalsUnchecked(o);
        }

        @Override
        public int hashCode() {
            return Objects.hash(a, b);
        }
    }

    static class P {
        int a, b;

        P(int a_, int b_) {
            a = a_;
            b = b_;
        }

        @Override
        public String toString() {
            return "Pair{" + "a = " + a + ", b = " + b + '}';
        }

        public static P mk(int a, int b) {
            return new P(a, b);
        }

        public boolean equalsSafe(Object o) {
            if(this == o) return true;
            if(o == null || getClass() != o.getClass()) return false;
            P p = (P)o;
            return a == p.a && b == p.b;
        }

        public boolean equalsUnchecked(Object o) {
            P p = (P)o;
            return a == p.a && b == p.b;
        }

        @Override
        public boolean equals(Object o) {
            return equalsUnchecked(o);
        }

        @Override
        public int hashCode() {
            return Objects.hash(a, b);
        }
    }

    static final int IBIG = 1000000007;
    static final int IMAX = 2147483647;
    static final long LMAX = 9223372036854775807L;
    static void read() throws IOException {input = new StringTokenizer(__in.readLine());}
    static String readLine() throws IOException {return __in.readLine();}
    static int nextInt() {return Integer.parseInt(input.nextToken());}
    static int readInt() throws IOException {return Integer.parseInt(__in.readLine());}
    static void print(String s) {__out.print(s);}
    static void println(String s) {__out.println(s);}
    static void print(Object o) {__out.print(o);}
    static void println(Object o) {__out.println(o);}
    static void printy() {__out.println("Yes");}
    static void printY() {__out.println("YES");}
    static void printn() {__out.println("No");}
    static void printN() {__out.println("NO");}
    static void printyn(boolean b) {__out.println(b ? "Yes" : "No");}
    static void printYN(boolean b) {__out.println(b ? "YES" : "NO");}
    static void println(int... a) {for(int i = 0, len = a.length - 1; i < len; __out.print(a[i]), __out.print(' '), i++); __out.println(a[a.length - 1]);}
    static void println(long... a) {for(int i = 0, len = a.length - 1; i < len; __out.print(a[i]), __out.print(' '), i++); __out.println(a[a.length - 1]);}
    static void println() {__out.println();}
    static void close() {__out.close();}
}