Problem: This is an interactive problem. Remember to flush your output while communicating with the testing program. You may use fflush(stdout) in C++, system.out.flush() in Java, stdout.flush() in Python or flush(output) in Pascal to flush the output. If you use some other programming language, consult its documentation. You may also refer to the guide on interactive problems: <https://codeforces.com/blog/entry/45307>.

The jury guessed some array a consisting of 6 integers. There are 6 special numbers — 4, 8, 15, 16, 23, 42 — and each of these numbers occurs in a exactly once (so, a is some permutation of these numbers).

You don't know anything about their order, but you are allowed to ask up to 4 queries. In each query, you may choose two indices i and j (1 ≤ i, j ≤ 6, i and j are not necessarily distinct), and you will get the value of a_i ⋅ a_j in return.

Can you guess the array a?

The array a is fixed beforehand in each test, the interaction program doesn't try to adapt to your queries.

Interaction

Before submitting the answer, you may ask up to 4 queries. To ask a query, print one line in the following format: ? i j, where i and j should be two integers such that 1 ≤ i, j ≤ 6. The line should be ended with a line break character. After submitting a query, flush the output and read the answer to your query — one line containing one integer a_i ⋅ a_j. If you submit an incorrect query (or ask more than 4 queries), the answer to it will be one string 0. After receiving such an answer, your program should terminate immediately — otherwise you may receive verdict "Runtime error", "Time limit exceeded" or some other verdict instead of "Wrong answer".

To give the answer, your program should print one line ! a_1 a_2 a_3 a_4 a_5 a_6 with a line break in the end. After that, it should flush the output and terminate gracefully.

Example

Input


16
64
345
672

Output


? 1 1
? 2 2
? 3 5
? 4 6
! 4 8 15 16 23 42

Note

If you want to submit a hack for this problem, your test should contain exactly six space-separated integers a_1, a_2, ..., a_6. Each of 6 special numbers should occur exactly once in the test. The test should be ended with a line break character.

Solution (in JAVA):

Solution:
import java.io.BufferedWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.InputMismatchException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Scanner;
import java.util.TreeSet;

import javax.management.Query;

import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.file.attribute.AclEntry.Builder;
import java.io.IOException;
 
public class Main
{
	static InputStream inputStream = System.in;
	static OutputStream outputStream = System.out;
	static InputReader in = new InputReader(inputStream);
	static OutputWriter out = new OutputWriter(outputStream);
	
	static Map<Integer,Integer>l=new HashMap<Integer,Integer>();
	static Map<Integer,Integer>r=new HashMap<Integer,Integer>();
	static TreeSet<Integer> set=new TreeSet<Integer>();
	public static void main(String[] args)
	{
		Scanner sc=new Scanner(System.in);
		int val[]=new int[7];
		val[1]=4;val[2]=8;val[3]=15;val[4]=16;val[5]=23;val[6]=42;
		for(int i=1;i<=6;i++) 
		{
			set.add(i);
			for(int j=i+1;j<=6;j++) 
			{
				int mul=val[i]*val[j];
				//System.out.print(mul+" ");
				l.put(mul,i);r.put(mul,j);
			}
		}
		//32 60 64 92 168 120 128 184 336 240 345 630 368 672 966
		int an[]=new int[5];
		int bn[]=new int[7];
//		an[0]=64;
//		an[1]=128;
//		an[2]=184;
//		an[3]=966;
		System.out.println("? 1 2");
		an[0]=in.readInt();
		set.remove(l.get(an[0]));set.remove(r.get(an[0]));
		//System.out.println(l.get(an[0])+" "+r.get(an[0]));
		System.out.println("? 2 3");
		an[1]=in.readInt();
		set.remove(l.get(an[1]));set.remove(r.get(an[1]));
		//System.out.println(l.get(an[1])+" "+r.get(an[1]));
		System.out.println("? 3 4");
		an[2]=in.readInt();
		//System.out.println(l.get(an[2])+" "+r.get(an[2]));
		set.remove(l.get(an[2]));set.remove(r.get(an[2]));
		System.out.println("? 4 5");
		an[3]=in.readInt();
		//System.out.println(l.get(an[3])+" "+r.get(an[3]));
		set.remove(l.get(an[3]));set.remove(r.get(an[3]));
		//此时最后一个数是确定的；
		bn[6]=val[set.last()];
		int x1=l.get(an[0]),y1=r.get(an[0]);
		int x2=l.get(an[1]),y2=r.get(an[1]);
		if(x1==x2) {bn[2]=val[x1];bn[1]=val[y1];bn[3]=val[y2];}
		else if(x1==y2) {bn[2]=val[x1];bn[1]=val[y1];bn[3]=val[x2];}
		else if(y1==x2){bn[2]=val[y1];bn[1]=val[x1];bn[3]=val[y2];}
		else if(y1==y2) {bn[2]=val[y1];bn[1]=val[x1];bn[3]=val[x2];}
		//此时bn[1] bn[2] bn[3 ]是确定的
		x1=l.get(an[2]);y1=r.get(an[2]);
		if(val[x1]==bn[3]) {bn[4]=val[y1];}
		else {bn[4]=val[x1];}
		x1=l.get(an[3]);y1=r.get(an[3]);
		if(val[x1]==bn[4]) {bn[5]=val[y1];}
		else {bn[5]=val[x1];}
		out.print("!");
		for(int i=1;i<=6;i++) 
		{
			out.print(" "+bn[i]);
		}
		out.close();
	}
}
 
 
//封装基于字节流读取的高效输入类InputReader，避免Scanner的低效率，比streamTokenizer快读还快；
class InputReader
{
	// java.io.InputStream 所有字节输入流的父类
	private InputStream stream;
	// 输入缓存byte数组
	private byte[] buf = new byte[1024];
	private int curChar;// 当前字符
	private int numChars;// 总输入字符
	// 自定义接口
	private SpaceCharFilter filter;
 
	// 构造函数
	public InputReader(InputStream stream)
	{
		this.stream = stream;
	}
 
	//尝试至少读取一个字节并存储到缓冲数组buf中
	public int read()
	{
		if (numChars == -1)throw new InputMismatchException();
		//既然是缓冲读取，如果1次读取1024个，那么每次直接缓冲区读取 如果curChar<numChar 那么证明缓冲区的还没有用完
		if (curChar >= numChars)
		{
			curChar = 0;//缓冲区的数据用完了，那么从0开始，再去一次性读取若干个放到缓冲数组里
			try
			{
				// 从输入流中读取一定数量的字节，并将其存储在缓冲区数组buf中，numChar等于实际读取的字节数量
				numChars = stream.read(buf);
			} 
			catch (IOException e)
			{
				throw new InputMismatchException();
			}
			if (numChars <= 0)//如果读取的有效数量为0，那么返回-1，巧妙的避开了合法的ASCII码
				return -1;
		}
		//等价于else (curChar<numChar),如果缓冲区没有用完，直接返回缓冲区当前第curChar字符，指针后移
		return buf[curChar++];
	}
 
	//读入一个一个字节，手工构造int
	public int readInt()
	{
		int c = read();
		while (isSpaceChar(c))//忽略>=1的所有空格符或者自己定义的不能构成整数的无意义符号入\n\r\t等
			c = read();
		int sgn = 1;//识别第一符号位，判定是正数还是负数
		if (c == '-')
		{
			sgn = -1;
			c = read();
		}
		int res = 0;
		do
		{
			if (c < '0' || c > '9')
				throw new InputMismatchException();
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		//不断的*10+当前数构成int的判断
		return res * sgn;
	}
 
	//读入一个一个字节，手工构造long
	public long readLong()
	{
		int c = read();
		while (isSpaceChar(c))
			c = read();
		int sgn = 1;
		if (c == '-')
		{
			sgn = -1;
			c = read();
		}
		long res = 0;
		do
		{
			if (c < '0' || c > '9')
				throw new InputMismatchException();
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}
 
	//高效的读取字符串
	public String readString()
	{
		int c = read();
		while (isSpaceChar(c))
			c = read();
		StringBuilder res = new StringBuilder();
		do
		{
			//确定指定的代码点是否是一个有效的Unicode代码点值
			if (Character.isValidCodePoint(c))
				res.appendCodePoint(c);//追加Unicode代码点值
			c = read();
		} while (!isSpaceChar(c));
		return res.toString();
	}
	//统一Scanner的语法习惯
	public String next()
	{
		return readString();
	}
	//读入一行字符串数组
	public static String[] readStringArray(InputReader in, int size) 
	{
		String[] array = new String[size];
		for (int i = 0; i < size; i++)
			array[i] = in.readString();
		return array;
	}
	//读入二维字符数组
	public static String[][] readStringTable(InputReader in, int rowCount, int columnCount) 
	{
		String[][] table = new String[rowCount][];
		for (int i = 0; i < rowCount; i++)
			table[i] = readStringArray(in, columnCount);
		return table;
	}
	//读入char
	public char readCharacter()
	{
		int c = read();
		while (isSpaceChar(c))
			c = read();
		return (char) c;
	}
	//读入一行字符串
	public String readStringLine()
	{
		int c = read();
		while (isSpaceChar2(c))
			c = read();
		StringBuilder res = new StringBuilder();
		do
		{
			//确定指定的代码点是否是一个有效的Unicode代码点值
			if (Character.isValidCodePoint(c))
				res.appendCodePoint(c);//追加Unicode代码点值
			c = read();
		} while (!isSpaceChar2(c));
		return res.toString();
	}
	
	//读入double
	public double readDouble()
	{
		int c = read();
		while (isSpaceChar(c))
			c = read();
		int sgn = 1;
		if (c == '-')
		{
			sgn = -1;
			c = read();
		}
		double res = 0;
		while (!isSpaceChar(c) && c != '.')
		{
			if (c == 'e' || c == 'E')
				return res * Math.pow(10, readInt());
			if (c < '0' || c > '9')
				throw new InputMismatchException();
			res *= 10;
			res += c - '0';
			c = read();
		}
		if (c == '.')
		{
			c = read();
			double m = 1;
			while (!isSpaceChar(c))
			{
				if (c == 'e' || c == 'E')
					return res * Math.pow(10, readInt());
				if (c < '0' || c > '9')
					throw new InputMismatchException();
				m /= 10;
				res += (c - '0') * m;
				c = read();
			}
		}
		return res * sgn;
	}
	public boolean isSpaceChar(int c)
	{
		if (filter != null)
			return filter.isSpaceChar(c);
		return isWhitespace(c);
	}
	
	public boolean isSpaceChar2(int c)
	{
		if (filter != null)
			return filter.isSpaceChar2(c);
		return isWhitespace2(c);
	}
	//可以输入空格的一行
	public static boolean isWhitespace2(int c)
	{
		return c == '\n' || c == '\r' || c == '\t' || c == -1;
	}
 
	public static boolean isWhitespace(int c)
	{
		return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
	}
 
	// 自定义接口，定了一个抽象方法判断是否是空格符
	public interface SpaceCharFilter
	{
		public boolean isSpaceChar(int ch);
		
		public boolean isSpaceChar2(int ch);
	}
}
 
 
class OutputWriter
{
	//向文本输出流打印对象的格式化表现形式 extends java.io.Writer
	private final PrintWriter writer;
 
	public OutputWriter(OutputStream outputStream)
	{
		writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
				outputStream)));
	}
//打印数组用空格分隔
	public void print(int[] array)
	{
		for (int i = 0; i < array.length; i++)
		{
			if (i != 0)
				writer.print(' ');
			writer.print(array[i]);
		}
	}
//带换行的数组打印
	public void printLine(int[] array)
	{
		print(array);
		writer.println();
	}
 
	public void print(Object... objects)
	{
		for (int i = 0; i < objects.length; i++)
		{
			if (i != 0)
				writer.print(' ');
			writer.print(objects[i]);
		}
	}
 
	public void printLine(Object... objects)
	{
		print(objects);
		writer.println();
	}
 
	public void close()
	{
		writer.close();
	}
	public void print(int i)
	{
		writer.print(i);
	}
	public void print(String i)
	{
		writer.print(i);
	}
	public void print(long i)
	{
		writer.print(i);
	}
	public void print(char i)
	{
		writer.print(i);
	}
	public void printf(String format,Object... x)
	{
		writer.printf(format,x);
	}
//打印带换行的整数i
	public void printLine(int i)
	{
		writer.println(i);
	}	
	public void printLine(long i) 
	{
		writer.println(i);
	}
}
 
class IOUtils
{
//高效读入整型一维数组
	public static int[] readIntArray(InputReader in, int size)
	{
		int[] array = new int[size];
		for (int i = 0; i < size; i++)
			array[i] = in.readInt();
		return array;
	}
	//调用上面的读入一维数组的快速读取二维数组
	public static int[][] readIntTable(InputReader in, int rowCount, int columnCount) {
		int[][] table = new int[rowCount][];
		for (int i = 0; i < rowCount; i++)
			table[i] = readIntArray(in, columnCount);
		return table;
	}
	//相当于二维数组（多关键字参数的另外一种写法）
	public static void readIntArrays(InputReader in, int[]... arrays)
	{
		for (int i = 0; i < arrays[0].length; i++)
		{
			for (int j = 0; j < arrays.length; j++)
				arrays[j][i] = in.readInt();
		}
	}
	
	public static char[] readCharArray(InputReader in, int size)
	{
		char[] array = new char[size];
		for (int i = 0; i < size; i++)
			array[i] = in.readCharacter();
		return array;
	}
 
	public static char[][] readTable(InputReader in, int rowCount,int columnCount)
	{
		char[][] table = new char[rowCount][];
		for (int i = 0; i < rowCount; i++)
			table[i] = readCharArray(in, columnCount);
		return table;
	}
 
}
class MiscUtils
{
	public static void decreaseByOne(int[]... arrays)
	{
		for (int[] array : arrays)
		{
			for (int i = 0; i < array.length; i++)
				array[i]--;
		}
	}
 
}