#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <unistd.h>
using namespace std;
typedef pair<int, int> pii;
typedef vector<pii> vi;
typedef vector<vi> vii;
typedef pair<double, int> P;
// func and term
enum {IF_FOOD_AHEAD, PROG2, PROG3, RIGHT, LEFT, MOVE};
// vector
enum {U, R, D, L};
// gen mode
enum {FULL, GROW};
// variants
int n, e, cnt, foods[55][55], FOODS[55][55], ant[55][55], nx, ny, nz, tmp;
string mp[55], MP[55];
vii node;
//int runcnt;
class Tree {
public:
int antx, anty;
int Energy, food;
int vec;
// int szs;
bool isans;
int adr, nid;
double badrate;
Tree(bool in, int id) {
antx = anty = 0;
Energy = e;
food = 0;
vec = R;
isans = in;
badrate = 0.0;
adr = 0;
nid=id;
// szs = node[nid].size();
}
void run() {
// runcnt++;
// printf("%d\n",runcnt);
if (adr >= node[nid].size()) return;
if (Energy == 0) return;
switch (node[nid][adr].first) {
case IF_FOOD_AHEAD:
if_Food_Ahead();
break;
case PROG2:
Prog2();
break;
case PROG3:
Prog3();
break;
case RIGHT:
case LEFT:
change_vec();
break;
case MOVE:
move();
break;
}
}
void if_Food_Ahead() {
nx=antx;
ny=anty;
if (vec == U) ny--;
else if (vec == R) nx++;
else if (vec == D) ny++;
else nx--;
if (nx<0||nx>=n||ny<0||ny>=n||!foods[ny][nx]) {
adr++;
trav();
run();
} else {
adr++;
if (node[nid][adr].first==MOVE) badrate+=0.5;
tmp = node[nid][adr].second;
run();
adr = tmp;
}
}
void Prog2() {
adr++;
tmp = node[nid][adr].second;
nx=node[nid][adr].first;
run();
ny=node[nid][adr].first;
run();
tmp = adr;
// printf("%d %d\n",nx,ny);
if ((nx==RIGHT&&ny==LEFT) || (ny==RIGHT&&nx==LEFT)) badrate+=1.0;
}
void Prog3() {
adr++;
nx=node[nid][adr].first;
run();
ny=node[nid][adr].first;
run();
nz=node[nid][adr].first;
run();
if ((nx==RIGHT&&ny==LEFT)||(ny==RIGHT&&nx==LEFT)) badrate+=1.0;
if ((ny==RIGHT&&nz==LEFT)||(nz==RIGHT&&ny==LEFT)) badrate+=1.0;
}
void change_vec() {
Energy--;
if (node[nid][adr].first == RIGHT) vec = (vec + 1) % 4;
else vec = (vec + 3) % 4;
adr++;
if (isans) {
puts("");
for (int i=0; i<n; i++) for (int j=0; j<n; j++) {
if (i == anty && j == antx) {
if (vec == 0) printf("^");
else if (vec == 1) printf(">");
else if (vec == 2) printf("v");
else printf("<");
} else {
printf("%c",mp[i][j]);
}
if (j == n - 1) puts("");
}
puts("");
usleep(1000*500);
}
}
void move() {
Energy--;
nx = antx;
ny = anty;
if (vec == U) ny--;
else if (vec == R) nx++;
else if (vec == D) ny++;
else nx--;
if (nx<0||ny>=n||ny<0||ny>=n) badrate+=1.0;
else {
antx=nx; anty=ny;
if (ant[anty][antx]) badrate += 0.5;
if (foods[anty][antx]) {
food++;
mp[anty][antx] = '.';
foods[anty][antx] = 0;
}
ant[anty][antx] = 1;
}
adr++;
if (isans) {
puts("");
for (int i=0; i<n; i++) for (int j=0; j<n; j++) {
if (i == anty && j == antx) {
if (vec == 0) printf("^");
else if (vec == 1) printf(">");
else if (vec == 2) printf("v");
else printf("<");
} else {
printf("%c",mp[i][j]);
}
if (j == n - 1) puts("");
}
puts("");
usleep(1000*500);
}
}
void trav() {
if (adr >= node[nid].size()) return;
switch (node[nid][adr].first) {
case IF_FOOD_AHEAD:
case PROG2:
adr++;
trav(); trav();
break;
case PROG3:
adr++;
trav(); trav(); trav();
break;
case RIGHT:
case LEFT:
case MOVE:
adr++;
break;
}
}
};
///////////////////////////////////////////////////////////////
int pa;
void printnode(int nid) {
if (node[nid][pa].first==IF_FOOD_AHEAD) {
pa++;
printf("f(");
printnode(nid);
printf(",");
printnode(nid);
printf(")");
} else if (node[nid][pa].first==PROG2) {
pa++;
printnode(nid);
printnode(nid);
} else if (node[nid][pa].first==PROG3) {
pa++;
printnode(nid);
printnode(nid);
printnode(nid);
} else if (node[nid][pa].first==RIGHT) {
pa++;
printf("r");
} else if (node[nid][pa].first==LEFT) {
pa++;
printf("l");
} else {
pa++;
printf("m");
}
}
void mapinit() {
for (int i=0; i<n; i++) {
mp[i] = MP[i];
for (int j=0; j<n; j++) {
foods[i][j] = FOODS[i][j];
ant[i][j] = 0;
}
}
ant[0][0] = 1;
}
int getsize(int nid) {
return node[nid].size();
}
double evalution(int nid) {
Tree tree(false, nid);
mapinit();
tree.run();
return (double)tree.food*100-tree.badrate-(double)getsize(nid)/100.0;
}
int calcfood(int nid) {
Tree tree(false, nid);
mapinit();
tree.run();
return tree.food;
}
// generate random node
int ga;
void gen_rnd_node(int nid, int depth, int max_d, int method) {
double r = (double)(rand() % 10 + 1) / 10.0;
if (max_d == depth || (depth > 1 && method == GROW && r < 0.5)) {
int rc = rand() % 3 + 3;
node[nid].push_back(make_pair(rc,0));
node[nid][node[nid].size()-1].second=node[nid].size();
} else {
int rc = rand() % 3;
node[nid].push_back(make_pair(rc,0));
ga=node[nid].size()-1;
gen_rnd_node(nid,depth+1,max_d,method);
gen_rnd_node(nid,depth+1,max_d,method);
if (rc==PROG3) gen_rnd_node(nid,depth+1,max_d,method);
node[nid][ga].second=node[nid].size();
}
}
class Func {
public:
// crossover
int crosscnt, crossadr[2];
vector<bool> cr1, cr2;
int c1, c2, c3, c4;
void find_same(int nid1, int nid2) {
if (crossadr[0]<getsize(nid1)||crossadr[1]<getsize(nid2)) return;
crosscnt++;
cr1[crossadr[0]] = cr2[crossadr[1]] = true;
if (node[nid1][crossadr[0]].first<=PROG2&&
node[nid2][crossadr[1]].first<=PROG2) {
crossadr[0]++; crossadr[1]++;
find_same(nid1,nid2);
find_same(nid1,nid2);
} else if (node[nid1][crossadr[0]].first==PROG3&&
node[nid2][crossadr[1]].first==PROG3) {
crossadr[0]++; crossadr[1]++;
find_same(nid1,nid2);
find_same(nid1,nid2);
find_same(nid1,nid2);
} else {
tmp = node[nid1][crossadr[0]].second;
crossadr[0] = tmp;
tmp = node[nid2][crossadr[1]].second;
crossadr[1] = tmp;
}
}
void unite_pos(int nid1, int nid2, int r) {
if (crosscnt==r) {
c1=crossadr[0];
c3=node[nid1][c1].second;
c2=crossadr[1];
c4=node[nid2][c2].second;
return;
}
crosscnt++;
if (node[nid1][crossadr[0]].first<=PROG2&&
node[nid2][crossadr[1]].first<=PROG2) {
crossadr[0]++; crossadr[1]++;
unite_pos(nid1,nid2,r);
unite_pos(nid1,nid2,r);
} else if (node[nid1][crossadr[0]].first==PROG3&&
node[nid2][crossadr[1]].first==PROG3) {
crossadr[0]++; crossadr[1]++;
unite_pos(nid1,nid2,r);
unite_pos(nid1,nid2,r);
unite_pos(nid1,nid2,r);
} else {
tmp = node[nid1][crossadr[0]].second;
crossadr[0]=tmp;
tmp=node[nid2][crossadr[1]].second;
crossadr[1]=tmp;
}
}
void crossover(int nid1, int nid2, int cid1, int cid2) {
crosscnt = 0;
cr1.resize(node[nid1].size(), false);
cr2.resize(node[nid2].size(), false);
crossadr[0]=crossadr[1]=0;
find_same(nid1, nid2);
if (crosscnt > 1) {
// puts("find same");
crossadr[0] = crossadr[1] = 0;
int r = rand() % (crosscnt-1) + 1;
crosscnt = 0;
unite_pos(nid1, nid2, r);
copy(node[nid1].begin(), node[nid1].begin()+c1, back_inserter(node[cid1]));
copy(node[nid2].begin(), node[nid2].begin()+c2, back_inserter(node[cid2]));
copy(node[nid1].begin()+c1, node[nid1].begin()+c3, back_inserter(node[cid2]));
copy(node[nid2].begin()+c2, node[nid2].begin()+c4, back_inserter(node[cid1]));
copy(node[nid1].begin()+c3, node[nid1].end(), back_inserter(node[cid1]));
copy(node[nid2].begin()+c4, node[nid2].end(), back_inserter(node[cid2]));
} else if (crosscnt == 1) {
// puts("find same");
crosscnt=0;
crossadr[0] = crossadr[1] = 0;
unite_pos(nid1, nid2, 1);
copy(node[nid1].begin(), node[nid1].begin()+c1, back_inserter(node[cid1]));
copy(node[nid2].begin(), node[nid2].begin()+c2, back_inserter(node[cid2]));
copy(node[nid1].begin()+c1, node[nid1].begin()+c3, back_inserter(node[cid2]));
copy(node[nid2].begin()+c2, node[nid2].begin()+c4, back_inserter(node[cid1]));
copy(node[nid1].begin()+c3, node[nid1].end(), back_inserter(node[cid1]));
copy(node[nid2].begin()+c4, node[nid2].end(), back_inserter(node[cid2]));;
}
}
// mutation
int mutcnt;
void mutrun(int togen, int fromgen, int depth, int r) {
if (mutcnt == r) {
gen_rnd_node(togen, depth+1, 20, GROW);
tmp = node[fromgen][mutcnt].second;
mutcnt = tmp;
}
if (mutcnt >= getsize(fromgen)) return;
node[togen].push_back(node[fromgen][mutcnt]);
int flag = node[fromgen][mutcnt].first;
mutcnt++;
if (flag<=PROG3) {
mutrun(togen, fromgen, depth+1, r);
mutrun(togen, fromgen, depth+1, r);
if (flag==PROG3) mutrun(togen,fromgen,depth+1,r);
}
}
void mutation(int ngen, int rgen) {
int sz = getsize(rgen);
if (sz!=0) {
int r = rand() % sz;
while (r == 0) r = rand() % sz;
mutcnt = 0;
// printf("%d\n",sz);
mutrun(ngen, rgen, 0, r);
}
}
};
// generation
static int SZ=100, GENE=1000, TSZ=2;
vector<P> dn;
Func func;
void initialisation() {
node.resize(SZ*2, vi(0));
for (int i=0; i<SZ; i++) {
gen_rnd_node(i,0,5,FULL);
}
}
int tournament() {
set<int> st;
while (st.size() < TSZ) {
int r = rand() % SZ;
st.insert(r);
}
set<int>::iterator it;
vector<P> dnx;
for (it=st.begin(); it!=st.end(); it++) {
dnx.push_back(P(evalution((*it)), (*it)));
}
sort(dnx.begin(), dnx.end());
return dnx[TSZ-1].second;
}
void run_cross(int ngen) {
int r1 = tournament();
int r2 = tournament();
if (ngen+1>=node.size()) node.push_back(vi(0));
if (ngen+2>=node.size()) node.push_back(vi(0));
func.crossover(r1,r2,ngen+1,ngen+2);
int e1 = evalution(ngen+1);
int e2 = evalution(ngen+2);
if (e1 > e2) {
copy(node[ngen+1].begin(), node[ngen+1].end(), back_inserter(node[ngen]));
} else {
copy(node[ngen+2].begin(), node[ngen+2].end(), back_inserter(node[ngen]));
}
node[ngen+1].clear();
node[ngen+2].clear();
}
void calc_gen() {
dn.clear();
for (int i=0; i<SZ; i++) {
dn.push_back(P(evalution(i), i));
}
sort(dn.begin(), dn.end());
}
int gp(int gennum) {
calc_gen();
if (gennum >= GENE) {
return dn[SZ-1].second;
}
double r=(double)(rand()%1000+1)/1000.0;
int ngen = SZ;
while (ngen<SZ*2) {
if (r<0.05) {
int rm= rand() % SZ;
// puts("mutation");
func.mutation(ngen, rm);
} else if (r<0.1) {
// puts("tournament");
int t = tournament();
copy(node[t].begin(), node[t].end(), back_inserter(node[ngen]));
} else {
// puts("crossover");
run_cross(ngen);
}
ngen++;
r=(double)(rand()%1000+1)/1000.0;
}
// puts("hyouji");
usleep(1000*200);
for (int i=0; i<SZ; i++) {
node[i].clear();
copy(node[i+SZ].begin(), node[i+SZ].end(), back_inserter(node[i]));
node[i+SZ].clear();
}
for (int i=0; i<SZ/10; i++) {
printf("generation %d: ", gennum + 1);
for (int j=i*10; j<min(SZ,(i+1)*10); j++) {
printf("%d(%.3f) ", calcfood(j), evalution(j));
}
puts("");
}
return gp(gennum + 1);
}
int main() {
srand((unsigned int)time(NULL));
scanf("%d%d",&n, &e);
for (int i=0; i<n; i++) cin>>MP[i];
for (int i=0; i<n; i++) {
mp[i] = MP[i];
for (int j=0; j<n; j++) {
if (MP[i][j] == '#') FOODS[i][j] = foods[i][j] = 1;
}
}
initialisation();
// runcnt=0;
for (int i=0; i<SZ/10; i++) {
printf("generation %d: ", 0);
for (int j=i*10; j<min(SZ,(i+1)*10); j++) {
printf("%d(%.3f) ", calcfood(j), evalution(j));
}
puts("");
}
int ans = gp(0);
mapinit();
Tree tree(true, ans);
tree.run();
printf("result: food=%d Energy=%d evalution=%.3f\n",tree.food,tree.Energy,evalution(ans));
printnode(ans);
puts("");
// test();
}
I2luY2x1ZGUgPGNzdGRpbz4KI2luY2x1ZGUgPGNzdGRsaWI+CiNpbmNsdWRlIDxjc3RyaW5nPgojaW5jbHVkZSA8Y3RpbWU+CiNpbmNsdWRlIDxpb3N0cmVhbT4KI2luY2x1ZGUgPGFsZ29yaXRobT4KI2luY2x1ZGUgPHZlY3Rvcj4KI2luY2x1ZGUgPG1hcD4KI2luY2x1ZGUgPHNldD4KI2luY2x1ZGUgPHVuaXN0ZC5oPgp1c2luZyBuYW1lc3BhY2Ugc3RkOwp0eXBlZGVmIHBhaXI8aW50LCBpbnQ+IHBpaTsKdHlwZWRlZiB2ZWN0b3I8cGlpPiB2aTsKdHlwZWRlZiB2ZWN0b3I8dmk+IHZpaTsKdHlwZWRlZiBwYWlyPGRvdWJsZSwgaW50PiBQOwoKLy8gZnVuYyBhbmQgdGVybQplbnVtIHtJRl9GT09EX0FIRUFELCBQUk9HMiwgUFJPRzMsIFJJR0hULCBMRUZULCBNT1ZFfTsKLy8gdmVjdG9yCmVudW0ge1UsIFIsIEQsIEx9OwovLyBnZW4gbW9kZQplbnVtIHtGVUxMLCBHUk9XfTsKLy8gdmFyaWFudHMKaW50IG4sIGUsIGNudCwgZm9vZHNbNTVdWzU1XSwgRk9PRFNbNTVdWzU1XSwgYW50WzU1XVs1NV0sIG54LCBueSwgbnosIHRtcDsKc3RyaW5nIG1wWzU1XSwgTVBbNTVdOwp2aWkgbm9kZTsKLy9pbnQgcnVuY250OwoKY2xhc3MgVHJlZSB7CnB1YmxpYzoKICBpbnQgYW50eCwgYW50eTsKICBpbnQgRW5lcmd5LCBmb29kOwogIGludCB2ZWM7CiAgLy8gIGludCBzenM7CiAgYm9vbCBpc2FuczsKICBpbnQgYWRyLCBuaWQ7CiAgZG91YmxlIGJhZHJhdGU7CiAgVHJlZShib29sIGluLCBpbnQgaWQpIHsKCWFudHggPSBhbnR5ID0gMDsKCUVuZXJneSA9IGU7Cglmb29kID0gMDsKCXZlYyA9IFI7Cglpc2FucyA9IGluOwoJYmFkcmF0ZSA9IDAuMDsKCWFkciA9IDA7CgluaWQ9aWQ7CgkvLwlzenMgPSBub2RlW25pZF0uc2l6ZSgpOwogIH0KICB2b2lkIHJ1bigpIHsKCS8vCXJ1bmNudCsrOwoJLy8JcHJpbnRmKCIlZFxuIixydW5jbnQpOwoJaWYgKGFkciA+PSBub2RlW25pZF0uc2l6ZSgpKSByZXR1cm47CglpZiAoRW5lcmd5ID09IDApIHJldHVybjsKCXN3aXRjaCAobm9kZVtuaWRdW2Fkcl0uZmlyc3QpIHsKCWNhc2UgSUZfRk9PRF9BSEVBRDoKCSAgaWZfRm9vZF9BaGVhZCgpOwoJICBicmVhazsKCWNhc2UgUFJPRzI6CgkgIFByb2cyKCk7CgkgIGJyZWFrOwoJY2FzZSBQUk9HMzoKCSAgUHJvZzMoKTsKCSAgYnJlYWs7CgljYXNlIFJJR0hUOgoJY2FzZSBMRUZUOgoJICBjaGFuZ2VfdmVjKCk7CgkgIGJyZWFrOwoJY2FzZSBNT1ZFOgoJICBtb3ZlKCk7CgkgIGJyZWFrOwoJfQogIH0KICB2b2lkIGlmX0Zvb2RfQWhlYWQoKSB7CglueD1hbnR4OwoJbnk9YW50eTsKCWlmICh2ZWMgPT0gVSkgbnktLTsKCWVsc2UgaWYgKHZlYyA9PSBSKSBueCsrOwoJZWxzZSBpZiAodmVjID09IEQpIG55Kys7CgllbHNlIG54LS07CglpZiAobng8MHx8bng+PW58fG55PDB8fG55Pj1ufHwhZm9vZHNbbnldW254XSkgewoJICBhZHIrKzsKCSAgdHJhdigpOwoJICBydW4oKTsKCX0gZWxzZSB7CgkgIGFkcisrOwoJICBpZiAobm9kZVtuaWRdW2Fkcl0uZmlyc3Q9PU1PVkUpIGJhZHJhdGUrPTAuNTsKCSAgdG1wID0gbm9kZVtuaWRdW2Fkcl0uc2Vjb25kOwoJICBydW4oKTsKCSAgYWRyID0gdG1wOwoJfQogIH0KICB2b2lkIFByb2cyKCkgewoJYWRyKys7Cgl0bXAgPSBub2RlW25pZF1bYWRyXS5zZWNvbmQ7CglueD1ub2RlW25pZF1bYWRyXS5maXJzdDsKCXJ1bigpOwoJbnk9bm9kZVtuaWRdW2Fkcl0uZmlyc3Q7CglydW4oKTsKCXRtcCA9IGFkcjsKCS8vCXByaW50ZigiJWQgJWRcbiIsbngsbnkpOwoJaWYgKChueD09UklHSFQmJm55PT1MRUZUKSB8fCAobnk9PVJJR0hUJiZueD09TEVGVCkpIGJhZHJhdGUrPTEuMDsKICB9CiAgdm9pZCBQcm9nMygpIHsKCWFkcisrOwoJbng9bm9kZVtuaWRdW2Fkcl0uZmlyc3Q7CglydW4oKTsKCW55PW5vZGVbbmlkXVthZHJdLmZpcnN0OwoJcnVuKCk7Cgluej1ub2RlW25pZF1bYWRyXS5maXJzdDsKCXJ1bigpOwoJaWYgKChueD09UklHSFQmJm55PT1MRUZUKXx8KG55PT1SSUdIVCYmbng9PUxFRlQpKSBiYWRyYXRlKz0xLjA7CglpZiAoKG55PT1SSUdIVCYmbno9PUxFRlQpfHwobno9PVJJR0hUJiZueT09TEVGVCkpIGJhZHJhdGUrPTEuMDsKICB9CiAgdm9pZCBjaGFuZ2VfdmVjKCkgewoJRW5lcmd5LS07CglpZiAobm9kZVtuaWRdW2Fkcl0uZmlyc3QgPT0gUklHSFQpIHZlYyA9ICh2ZWMgKyAxKSAlIDQ7CgllbHNlIHZlYyA9ICh2ZWMgKyAzKSAlIDQ7CglhZHIrKzsKCWlmIChpc2FucykgewoJICBwdXRzKCIiKTsKCSAgZm9yIChpbnQgaT0wOyBpPG47IGkrKykgZm9yIChpbnQgaj0wOyBqPG47IGorKykgewoJCSAgaWYgKGkgPT0gYW50eSAmJiBqID09IGFudHgpIHsKCQkJaWYgKHZlYyA9PSAwKSBwcmludGYoIl4iKTsKCQkJZWxzZSBpZiAodmVjID09IDEpIHByaW50ZigiPiIpOwoJCQllbHNlIGlmICh2ZWMgPT0gMikgcHJpbnRmKCJ2Iik7CgkJCWVsc2UgcHJpbnRmKCI8Iik7CgkJICB9IGVsc2UgewoJCQlwcmludGYoIiVjIixtcFtpXVtqXSk7CgkJICB9CgkJICBpZiAoaiA9PSBuIC0gMSkgcHV0cygiIik7CgkJfQoJICBwdXRzKCIiKTsKCSAgdXNsZWVwKDEwMDAqNTAwKTsKCX0KICB9CiAgdm9pZCBtb3ZlKCkgewoJRW5lcmd5LS07CglueCA9IGFudHg7CglueSA9IGFudHk7CglpZiAodmVjID09IFUpIG55LS07CgllbHNlIGlmICh2ZWMgPT0gUikgbngrKzsKCWVsc2UgaWYgKHZlYyA9PSBEKSBueSsrOwoJZWxzZSBueC0tOwoJaWYgKG54PDB8fG55Pj1ufHxueTwwfHxueT49bikgYmFkcmF0ZSs9MS4wOwoJZWxzZSB7CgkgIGFudHg9bng7IGFudHk9bnk7CgkgIGlmIChhbnRbYW50eV1bYW50eF0pIGJhZHJhdGUgKz0gMC41OwoJICBpZiAoZm9vZHNbYW50eV1bYW50eF0pIHsKCQlmb29kKys7CgkJbXBbYW50eV1bYW50eF0gPSAnLic7CgkJZm9vZHNbYW50eV1bYW50eF0gPSAwOwoJICB9CgkgIGFudFthbnR5XVthbnR4XSA9IDE7Cgl9CglhZHIrKzsKCWlmIChpc2FucykgewoJICBwdXRzKCIiKTsKCSAgZm9yIChpbnQgaT0wOyBpPG47IGkrKykgZm9yIChpbnQgaj0wOyBqPG47IGorKykgewoJCSAgaWYgKGkgPT0gYW50eSAmJiBqID09IGFudHgpIHsKCQkJaWYgKHZlYyA9PSAwKSBwcmludGYoIl4iKTsKCQkJZWxzZSBpZiAodmVjID09IDEpIHByaW50ZigiPiIpOwoJCQllbHNlIGlmICh2ZWMgPT0gMikgcHJpbnRmKCJ2Iik7CgkJCWVsc2UgcHJpbnRmKCI8Iik7CgkJICB9IGVsc2UgewoJCQlwcmludGYoIiVjIixtcFtpXVtqXSk7CgkJICB9CgkJICBpZiAoaiA9PSBuIC0gMSkgcHV0cygiIik7CgkJfQoJICBwdXRzKCIiKTsKCSAgdXNsZWVwKDEwMDAqNTAwKTsKCX0KICB9CiAgdm9pZCB0cmF2KCkgewoJaWYgKGFkciA+PSBub2RlW25pZF0uc2l6ZSgpKSByZXR1cm47Cglzd2l0Y2ggKG5vZGVbbmlkXVthZHJdLmZpcnN0KSB7CgljYXNlIElGX0ZPT0RfQUhFQUQ6CgljYXNlIFBST0cyOgoJICBhZHIrKzsKCSAgdHJhdigpOyB0cmF2KCk7CgkgIGJyZWFrOwoJY2FzZSBQUk9HMzoKCSAgYWRyKys7CgkgIHRyYXYoKTsgdHJhdigpOyB0cmF2KCk7CgkgIGJyZWFrOwoJY2FzZSBSSUdIVDoKCWNhc2UgTEVGVDoKCWNhc2UgTU9WRToKCSAgYWRyKys7CgkgIGJyZWFrOwoJfQogIH0KfTsKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCmludCBwYTsKdm9pZCBwcmludG5vZGUoaW50IG5pZCkgewogIGlmIChub2RlW25pZF1bcGFdLmZpcnN0PT1JRl9GT09EX0FIRUFEKSB7CglwYSsrOwoJcHJpbnRmKCJmKCIpOwoJcHJpbnRub2RlKG5pZCk7CglwcmludGYoIiwiKTsKCXByaW50bm9kZShuaWQpOwoJcHJpbnRmKCIpIik7CiAgfSBlbHNlIGlmIChub2RlW25pZF1bcGFdLmZpcnN0PT1QUk9HMikgewoJcGErKzsKCXByaW50bm9kZShuaWQpOwoJcHJpbnRub2RlKG5pZCk7CiAgfSBlbHNlIGlmIChub2RlW25pZF1bcGFdLmZpcnN0PT1QUk9HMykgewoJcGErKzsKCXByaW50bm9kZShuaWQpOwoJcHJpbnRub2RlKG5pZCk7CglwcmludG5vZGUobmlkKTsKICB9IGVsc2UgaWYgKG5vZGVbbmlkXVtwYV0uZmlyc3Q9PVJJR0hUKSB7CglwYSsrOwoJcHJpbnRmKCJyIik7CiAgfSBlbHNlIGlmIChub2RlW25pZF1bcGFdLmZpcnN0PT1MRUZUKSB7CglwYSsrOwoJcHJpbnRmKCJsIik7CiAgfSBlbHNlIHsKCXBhKys7CglwcmludGYoIm0iKTsKICB9Cn0Kdm9pZCBtYXBpbml0KCkgewogIGZvciAoaW50IGk9MDsgaTxuOyBpKyspIHsKCW1wW2ldID0gTVBbaV07Cglmb3IgKGludCBqPTA7IGo8bjsgaisrKSB7CgkgIGZvb2RzW2ldW2pdID0gRk9PRFNbaV1bal07CgkgIGFudFtpXVtqXSA9IDA7Cgl9CiAgfQogIGFudFswXVswXSA9IDE7Cn0KaW50IGdldHNpemUoaW50IG5pZCkgewogIHJldHVybiBub2RlW25pZF0uc2l6ZSgpOwp9CmRvdWJsZSBldmFsdXRpb24oaW50IG5pZCkgewogIFRyZWUgdHJlZShmYWxzZSwgbmlkKTsKICBtYXBpbml0KCk7CiAgdHJlZS5ydW4oKTsKICByZXR1cm4gKGRvdWJsZSl0cmVlLmZvb2QqMTAwLXRyZWUuYmFkcmF0ZS0oZG91YmxlKWdldHNpemUobmlkKS8xMDAuMDsKfQppbnQgY2FsY2Zvb2QoaW50IG5pZCkgewogIFRyZWUgdHJlZShmYWxzZSwgbmlkKTsKICBtYXBpbml0KCk7CiAgdHJlZS5ydW4oKTsKICByZXR1cm4gdHJlZS5mb29kOwp9CgovLyBnZW5lcmF0ZSByYW5kb20gbm9kZQppbnQgZ2E7CnZvaWQgZ2VuX3JuZF9ub2RlKGludCBuaWQsIGludCBkZXB0aCwgaW50IG1heF9kLCBpbnQgbWV0aG9kKSB7CiAgZG91YmxlIHIgPSAoZG91YmxlKShyYW5kKCkgJSAxMCArIDEpIC8gMTAuMDsKICBpZiAobWF4X2QgPT0gZGVwdGggfHwgKGRlcHRoID4gMSAmJiBtZXRob2QgPT0gR1JPVyAmJiByIDwgMC41KSkgewoJaW50IHJjID0gcmFuZCgpICUgMyArIDM7Cglub2RlW25pZF0ucHVzaF9iYWNrKG1ha2VfcGFpcihyYywwKSk7Cglub2RlW25pZF1bbm9kZVtuaWRdLnNpemUoKS0xXS5zZWNvbmQ9bm9kZVtuaWRdLnNpemUoKTsKICB9IGVsc2UgewoJaW50IHJjID0gcmFuZCgpICUgMzsKCW5vZGVbbmlkXS5wdXNoX2JhY2sobWFrZV9wYWlyKHJjLDApKTsKCWdhPW5vZGVbbmlkXS5zaXplKCktMTsKCWdlbl9ybmRfbm9kZShuaWQsZGVwdGgrMSxtYXhfZCxtZXRob2QpOwoJZ2VuX3JuZF9ub2RlKG5pZCxkZXB0aCsxLG1heF9kLG1ldGhvZCk7CglpZiAocmM9PVBST0czKSBnZW5fcm5kX25vZGUobmlkLGRlcHRoKzEsbWF4X2QsbWV0aG9kKTsKCW5vZGVbbmlkXVtnYV0uc2Vjb25kPW5vZGVbbmlkXS5zaXplKCk7CiAgfQp9CgpjbGFzcyBGdW5jIHsKcHVibGljOgogIC8vIGNyb3Nzb3ZlcgogIGludCBjcm9zc2NudCwgY3Jvc3NhZHJbMl07CiAgdmVjdG9yPGJvb2w+IGNyMSwgY3IyOwogIGludCBjMSwgYzIsIGMzLCBjNDsKICB2b2lkIGZpbmRfc2FtZShpbnQgbmlkMSwgaW50IG5pZDIpIHsKCWlmIChjcm9zc2FkclswXTxnZXRzaXplKG5pZDEpfHxjcm9zc2FkclsxXTxnZXRzaXplKG5pZDIpKSByZXR1cm47Cgljcm9zc2NudCsrOwoJY3IxW2Nyb3NzYWRyWzBdXSA9IGNyMltjcm9zc2FkclsxXV0gPSB0cnVlOwoJaWYgKG5vZGVbbmlkMV1bY3Jvc3NhZHJbMF1dLmZpcnN0PD1QUk9HMiYmCgkJbm9kZVtuaWQyXVtjcm9zc2FkclsxXV0uZmlyc3Q8PVBST0cyKSB7CgkgIGNyb3NzYWRyWzBdKys7IGNyb3NzYWRyWzFdKys7CgkgIGZpbmRfc2FtZShuaWQxLG5pZDIpOwoJICBmaW5kX3NhbWUobmlkMSxuaWQyKTsKCX0gZWxzZSBpZiAobm9kZVtuaWQxXVtjcm9zc2FkclswXV0uZmlyc3Q9PVBST0czJiYKCQkJICAgbm9kZVtuaWQyXVtjcm9zc2FkclsxXV0uZmlyc3Q9PVBST0czKSB7CgkgIGNyb3NzYWRyWzBdKys7IGNyb3NzYWRyWzFdKys7CgkgIGZpbmRfc2FtZShuaWQxLG5pZDIpOwoJICBmaW5kX3NhbWUobmlkMSxuaWQyKTsKCSAgZmluZF9zYW1lKG5pZDEsbmlkMik7Cgl9IGVsc2UgewoJICB0bXAgPSBub2RlW25pZDFdW2Nyb3NzYWRyWzBdXS5zZWNvbmQ7CgkgIGNyb3NzYWRyWzBdID0gdG1wOwoJICB0bXAgPSBub2RlW25pZDJdW2Nyb3NzYWRyWzFdXS5zZWNvbmQ7CgkgIGNyb3NzYWRyWzFdID0gdG1wOwoJfQogIH0KICB2b2lkIHVuaXRlX3BvcyhpbnQgbmlkMSwgaW50IG5pZDIsIGludCByKSB7CglpZiAoY3Jvc3NjbnQ9PXIpIHsKCSAgYzE9Y3Jvc3NhZHJbMF07CgkgIGMzPW5vZGVbbmlkMV1bYzFdLnNlY29uZDsKCSAgYzI9Y3Jvc3NhZHJbMV07CgkgIGM0PW5vZGVbbmlkMl1bYzJdLnNlY29uZDsKCSAgcmV0dXJuOwoJfQoJY3Jvc3NjbnQrKzsKCWlmIChub2RlW25pZDFdW2Nyb3NzYWRyWzBdXS5maXJzdDw9UFJPRzImJgoJCW5vZGVbbmlkMl1bY3Jvc3NhZHJbMV1dLmZpcnN0PD1QUk9HMikgewoJICBjcm9zc2FkclswXSsrOyBjcm9zc2FkclsxXSsrOwoJICB1bml0ZV9wb3MobmlkMSxuaWQyLHIpOwoJICB1bml0ZV9wb3MobmlkMSxuaWQyLHIpOwoJfSBlbHNlIGlmIChub2RlW25pZDFdW2Nyb3NzYWRyWzBdXS5maXJzdD09UFJPRzMmJgoJCQkgICBub2RlW25pZDJdW2Nyb3NzYWRyWzFdXS5maXJzdD09UFJPRzMpIHsKCSAgY3Jvc3NhZHJbMF0rKzsgY3Jvc3NhZHJbMV0rKzsKCSAgdW5pdGVfcG9zKG5pZDEsbmlkMixyKTsKCSAgdW5pdGVfcG9zKG5pZDEsbmlkMixyKTsKCSAgdW5pdGVfcG9zKG5pZDEsbmlkMixyKTsKCX0gZWxzZSB7CgkgIHRtcCA9IG5vZGVbbmlkMV1bY3Jvc3NhZHJbMF1dLnNlY29uZDsKCSAgY3Jvc3NhZHJbMF09dG1wOwoJICB0bXA9bm9kZVtuaWQyXVtjcm9zc2FkclsxXV0uc2Vjb25kOwoJICBjcm9zc2FkclsxXT10bXA7Cgl9CiAgfQogIHZvaWQgY3Jvc3NvdmVyKGludCBuaWQxLCBpbnQgbmlkMiwgaW50IGNpZDEsIGludCBjaWQyKSB7Cgljcm9zc2NudCA9IDA7CgljcjEucmVzaXplKG5vZGVbbmlkMV0uc2l6ZSgpLCBmYWxzZSk7CgljcjIucmVzaXplKG5vZGVbbmlkMl0uc2l6ZSgpLCBmYWxzZSk7Cgljcm9zc2FkclswXT1jcm9zc2FkclsxXT0wOwoJZmluZF9zYW1lKG5pZDEsIG5pZDIpOwoJaWYgKGNyb3NzY250ID4gMSkgewoJICAvLyBwdXRzKCJmaW5kIHNhbWUiKTsKCSAgY3Jvc3NhZHJbMF0gPSBjcm9zc2FkclsxXSA9IDA7CgkgIGludCByID0gcmFuZCgpICUgKGNyb3NzY250LTEpICsgMTsKCSAgY3Jvc3NjbnQgPSAwOwoJICB1bml0ZV9wb3MobmlkMSwgbmlkMiwgcik7CgkgIGNvcHkobm9kZVtuaWQxXS5iZWdpbigpLCBub2RlW25pZDFdLmJlZ2luKCkrYzEsIGJhY2tfaW5zZXJ0ZXIobm9kZVtjaWQxXSkpOwoJICBjb3B5KG5vZGVbbmlkMl0uYmVnaW4oKSwgbm9kZVtuaWQyXS5iZWdpbigpK2MyLCBiYWNrX2luc2VydGVyKG5vZGVbY2lkMl0pKTsKCSAgY29weShub2RlW25pZDFdLmJlZ2luKCkrYzEsIG5vZGVbbmlkMV0uYmVnaW4oKStjMywgYmFja19pbnNlcnRlcihub2RlW2NpZDJdKSk7CgkgIGNvcHkobm9kZVtuaWQyXS5iZWdpbigpK2MyLCBub2RlW25pZDJdLmJlZ2luKCkrYzQsIGJhY2tfaW5zZXJ0ZXIobm9kZVtjaWQxXSkpOwoJICBjb3B5KG5vZGVbbmlkMV0uYmVnaW4oKStjMywgbm9kZVtuaWQxXS5lbmQoKSwgYmFja19pbnNlcnRlcihub2RlW2NpZDFdKSk7CgkgIGNvcHkobm9kZVtuaWQyXS5iZWdpbigpK2M0LCBub2RlW25pZDJdLmVuZCgpLCBiYWNrX2luc2VydGVyKG5vZGVbY2lkMl0pKTsKCX0gZWxzZSBpZiAoY3Jvc3NjbnQgPT0gMSkgewoJICAvLyBwdXRzKCJmaW5kIHNhbWUiKTsKCSAgY3Jvc3NjbnQ9MDsKCSAgY3Jvc3NhZHJbMF0gPSBjcm9zc2FkclsxXSA9IDA7CgkgIHVuaXRlX3BvcyhuaWQxLCBuaWQyLCAxKTsKCSAgY29weShub2RlW25pZDFdLmJlZ2luKCksIG5vZGVbbmlkMV0uYmVnaW4oKStjMSwgYmFja19pbnNlcnRlcihub2RlW2NpZDFdKSk7CgkgIGNvcHkobm9kZVtuaWQyXS5iZWdpbigpLCBub2RlW25pZDJdLmJlZ2luKCkrYzIsIGJhY2tfaW5zZXJ0ZXIobm9kZVtjaWQyXSkpOwoJICBjb3B5KG5vZGVbbmlkMV0uYmVnaW4oKStjMSwgbm9kZVtuaWQxXS5iZWdpbigpK2MzLCBiYWNrX2luc2VydGVyKG5vZGVbY2lkMl0pKTsKCSAgY29weShub2RlW25pZDJdLmJlZ2luKCkrYzIsIG5vZGVbbmlkMl0uYmVnaW4oKStjNCwgYmFja19pbnNlcnRlcihub2RlW2NpZDFdKSk7CgkgIGNvcHkobm9kZVtuaWQxXS5iZWdpbigpK2MzLCBub2RlW25pZDFdLmVuZCgpLCBiYWNrX2luc2VydGVyKG5vZGVbY2lkMV0pKTsKCSAgY29weShub2RlW25pZDJdLmJlZ2luKCkrYzQsIG5vZGVbbmlkMl0uZW5kKCksIGJhY2tfaW5zZXJ0ZXIobm9kZVtjaWQyXSkpOzsKCX0KICB9CgogIC8vIG11dGF0aW9uCiAgaW50IG11dGNudDsKICB2b2lkIG11dHJ1bihpbnQgdG9nZW4sIGludCBmcm9tZ2VuLCBpbnQgZGVwdGgsIGludCByKSB7CglpZiAobXV0Y250ID09IHIpIHsKCSAgZ2VuX3JuZF9ub2RlKHRvZ2VuLCBkZXB0aCsxLCAyMCwgR1JPVyk7CgkgIHRtcCA9IG5vZGVbZnJvbWdlbl1bbXV0Y250XS5zZWNvbmQ7CgkgIG11dGNudCA9IHRtcDsKCX0KCWlmIChtdXRjbnQgPj0gZ2V0c2l6ZShmcm9tZ2VuKSkgcmV0dXJuOwoJbm9kZVt0b2dlbl0ucHVzaF9iYWNrKG5vZGVbZnJvbWdlbl1bbXV0Y250XSk7CglpbnQgZmxhZyA9IG5vZGVbZnJvbWdlbl1bbXV0Y250XS5maXJzdDsKCW11dGNudCsrOwoJaWYgKGZsYWc8PVBST0czKSB7CgkgIG11dHJ1bih0b2dlbiwgZnJvbWdlbiwgZGVwdGgrMSwgcik7CgkgIG11dHJ1bih0b2dlbiwgZnJvbWdlbiwgZGVwdGgrMSwgcik7CgkgIGlmIChmbGFnPT1QUk9HMykgbXV0cnVuKHRvZ2VuLGZyb21nZW4sZGVwdGgrMSxyKTsKCX0gCiAgfQogIHZvaWQgbXV0YXRpb24oaW50IG5nZW4sIGludCByZ2VuKSB7CglpbnQgc3ogPSBnZXRzaXplKHJnZW4pOwoJaWYgKHN6IT0wKSB7CgkgIGludCByID0gcmFuZCgpICUgc3o7CgkgIHdoaWxlIChyID09IDApIHIgPSByYW5kKCkgJSBzejsKCSAgbXV0Y250ID0gMDsKCSAgLy8gcHJpbnRmKCIlZFxuIixzeik7CgkgIG11dHJ1bihuZ2VuLCByZ2VuLCAwLCByKTsKCX0KICB9Cn07CgovLyBnZW5lcmF0aW9uCnN0YXRpYyBpbnQgU1o9MTAwLCBHRU5FPTEwMDAsIFRTWj0yOwp2ZWN0b3I8UD4gZG47CkZ1bmMgZnVuYzsKCnZvaWQgaW5pdGlhbGlzYXRpb24oKSB7CiAgbm9kZS5yZXNpemUoU1oqMiwgdmkoMCkpOwogIGZvciAoaW50IGk9MDsgaTxTWjsgaSsrKSB7CglnZW5fcm5kX25vZGUoaSwwLDUsRlVMTCk7CiAgfQp9CmludCB0b3VybmFtZW50KCkgewogIHNldDxpbnQ+IHN0OwogIHdoaWxlIChzdC5zaXplKCkgPCBUU1opIHsKCWludCByID0gcmFuZCgpICUgU1o7CglzdC5pbnNlcnQocik7CiAgfQogIHNldDxpbnQ+OjppdGVyYXRvciBpdDsKICB2ZWN0b3I8UD4gZG54OwogIGZvciAoaXQ9c3QuYmVnaW4oKTsgaXQhPXN0LmVuZCgpOyBpdCsrKSB7CglkbngucHVzaF9iYWNrKFAoZXZhbHV0aW9uKCgqaXQpKSwgKCppdCkpKTsKICB9CiAgc29ydChkbnguYmVnaW4oKSwgZG54LmVuZCgpKTsKICByZXR1cm4gZG54W1RTWi0xXS5zZWNvbmQ7Cn0Kdm9pZCBydW5fY3Jvc3MoaW50IG5nZW4pIHsKICBpbnQgcjEgPSB0b3VybmFtZW50KCk7CiAgaW50IHIyID0gdG91cm5hbWVudCgpOwogIGlmIChuZ2VuKzE+PW5vZGUuc2l6ZSgpKSBub2RlLnB1c2hfYmFjayh2aSgwKSk7CiAgaWYgKG5nZW4rMj49bm9kZS5zaXplKCkpIG5vZGUucHVzaF9iYWNrKHZpKDApKTsKICBmdW5jLmNyb3Nzb3ZlcihyMSxyMixuZ2VuKzEsbmdlbisyKTsKICBpbnQgZTEgPSBldmFsdXRpb24obmdlbisxKTsKICBpbnQgZTIgPSBldmFsdXRpb24obmdlbisyKTsKICBpZiAoZTEgPiBlMikgewoJY29weShub2RlW25nZW4rMV0uYmVnaW4oKSwgbm9kZVtuZ2VuKzFdLmVuZCgpLCBiYWNrX2luc2VydGVyKG5vZGVbbmdlbl0pKTsKICB9IGVsc2UgewoJY29weShub2RlW25nZW4rMl0uYmVnaW4oKSwgbm9kZVtuZ2VuKzJdLmVuZCgpLCBiYWNrX2luc2VydGVyKG5vZGVbbmdlbl0pKTsKICB9CiAgbm9kZVtuZ2VuKzFdLmNsZWFyKCk7CiAgbm9kZVtuZ2VuKzJdLmNsZWFyKCk7Cn0Kdm9pZCBjYWxjX2dlbigpIHsKICBkbi5jbGVhcigpOwogIGZvciAoaW50IGk9MDsgaTxTWjsgaSsrKSB7Cglkbi5wdXNoX2JhY2soUChldmFsdXRpb24oaSksIGkpKTsKICB9CiAgc29ydChkbi5iZWdpbigpLCBkbi5lbmQoKSk7Cn0KCmludCBncChpbnQgZ2VubnVtKSB7CiAgY2FsY19nZW4oKTsKICBpZiAoZ2VubnVtID49IEdFTkUpIHsKCXJldHVybiBkbltTWi0xXS5zZWNvbmQ7CiAgfQogIGRvdWJsZSByPShkb3VibGUpKHJhbmQoKSUxMDAwKzEpLzEwMDAuMDsKICBpbnQgbmdlbiA9IFNaOwogIHdoaWxlIChuZ2VuPFNaKjIpIHsKCWlmIChyPDAuMDUpIHsKCSAgaW50IHJtPSByYW5kKCkgJSBTWjsKCSAgLy8gcHV0cygibXV0YXRpb24iKTsKCSAgZnVuYy5tdXRhdGlvbihuZ2VuLCBybSk7Cgl9IGVsc2UgaWYgKHI8MC4xKSB7CgkgIC8vIHB1dHMoInRvdXJuYW1lbnQiKTsKCSAgaW50IHQgPSB0b3VybmFtZW50KCk7CgkgIGNvcHkobm9kZVt0XS5iZWdpbigpLCBub2RlW3RdLmVuZCgpLCBiYWNrX2luc2VydGVyKG5vZGVbbmdlbl0pKTsKCX0gZWxzZSB7CgkgIC8vIHB1dHMoImNyb3Nzb3ZlciIpOwoJICBydW5fY3Jvc3Mobmdlbik7Cgl9CgluZ2VuKys7CglyPShkb3VibGUpKHJhbmQoKSUxMDAwKzEpLzEwMDAuMDsKICB9CiAgLy8gcHV0cygiaHlvdWppIik7CiAgdXNsZWVwKDEwMDAqMjAwKTsKICBmb3IgKGludCBpPTA7IGk8U1o7IGkrKykgewoJbm9kZVtpXS5jbGVhcigpOwoJY29weShub2RlW2krU1pdLmJlZ2luKCksIG5vZGVbaStTWl0uZW5kKCksIGJhY2tfaW5zZXJ0ZXIobm9kZVtpXSkpOwoJbm9kZVtpK1NaXS5jbGVhcigpOwogIH0KICAKICBmb3IgKGludCBpPTA7IGk8U1ovMTA7IGkrKykgewogIAlwcmludGYoImdlbmVyYXRpb24gJWQ6ICIsIGdlbm51bSArIDEpOwogIAlmb3IgKGludCBqPWkqMTA7IGo8bWluKFNaLChpKzEpKjEwKTsgaisrKSB7CiAgCSAgcHJpbnRmKCIlZCglLjNmKSAiLCBjYWxjZm9vZChqKSwgZXZhbHV0aW9uKGopKTsKICAJfQogIAlwdXRzKCIiKTsKICB9CiAgcmV0dXJuIGdwKGdlbm51bSArIDEpOwp9CgppbnQgbWFpbigpIHsKICBzcmFuZCgodW5zaWduZWQgaW50KXRpbWUoTlVMTCkpOwogIHNjYW5mKCIlZCVkIiwmbiwgJmUpOwogIGZvciAoaW50IGk9MDsgaTxuOyBpKyspIGNpbj4+TVBbaV07CiAgZm9yIChpbnQgaT0wOyBpPG47IGkrKykgewoJbXBbaV0gPSBNUFtpXTsKCWZvciAoaW50IGo9MDsgajxuOyBqKyspIHsKCSAgaWYgKE1QW2ldW2pdID09ICcjJykgRk9PRFNbaV1bal0gPSBmb29kc1tpXVtqXSA9IDE7Cgl9CiAgfQoKICBpbml0aWFsaXNhdGlvbigpOwogIAogIC8vICBydW5jbnQ9MDsKICBmb3IgKGludCBpPTA7IGk8U1ovMTA7IGkrKykgewoJcHJpbnRmKCJnZW5lcmF0aW9uICVkOiAiLCAwKTsKICAJZm9yIChpbnQgaj1pKjEwOyBqPG1pbihTWiwoaSsxKSoxMCk7IGorKykgewogIAkgIHByaW50ZigiJWQoJS4zZikgIiwgY2FsY2Zvb2QoaiksIGV2YWx1dGlvbihqKSk7CiAgCX0KICAJcHV0cygiIik7CiAgfQoKICBpbnQgYW5zID0gZ3AoMCk7CiAgbWFwaW5pdCgpOwogIFRyZWUgdHJlZSh0cnVlLCBhbnMpOwogIHRyZWUucnVuKCk7CgogIHByaW50ZigicmVzdWx0OiBmb29kPSVkIEVuZXJneT0lZCBldmFsdXRpb249JS4zZlxuIix0cmVlLmZvb2QsdHJlZS5FbmVyZ3ksZXZhbHV0aW9uKGFucykpOwogIHByaW50bm9kZShhbnMpOwogIHB1dHMoIiIpOwogIC8vIHRlc3QoKTsKfQo=