Problem: After some programming contest Roma decided to try himself in tourism. His home country Uzhlyandia is a Cartesian plane. He wants to walk along each of the Main Straight Lines in Uzhlyandia. It is known that each of these lines is a straight line parallel to one of the axes (i.e. it is described with the equation x = a or y = a, where a is integer called the coordinate of this line).

Roma lost his own map, so he should find out the coordinates of all lines at first. Uncle Anton agreed to help him, using the following rules: 

  * Initially Roma doesn't know the number of vertical and horizontal lines and their coordinates; 
  * Roma can announce integer coordinates of some point in Uzhlandia, and Anton then will tell him the minimum among the distances from the chosen point to each of the lines. However, since the coordinates of the lines don't exceed 108 by absolute value, Roma can't choose a point with coordinates exceeding 108 by absolute value. 



Uncle Anton is in a hurry to the UOI (Uzhlandian Olympiad in Informatics), so he can only answer no more than 3·105 questions.

The problem is that Roma doesn't know how to find out the coordinates of the lines. Write a program that plays Roma's role and finds the coordinates.

Input

There is no input initially. Your program should make queries to get information.

It is guaranteed that the number of horizontal and vertical lines is at least 1 and less than or equal to 104 for each type.

Interaction

To make a query, print a line "0 x y" (-108 ≤ x, y ≤ 108), where x and y are the coordinates of the point. After each query you need to print end-of-line, make "flush" operation, and then read the answer to the query — the minimum among the distances prom this point to the Main Straight Lines of Uzhlyandia.

You can do no more than 3·105 queries.

When you are ready to print the answer, print three lines:

  1. In the first line print "1 n m", where n is the number of vertical lines (parallel to OY), and m is the number of horizontal lines (parallel to OX). 
  2. In the second line print n integers x1, x2, ..., xn — the coordinates of the vertical lines. 
  3. In the third line in the same format print m integers y1, y2, ..., ym — the coordinates of the horizontal lines. 



You can print coordinates in arbitrary order.

To make "flush", you can use (just after printing a query/answer and end-of-line):

  * fflush(stdout) in C++; 
  * System.out.flush() in Java; 
  * stdout.flush() in Python; 
  * flush(output) in Pascal; 
  * see the documentation for other languages. 



You will get Wrong Answer if you make more queries than allowed or make an invalid query. 

You can get Idleness Limit Exceeded if you don't print anything or if you forget to flush the output.

If at any moment your program reads -1 as an answer, it should immediately exit normally (for example, by calling exit(0)). You will get Wrong Answer in this case, it means that you made more queries than allowed, or made an invalid query. If you ignore this, you can get other verdicts since your program will continue to read from a closed stream.

Making test for hacking

The first line should contain two integers n and m (1 ≤ n, m ≤ 104).

The second line should contain n distinct integers xi (-108 ≤ xi ≤ 108) — the coordinates of the vertical lines.

The third line should contain m distinct integers yi (-108 ≤ yi ≤ 108) — the coordinates of the horizontal lines.

You can write coordinates in arbitrary order.

You can see the example case in the notes.

Example

Input

1
1
3
2


Output

0 1 2
0 -2 -2
0 5 6
0 -2 2
1 1 2
2
0 -3

Note

The example test is 
    
    
      
    1 2  
    2  
    0 -3  
    

The minimum distances are:

  * from (1, 2) to x = 2; 
  * from ( - 2, - 2) to y = - 3; 
  * from (5, 6) to x = 2; 
  * from ( - 2, 2) to y = 0. 

Solution (in JAVA):

Solution:
import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.stream.IntStream;
import java.util.PriorityQueue;
import java.util.AbstractQueue;
import java.util.Random;
import java.util.ArrayList;
import java.io.OutputStreamWriter;
import java.io.OutputStream;
import java.util.Collection;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.List;
import java.util.stream.Stream;
import java.io.Closeable;
import java.io.Writer;
import java.util.Comparator;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(null, new TaskAdapter(), "", 1 << 29);
        thread.start();
        thread.join();
    }

    static class TaskAdapter implements Runnable {
        @Override
        public void run() {
            InputStream inputStream = System.in;
            OutputStream outputStream = System.out;
            FastInput in = new FastInput(inputStream);
            FastOutput out = new FastOutput(outputStream);
            DFindingLines solver = new DFindingLines();
            solver.solve(1, in, out);
            out.close();
        }
    }

    static class DFindingLines {
        int interval = 19000;
        int inf = (int) 1e8;
        Comparator<Interval> comp = (a, b) -> a.len == b.len ? Integer.compare(a.l, b.l) : -Integer.compare(a.len, b.len);
        PriorityQueue<Interval> ySet = new PriorityQueue<>((int) 1e4, comp);
        List<Integer> xLines = new ArrayList<>();
        FastInput in;
        FastOutput out;
        RandomWrapper rw = new RandomWrapper(new Random());
        int limit = (int) 3e5;

        public void solve(int testNumber, FastInput in, FastOutput out) {
            this.in = in;
            this.out = out;
            clear();
            for (int i = -inf; i <= inf; i += interval) {
                int l = i;
                int r = Math.min(inf, i + interval - 1);
                check(new Interval(l, r), false, 0);
            }
            xLines.sort(Comparator.naturalOrder());
            int[] xArrays = xLines.stream()
                    .mapToInt(Integer::intValue).toArray();

            clear();
            ySet.clear();
            int left = -inf;
            for (int x : xArrays) {
                Interval interval = new Interval(left, x - 1);
                if (!interval.isEmpty()) {
                    ySet.add(interval);
                }
                left = x + 1;
            }
            {
                Interval interval = new Interval(left, inf);
                if (!interval.isEmpty()) {
                    ySet.add(interval);
                }
            }

            for (int i = -inf; i <= inf; i += interval) {
                int l = i;
                int r = Math.min(inf, i + interval - 1);
                check(new Interval(l, r), true, 0);
            }
            xLines.sort(Comparator.naturalOrder());
            int[] yArrays = xLines.stream()
                    .mapToInt(Integer::intValue).toArray();

            out.printf("1 %d %d", xArrays.length, yArrays.length).println();
            for (int x : xArrays) {
                out.append(x).append(' ');
            }
            out.println();
            for (int y : yArrays) {
                out.append(y).append(' ');
            }
            out.println().flush();
        }

        public void clear() {
            ySet.clear();
            xLines.clear();
            ySet.add(new Interval(-inf, inf));
        }

        public void check(Interval x, boolean inv, int depth) {
            if (x.isEmpty()) {
                return;
            }

            Interval y = ySet.peek();
            int cx = x.middle();
            int cy = y.middle();
            int dist = ask(cx, cy, inv);

            if (!(cx - dist >= x.l || cx + dist <= x.r)) {
                return;
            }

            if (cx - dist >= x.l && exist(cx - dist, inv, 3)) {
                xLines.add(cx - dist);
                for (Interval interval : x.split(cx - dist)) {
                    check(interval, inv, depth + 1);
                }
                return;
            }

            if (dist != 0 && cx + dist <= x.r && exist(cx + dist, inv, 3)) {
                xLines.add(cx + dist);
                for (Interval interval : x.split(cx + dist)) {
                    check(interval, inv, depth + 1);
                }
                return;
            }

            if (cy - dist >= y.l && exist(cy - dist, !inv, 3)) {
                ySet.remove();
                for (Interval interval : y.split(cy - dist)) {
                    if (!interval.isEmpty()) {
                        ySet.add(interval);
                    }
                }
                check(x, inv, depth + 1);
                return;
            }

            if (dist != 0 && cy + dist <= y.r && exist(cy + dist, !inv, 3)) {
                ySet.remove();
                for (Interval interval : y.split(cy + dist)) {
                    if (!interval.isEmpty()) {
                        ySet.add(interval);
                    }
                }
                check(x, inv, depth + 1);
                return;
            }


        }

        public boolean exist(int x, boolean inv, int time) {
            for (int i = 0; i < time - 1; i++) {
                int y1 = rw.nextInt(-inf, inf);
                if (ask(x, y1, inv) != 0) {
                    return false;
                }
            }
            return true;
        }

        public int ask(int x, int y, boolean inv) {
            if (inv) {
                int tmp = x;
                x = y;
                y = tmp;
            }

            if (limit-- == 0) {
                throw new RuntimeException();
            }

            out.append("0 ").append(x).append(' ').append(y).println().flush();
            return in.readInt();
        }

    }

    static class Interval {
        int l;
        int r;
        int len;

        public int middle() {
            return (r + l) / 2;
        }

        public Interval(int l, int r) {
            this.l = l;
            this.r = r;
            this.len = r - l + 1;
        }

        public boolean isEmpty() {
            return r < l;
        }

        public Interval[] split(int x) {
            return new Interval[]{new Interval(l, x - 1), new Interval(x + 1, r)};
        }

        public String toString() {
            return String.format("[%d, %d]", l, r);
        }

    }

    static class FastOutput implements AutoCloseable, Closeable, Appendable {
        private StringBuilder cache = new StringBuilder(10 << 20);
        private final Writer os;

        public FastOutput append(CharSequence csq) {
            cache.append(csq);
            return this;
        }

        public FastOutput append(CharSequence csq, int start, int end) {
            cache.append(csq, start, end);
            return this;
        }

        public FastOutput(Writer os) {
            this.os = os;
        }

        public FastOutput(OutputStream os) {
            this(new OutputStreamWriter(os));
        }

        public FastOutput append(char c) {
            cache.append(c);
            return this;
        }

        public FastOutput append(int c) {
            cache.append(c);
            return this;
        }

        public FastOutput append(String c) {
            cache.append(c);
            return this;
        }

        public FastOutput printf(String format, Object... args) {
            cache.append(String.format(format, args));
            return this;
        }

        public FastOutput println() {
            cache.append(System.lineSeparator());
            return this;
        }

        public FastOutput flush() {
            try {
                os.append(cache);
                os.flush();
                cache.setLength(0);
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
            return this;
        }

        public void close() {
            flush();
            try {
                os.close();
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }

        public String toString() {
            return cache.toString();
        }

    }

    static class FastInput {
        private final InputStream is;
        private byte[] buf = new byte[1 << 13];
        private int bufLen;
        private int bufOffset;
        private int next;

        public FastInput(InputStream is) {
            this.is = is;
        }

        private int read() {
            while (bufLen == bufOffset) {
                bufOffset = 0;
                try {
                    bufLen = is.read(buf);
                } catch (IOException e) {
                    bufLen = -1;
                }
                if (bufLen == -1) {
                    return -1;
                }
            }
            return buf[bufOffset++];
        }

        public void skipBlank() {
            while (next >= 0 && next <= 32) {
                next = read();
            }
        }

        public int readInt() {
            int sign = 1;

            skipBlank();
            if (next == '+' || next == '-') {
                sign = next == '+' ? 1 : -1;
                next = read();
            }

            int val = 0;
            if (sign == 1) {
                while (next >= '0' && next <= '9') {
                    val = val * 10 + next - '0';
                    next = read();
                }
            } else {
                while (next >= '0' && next <= '9') {
                    val = val * 10 - next + '0';
                    next = read();
                }
            }

            return val;
        }

    }

    static class RandomWrapper {
        private Random random;

        public RandomWrapper() {
            this(new Random());
        }

        public RandomWrapper(Random random) {
            this.random = random;
        }

        public int nextInt(int l, int r) {
            return random.nextInt(r - l + 1) + l;
        }

    }
}