#include <algorithm>  
#include <iostream>  
#include <sstream>  
#include <string>  
#include <vector>  
#include <queue>  
#include <set>  
#include <map>  
#include <cstdio>  
#include <cstdlib>  
#include <cctype>  
#include <cmath>  
#include <cstring>
#include <list>  
#include <cassert>
#include <climits>
#include <bitset>
#include <chrono>
#include <random>
using namespace std;

#define PB push_back  
#define MP make_pair  
#define SZ(v) ((int)(v).size())  
#define FOR(i,a,b) for(int i=(a);i<(b);++i)  
#define REP(i,n) FOR(i,0,n)  
#define FORE(i,a,b) for(int i=(a);i<=(b);++i)  
#define REPE(i,n) FORE(i,0,n)  
#define FORSZ(i,a,v) FOR(i,a,SZ(v))  
#define REPSZ(i,v) REP(i,SZ(v))  
std::mt19937 rnd((int)std::chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }

const int NCHAR = 62;
const int MAXLEN = 128;
const int MAXQ = 850;
const char CHARS[NCHAR + 1] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWYXZ0123456789";

int cnt[NCHAR];
int len;

char ans[MAXLEN + 1];

int nq;
bool local = false;
string locans;

void upd(int& a, int b) { a = min(a, b); }
int calcdist(const string& a, const string& b) {
	int alen = SZ(a), blen = SZ(b);
	vector<vector<int>> dp(alen + 1, vector<int>(blen + 1, INT_MAX));
	dp[0][0] = 0;
	REP(i, alen) REP(j, blen) if (dp[i][j] != INT_MAX) {
		if (i < alen) upd(dp[i + 1][j], dp[i][j] + 1);
		if (j < blen) upd(dp[i][j + 1], dp[i][j] + 1);
		if (i < alen && j < blen) upd(dp[i + 1][j + 1], dp[i][j] + (a[i] == b[j] ? 0 : 1));
	}
	return dp[alen][blen];
}

int query(string s) {
	++nq;
	if (!local) {
		printf("? %s\n", s.c_str()); fflush(stdout);
		int ret; scanf("%d", &ret); return ret;
	} else {
		//printf("%s\n", s.c_str());
		return calcdist(s, locans);
	}
}

int known;
int rec(vector<int> opt, char c, int lim) {
	assert(SZ(opt) >= 1); assert(lim >= 1);
	if (SZ(opt) == 1) {
		int idx = opt[0];
		ans[idx] = c, ++known;
		return 1;
	}
	int m = SZ(opt) / 2;
	vector<int> lopt, ropt; REPSZ(i, opt) if (i < m) lopt.PB(opt[i]); else ropt.PB(opt[i]);
	string s(len, '?'); REP(j, len) s[j] = ans[j];
	REPSZ(k, lopt) s[lopt[k]] = c;
	REP(j, len) if (s[j] == '?') s[j] = CHARS[0];
	int cur = query(s);
	int ret = 0;
	if (cur == len - known) {
		ret+=rec(ropt, c, lim);
	} else {
		ret += rec(lopt, c, len - known - cur);
		if (lim > ret) ret += rec(ropt, c, lim - ret);
	}
	return ret;
}

void solve() {
	REP(i, NCHAR) cnt[i] = MAXLEN - query(string(MAXLEN, CHARS[i]));
	len = 0; REP(i, NCHAR) len += cnt[i];
	REP(j, len) ans[j] = '?'; ans[len] = '\0';
	known = 0;
	REP(j, len) {
		string s(len, CHARS[1]); s[j] = CHARS[0];
		int cur = query(s);
		if (cur == len - cnt[1] - 1) ans[j] = CHARS[0], ++known;
	}
	FOR(i, 1, NCHAR) {
		if (cnt[i] == 0) continue;
		vector<int> opt; REP(j, len) if (ans[j] == '?') opt.PB(j);
		rec(opt, CHARS[i], cnt[i]);
		//printf("ans=%s\n", ans);
	}
}

void run() {
	solve();
	printf("! %s\n", ans); fflush(stdout);
}

void test() {
	local = true;
	cin >> locans;
	solve();
	printf("%s\n", ans);
}

void stress() {
	local = true;
	REP(rep, 1000) {
		int len = MAXLEN; // rnd() % MAXLEN + 1;
		locans = string(len, '?'); REP(i, len) locans[i] = CHARS[rnd() % NCHAR];
		nq = 0;
		solve();
		printf("%d\n", nq);
		assert(string(ans) == locans);
		assert(nq <= MAXQ);
	}
}

int main() {
	run();
	//test();
	//stress();
	return 0;
}


Measured memory_bytes: 3800