#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <assert.h>
#include <chrono>
class muTimer
{
using Clock = std::chrono::high_resolution_clock;
bool active = false;
Clock::duration duration_;
Clock::time_point start_ = Clock::now(), stop_ = Clock::now();
muTimer(const muTimer&) = delete;
muTimer& operator=(const muTimer&) = delete;
public:
using ns = std::chrono::nanoseconds;
using mks = std::chrono::microseconds;
using ms = std::chrono::milliseconds;
muTimer() { reset(); start(); }
~muTimer() = default;
muTimer& reset()
{
duration_ = std::chrono::nanoseconds(0);
active = false;
return *this;
}
muTimer& start()
{
if (!active)
{
start_ = Clock::now();
active = true;
}
return *this;
}
muTimer& stop()
{
if (active)
{
stop_ = Clock::now();
duration_ += stop_ - start_;
active = false;
}
return *this;
}
template<typename T = mks>
unsigned long long duration()
{
return static_cast<unsigned long long>
(std::chrono::duration_cast<T>(stop_-start_).count());
}
};
class Sudoku
{
public:
Sudoku(bool clean = true);
Sudoku(const Sudoku&s) { memcpy(p,s.p,sizeof(p)); }
Sudoku(const char *);
Sudoku& operator = (const Sudoku&s) { memcpy(p,s.p,sizeof(p)); return *this; }
~Sudoku() {};
int operator()(int r, int c) const;
int& operator()(int r, int c) { return p[r-1][c-1]; }
int ok () const;
void shuffle (int count = 3);
void out () const;
int zeros () const;
Sudoku solidSolve() const;
Sudoku addZeros (int max) const;
Sudoku solve (int&count) const;
void Generate();
private:
bool Gen();
static void trySolve(Sudoku&s, Sudoku& result, int& count );
void swapSqR(int i, int j);
void swapSqC(int i, int j);
void swapRow(int i, int j);
void swapCol(int i, int j);
void permut (int*perm);
void swap(int&i,int&j) { int t = i; i = j; j = t; }
int check(int r, int c) const; // ? ? - ?
int checkCount(int r, int c) const; // ? ??
int p[9][9];
};
inline int Sudoku::zeros() const /*fold00*/
{
int z = 0;
for(int i = 0; i < sizeof(p)/sizeof(int); ++i)
if (*((int*)p+i) == 0) ++z;
return z;
}
inline int Sudoku::ok() const /*fold00*/
{
if (zeros()) return -1;
static const char cstr[] = "-+++++++++";
// ?? ? ?
for(int r = 0; r < 9; ++r)
{
char h[11] = {0}, v[11] = {0};
memset(h,'-',10); memset(v,'-',10);
for(int c = 0; c < 9; ++c)
{
h[p[r][c]] = '+';
v[p[c][r]] = '+';
}
if (strcmp(h,cstr)) return 0;
if (strcmp(v,cstr)) return 0;
}
// ?? ?
for(int i = 0; i < 3; ++i)
for(int j = 0; j < 3; ++j)
{
char s[11] = {0};
memset(s,'-',10);
for(int r = i*3; r < i*3+3; ++r)
for(int c = j*3; c < j*3 + 3; ++c)
s[p[r][c]] = '+';
if (strcmp(s,cstr))
return 0;
}
return 1;
}
inline int Sudoku::check(int r, int c) const /*fold00*/
{
int allow[9] = {1,2,3,4,5,6,7,8,9};
// ?? ??
for(int x = 0; x < 9; ++x)
{
if (p[x][c] && (r != x)) allow[p[x][c]-1] = 0;
if (p[r][x] && (c != x)) allow[p[r][x]-1] = 0;
}
// ??
int rq = (r/3)*3;
int cq = (c/3)*3;
for(int x = 0; x < 3; ++x)
for(int y = 0; y < 3; ++y)
{
int rx = rq + x;
int cy = cq + y;
if (p[rx][cy] && ((rx != r) || (cy != c)))
allow[p[rx][cy]-1] = 0;
}
int nonzero = 0;
int result = 0;
for(int i = 0; i < 9; ++i)
if (allow[i])
{
if (++nonzero > 1) break;
result = allow[i];
}
if (nonzero != 1) return 0;
return result;
}
inline int Sudoku::checkCount(int r, int c) const /*FOLD00*/
{
int allow[9] = {1,2,3,4,5,6,7,8,9};
// ?? ??
for(int x = 0; x < 9; ++x)
{
if (p[x][c] && (r != x)) allow[p[x][c]-1] = 0;
if (p[r][x] && (c != x)) allow[p[r][x]-1] = 0;
}
// ??
int rq = (r/3)*3;
int cq = (c/3)*3;
for(int x = 0; x < 3; ++x)
for(int y = 0; y < 3; ++y)
{
int rx = rq + x;
int cy = cq + y;
if (p[rx][cy] && ((rx != r) || (cy != c)))
allow[p[rx][cy]-1] = 0;
}
int nonzero = 0;
for(int i = 0; i < 9; ++i)
if (allow[i])
{
++nonzero;
}
return nonzero;
}
Sudoku Sudoku::solidSolve() const /*fold00*/
{
Sudoku s(*this);
while(s.zeros())
{
bool found = false;
for(int i = 0; i < 9; ++i)
for(int j = 0; j < 9; ++j)
if (s.p[i][j] == 0)
{
int res = s.check(i,j);
if (res)
{
found = true;
s.p[i][j] = res;
}
}
if (!found) break;
}
return s;
}
Sudoku::Sudoku(const char * s) /*FOLD00*/
{
for(int r = 0; r < 9; ++r)
for(int c = 0; c < 9; ++c)
{
while(!isdigit(*s)) ++s;
p[r][c] = *s - '0';
++s;
}
}
Sudoku::Sudoku(bool clean) /*FOLD00*/
{
static int sd[9][9] = {
{1,2,3,4,5,6,7,8,9},
{4,5,6,7,8,9,1,2,3},
{7,8,9,1,2,3,4,5,6},
{2,3,1,5,6,4,8,9,7},
{5,6,4,8,9,7,2,3,1},
{8,9,7,2,3,1,5,6,4},
{3,1,2,6,4,5,9,7,8},
{6,4,5,9,7,8,3,1,2},
{9,7,8,3,1,2,6,4,5}
};
if (clean)
{
for(int i = 0; i < 9; ++i)
for(int j = 0; j < 9; ++j)
p[i][j] = 0;
}
else
{
Generate();
//for(int i = 0; i < 9; ++i)
// for(int j = 0; j < 9; ++j)
// p[i][j] = sd[i][j];
//shuffle();
}
}
void Sudoku::permut (int*perm) /*FOLD00*/
{
for(int i = 0; i < 9; ++i)
for(int j = 0; j < 9; ++j)
p[i][j] = perm[p[i][j]-1];
}
void Sudoku::out() const /*fold00*/
{
for(int i = 0; i < 9; ++i)
{
for(int j = 0; j < 9; ++j)
printf("%d",p[i][j]);
printf("\n");
}
}
void Sudoku::shuffle(int count) /*FOLD00*/
{
int perm[9] = {1,2,3,4,5,6,7,8,9};
for(int k = 8; k > 0; --k)
{
swap(perm[k],perm[rand()%k]);
}
int i,j,l;
for(int k = 0; k < count; k++)
{
i = rand()%3; j = rand()%3; swapSqR(i,j);
i = rand()%3; j = rand()%3; swapSqC(i,j);
i = rand()%3; j = rand()%3; l = rand()%3; swapRow(i+l*3,j+l*3);
i = rand()%3; j = rand()%3; l = rand()%3; swapCol(i+l*3,j+l*3);
permut(perm);
}
}
void Sudoku::swapSqR(int i, int j) /*fold00*/
{
if ((i>=0)&&(i<=2)&&
(j>=0)&&(j<=2)&&
(i != j))
{
for(int r = 0; r < 3; ++r)
for(int c = 0; c < 9; ++c)
{
swap(p[i*3+r][c],p[j*3+r][c]);
}
}
}
void Sudoku::swapSqC(int i, int j) /*fold00*/
{
if ((i>=0)&&(i<=2)&&
(j>=0)&&(j<=2)&&
(i != j))
{
for(int c = 0; c < 3; ++c)
for(int r = 0; r < 9; ++r)
{
swap(p[r][i*3+c],p[r][j*3+c]);
}
}
}
void Sudoku::swapRow(int i, int j) /*fold00*/
{
if ((i>=0)&&(i<=8)&&
(j>=0)&&(j<=8)&&
(i/3 == j/3)&&
(i != j))
{
for(int c = 0; c < 9; ++c)
swap(p[i][c],p[j][c]);
}
}
void Sudoku::swapCol(int i, int j) /*fold00*/
{
if ((i>=0)&&(i<=8)&&
(j>=0)&&(j<=8)&&
(i/3 == j/3)&&
(i != j))
{
for(int r = 0; r < 9; ++r)
swap(p[r][i],p[r][j]);
}
}
int Sudoku::operator()(int r, int c) const /*fold00*/
{
if (r < 0) return -1;
if (c < 0) return -1;
if (r > 8) return -1;
if (c > 8) return -1;
return p[r][c];
}
Sudoku Sudoku::addZeros(int max) const /*FOLD00*/
{
Sudoku s(*this); // ?
while(s.zeros() < max)
{
int nonzeros = 81 - s.zeros();
bool added = false;
//printf("Zeros = %d\n",s.zeros());
for(int i = 0; i < nonzeros; ++i) // ?...
{
Sudoku t(s); // ?
int q = rand()%nonzeros;
for(int r = 0; r < 9; ++r)
{
for(int c = 0; c < 9; ++c)
{
if (t.p[r][c] == 0) continue;
if (q > 0)
{
--q;
continue;
}
t.p[r][c] = 0;
int count = 1;
//Sudoku sol = t.solidSolve();
Sudoku sol = t.solidSolve();
if ((sol.ok() == 1)&&(count == 1))
{
added = true;
//printf("s.zeros() = %d\n",s.zeros());
//printf("Added...\n");
s = t;
//printf("s.zeros() = %d\n",s.zeros());
break;
}
}
if (added) break;
}
if (added) break;
}
if (!added) // ? ... ??
{
for(int i = 0; i < nonzeros; ++i) // ?...
{
Sudoku t(s); // ?
int q = rand()%nonzeros;
for(int r = 0; r < 9; ++r)
{
for(int c = 0; c < 9; ++c)
{
if (t.p[r][c] == 0) continue;
if (q > 0)
{
--q;
continue;
}
t.p[r][c] = 0;
int count;
Sudoku sol = t.solve(count);
if ((sol.ok() == 1)&&(count == 1))
{
added = true;
//printf("s.zeros() = %d\n",s.zeros());
//printf("Added...\n");
s = t;
//printf("s.zeros() = %d\n",s.zeros());
break;
}
}
if (added) break;
}
if (added) break;
}
}
if (!added) break;
}
return s;
}
Sudoku Sudoku::solve(int&count) const /*FOLD00*/
{
Sudoku s = solidSolve();
if (s.ok() == 1)
{
count = 1;
return s;
}
s = *this;
count = 0;
Sudoku res = s;
trySolve(s,res,count);
return res;
}
int level = 0;
void Sudoku::trySolve(Sudoku&s, Sudoku&res, int&count) /*FOLD00*/
{
if (s.zeros() == 0) return; // ?
if (count > 1) return;
++level;
//printf(" Level %3d, zeros %3d, count %2d\r",level,s.zeros(), count);
//fflush(stdout);
// ?
int r = -1, c = -1;
int cnt = 9;
for(int x = 0; x < 9; ++x)
{
for(int y = 0; y < 9; ++y)
{
if (s.p[x][y]) continue;
int count = s.checkCount(x,y);
if (cnt >= count)
{
r = x;
c = y;
cnt = count;
}
}
}
assert((r >= 0) && (c >= 0));
// ?? ? ? ?
int allow[9] = { 1,2,3,4,5,6,7,8,9 };
for(int x = 0; x < 9; ++x)
{
if (s.p[r][x]) allow[s.p[r][x]-1] = 0;
if (s.p[x][c]) allow[s.p[x][c]-1] = 0;
}
for(int x = 0; x < 3; ++x)
for(int y = 0; y < 3; ++y)
if (s.p[(r/3)*3+x][(c/3)*3+y])
allow[s.p[(r/3)*3+x][(c/3)*3+y]-1] = 0;
for(int i = 0; i < 9; ++i)
{
if (allow[i] == 0) continue;
s.p[r][c] = allow[i];
Sudoku v = s.solidSolve();
if (v.ok() == 1) // ?
{
res = v;
count++;
if (count > 1) break;
continue;
}
trySolve(s,res,count);
if (count > 1) break;
}
s.p[r][c] = 0;
--level;
}
void Sudoku::Generate()
{
for(int r = 0; r < 9; ++r)
for(int c = 0; c < 9; ++c)
p[r][c] = (r == 0) ? c + 1 : 0;
Gen();
shuffle();
}
bool Sudoku::Gen()
{
if (zeros() == 0) return true;
// ? ?
int r, c;
for(int x = 0; x < 9; ++x)
for(int y = 0; y < 9; ++y)
{
if (p[x][y]) continue;
r = x;
c = y;
break;
}
// ?? ? ? ?
int allow[9] = { 1,2,3,4,5,6,7,8,9 };
for(int x = 0; x < 9; ++x)
{
if (p[r][x]) allow[p[r][x]-1] = 0;
if (p[x][c]) allow[p[x][c]-1] = 0;
}
for(int x = 0; x < 3; ++x)
for(int y = 0; y < 3; ++y)
if (p[(r/3)*3+x][(c/3)*3+y])
allow[p[(r/3)*3+x][(c/3)*3+y]-1] = 0;
// ?? ? ?
for(int k = 8; k > 0; --k)
swap(allow[k],allow[rand()%k]);
for(int k = 0; k < 9; ++k)
{
if (allow[k] == 0) continue;
p[r][c] = allow[k];
if (zeros() == 0)
{
if (ok() == 1)
{
//printf("---------\n");
//out();
//printf("---------\n");
return true;
}
}
if (Gen()) return true;
}
p[r][c] = 0;
return false;
}
int main(int argc, const char * argv[]) /*FOLD00*/
{
muTimer mt;
srand(time(0));
Sudoku s("800000000003600000070090200050007000000045700000100030001000068008500010090000400");
int count;
s = s.solve(count);
mt.stop();
s.out();
printf("Count = %d\n",count);
printf("Zeros = %d\n",s.zeros());
printf("%llu mks\n",mt.duration());
exit(0);
Sudoku t = s;
t.Generate();
t.out();
printf("Zeros = %d, ok = %d\n",t.zeros(), t.ok());
}
I2luY2x1ZGUgPHN0ZGxpYi5oPgojaW5jbHVkZSA8c3RkaW8uaD4KI2luY2x1ZGUgPHN0cmluZy5oPgojaW5jbHVkZSA8dGltZS5oPgojaW5jbHVkZSA8Y3R5cGUuaD4KI2luY2x1ZGUgPGFzc2VydC5oPgojaW5jbHVkZSA8Y2hyb25vPgoKY2xhc3MgbXVUaW1lcgp7CiAgICB1c2luZyBDbG9jayA9IHN0ZDo6Y2hyb25vOjpoaWdoX3Jlc29sdXRpb25fY2xvY2s7CiAgICBib29sIGFjdGl2ZSA9IGZhbHNlOwogICAgQ2xvY2s6OmR1cmF0aW9uICAgZHVyYXRpb25fOwogICAgQ2xvY2s6OnRpbWVfcG9pbnQgc3RhcnRfID0gQ2xvY2s6Om5vdygpLCBzdG9wXyA9IENsb2NrOjpub3coKTsKCiAgICBtdVRpbWVyKGNvbnN0IG11VGltZXImKSAgICAgICAgICAgICA9IGRlbGV0ZTsKICAgIG11VGltZXImIG9wZXJhdG9yPShjb25zdCBtdVRpbWVyJikgID0gZGVsZXRlOwpwdWJsaWM6CiAgICB1c2luZyBucyAgICAgICA9IHN0ZDo6Y2hyb25vOjpuYW5vc2Vjb25kczsKICAgIHVzaW5nIG1rcyAgICAgID0gc3RkOjpjaHJvbm86Om1pY3Jvc2Vjb25kczsKICAgIHVzaW5nIG1zICAgICAgID0gc3RkOjpjaHJvbm86Om1pbGxpc2Vjb25kczsKICAgIG11VGltZXIoKSB7IHJlc2V0KCk7IHN0YXJ0KCk7IH0KICAgIH5tdVRpbWVyKCkgPSBkZWZhdWx0OwogICAgbXVUaW1lciYgcmVzZXQoKQogICAgewogICAgICAgIGR1cmF0aW9uXyA9IHN0ZDo6Y2hyb25vOjpuYW5vc2Vjb25kcygwKTsKICAgICAgICBhY3RpdmUgICAgPSBmYWxzZTsKICAgICAgICByZXR1cm4gKnRoaXM7CiAgICB9CiAgICBtdVRpbWVyJiBzdGFydCgpCiAgICB7CiAgICAgICAgaWYgKCFhY3RpdmUpCiAgICAgICAgewogICAgICAgICAgICBzdGFydF8gPSBDbG9jazo6bm93KCk7CiAgICAgICAgICAgIGFjdGl2ZSA9IHRydWU7CiAgICAgICAgfQogICAgICAgIHJldHVybiAqdGhpczsKICAgIH0KICAgIG11VGltZXImIHN0b3AoKQogICAgewogICAgICAgIGlmIChhY3RpdmUpCiAgICAgICAgewogICAgICAgICAgICBzdG9wXyAgICAgID0gQ2xvY2s6Om5vdygpOwogICAgICAgICAgICBkdXJhdGlvbl8gKz0gc3RvcF8gLSBzdGFydF87CiAgICAgICAgICAgIGFjdGl2ZSAgICAgPSBmYWxzZTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuICp0aGlzOwogICAgfQogICAgdGVtcGxhdGU8dHlwZW5hbWUgVCA9IG1rcz4KICAgICAgICB1bnNpZ25lZCBsb25nIGxvbmcgZHVyYXRpb24oKQogICAgewogICAgICAgIHJldHVybiBzdGF0aWNfY2FzdDx1bnNpZ25lZCBsb25nIGxvbmc+CiAgICAgICAgICAgIChzdGQ6OmNocm9ubzo6ZHVyYXRpb25fY2FzdDxUPihzdG9wXy1zdGFydF8pLmNvdW50KCkpOwogICAgfQp9OwoKCmNsYXNzIFN1ZG9rdQp7CnB1YmxpYzoKICAgIFN1ZG9rdShib29sIGNsZWFuID0gdHJ1ZSk7CiAgICBTdWRva3UoY29uc3QgU3Vkb2t1JnMpICAgICAgICAgICAgICB7IG1lbWNweShwLHMucCxzaXplb2YocCkpOyB9CiAgICBTdWRva3UoY29uc3QgY2hhciAqKTsKICAgIFN1ZG9rdSYgb3BlcmF0b3IgPSAoY29uc3QgU3Vkb2t1JnMpIHsgbWVtY3B5KHAscy5wLHNpemVvZihwKSk7IHJldHVybiAqdGhpczsgfQogICAgflN1ZG9rdSgpIHt9OwoKICAgIGludCAgICBvcGVyYXRvcigpKGludCByLCBpbnQgYykgY29uc3Q7CiAgICBpbnQmICAgb3BlcmF0b3IoKShpbnQgciwgaW50IGMpIHsgcmV0dXJuIHBbci0xXVtjLTFdOyB9CiAgICBpbnQgICAgb2sgICAgICAgICgpIGNvbnN0OwogICAgdm9pZCAgIHNodWZmbGUgICAoaW50IGNvdW50ID0gMyk7CiAgICB2b2lkICAgb3V0ICAgICAgICgpIGNvbnN0OwogICAgaW50ICAgIHplcm9zICAgICAoKSBjb25zdDsKICAgIFN1ZG9rdSBzb2xpZFNvbHZlKCkgY29uc3Q7CiAgICBTdWRva3UgYWRkWmVyb3MgIChpbnQgbWF4KSBjb25zdDsKICAgIFN1ZG9rdSBzb2x2ZSAgICAgKGludCZjb3VudCkgY29uc3Q7CgogICAgdm9pZCBHZW5lcmF0ZSgpOwpwcml2YXRlOgogICAgYm9vbCBHZW4oKTsKICAgIHN0YXRpYyB2b2lkIHRyeVNvbHZlKFN1ZG9rdSZzLCBTdWRva3UmIHJlc3VsdCwgaW50JiBjb3VudCApOwogICAgdm9pZCBzd2FwU3FSKGludCBpLCBpbnQgaik7CiAgICB2b2lkIHN3YXBTcUMoaW50IGksIGludCBqKTsKICAgIHZvaWQgc3dhcFJvdyhpbnQgaSwgaW50IGopOwogICAgdm9pZCBzd2FwQ29sKGludCBpLCBpbnQgaik7CiAgICB2b2lkIHBlcm11dCAoaW50KnBlcm0pOwogICAgdm9pZCBzd2FwKGludCZpLGludCZqKSB7IGludCB0ID0gaTsgaSA9IGo7IGogPSB0OyB9CiAgICBpbnQgIGNoZWNrKGludCByLCBpbnQgYykgY29uc3Q7ICAgICAgIC8vID8gID8gLSA/CiAgICBpbnQgIGNoZWNrQ291bnQoaW50IHIsIGludCBjKSBjb25zdDsgIC8vID8gPz8KICAgIGludCBwWzldWzldOwp9OwoKaW5saW5lIGludCAgU3Vkb2t1Ojp6ZXJvcygpIGNvbnN0IC8qZm9sZDAwKi8KewogICAgaW50IHogPSAwOwogICAgZm9yKGludCBpID0gMDsgaSA8IHNpemVvZihwKS9zaXplb2YoaW50KTsgKytpKQogICAgICAgIGlmICgqKChpbnQqKXAraSkgPT0gMCkgKyt6OwogICAgcmV0dXJuIHo7Cn0KCmlubGluZSBpbnQgU3Vkb2t1OjpvaygpIGNvbnN0IC8qZm9sZDAwKi8KewogICAgaWYgKHplcm9zKCkpIHJldHVybiAtMTsKICAgIHN0YXRpYyBjb25zdCBjaGFyIGNzdHJbXSA9ICItKysrKysrKysrIjsKICAgIC8vID8/ID8gID8KICAgIGZvcihpbnQgciA9IDA7IHIgPCA5OyArK3IpCiAgICB7CiAgICAgICAgY2hhciBoWzExXSA9IHswfSwgdlsxMV0gPSB7MH07CiAgICAgICAgbWVtc2V0KGgsJy0nLDEwKTsgbWVtc2V0KHYsJy0nLDEwKTsKICAgICAgICBmb3IoaW50IGMgPSAwOyBjIDwgOTsgKytjKQogICAgICAgIHsKICAgICAgICAgICAgaFtwW3JdW2NdXSA9ICcrJzsKICAgICAgICAgICAgdltwW2NdW3JdXSA9ICcrJzsKICAgICAgICB9CiAgICAgICAgaWYgKHN0cmNtcChoLGNzdHIpKSByZXR1cm4gMDsKICAgICAgICBpZiAoc3RyY21wKHYsY3N0cikpIHJldHVybiAwOwogICAgfQogICAgLy8gPz8gPwogICAgZm9yKGludCBpID0gMDsgaSA8IDM7ICsraSkKICAgICAgICBmb3IoaW50IGogPSAwOyBqIDwgMzsgKytqKQogICAgICAgIHsKICAgICAgICAgICAgY2hhciBzWzExXSA9IHswfTsKICAgICAgICAgICAgbWVtc2V0KHMsJy0nLDEwKTsKICAgICAgICAgICAgZm9yKGludCByID0gaSozOyByIDwgaSozKzM7ICsrcikKICAgICAgICAgICAgICAgIGZvcihpbnQgYyA9IGoqMzsgYyA8IGoqMyArIDM7ICsrYykKICAgICAgICAgICAgICAgICAgICBzW3Bbcl1bY11dID0gJysnOwogICAgICAgICAgICBpZiAoc3RyY21wKHMsY3N0cikpCiAgICAgICAgICAgICAgICByZXR1cm4gMDsKICAgICAgICB9CiAgICByZXR1cm4gMTsKfQoKaW5saW5lIGludCBTdWRva3U6OmNoZWNrKGludCByLCBpbnQgYykgY29uc3QgLypmb2xkMDAqLwp7CiAgICBpbnQgYWxsb3dbOV0gPSB7MSwyLDMsNCw1LDYsNyw4LDl9OwogICAgLy8gPz8gPz8KICAgIGZvcihpbnQgeCA9IDA7IHggPCA5OyArK3gpCiAgICB7CiAgICAgICAgaWYgKHBbeF1bY10gJiYgKHIgIT0geCkpIGFsbG93W3BbeF1bY10tMV0gPSAwOwogICAgICAgIGlmIChwW3JdW3hdICYmIChjICE9IHgpKSBhbGxvd1twW3JdW3hdLTFdID0gMDsKICAgIH0KICAgIC8vID8/IAogICAgaW50IHJxID0gKHIvMykqMzsKICAgIGludCBjcSA9IChjLzMpKjM7CiAgICBmb3IoaW50IHggPSAwOyB4IDwgMzsgKyt4KQogICAgICAgIGZvcihpbnQgeSA9IDA7IHkgPCAzOyArK3kpCiAgICAgICAgewogICAgICAgICAgICBpbnQgcnggPSBycSArIHg7CiAgICAgICAgICAgIGludCBjeSA9IGNxICsgeTsKCiAgICAgICAgICAgIGlmIChwW3J4XVtjeV0gJiYgKChyeCAhPSByKSB8fCAoY3kgIT0gYykpKQogICAgICAgICAgICAgICAgYWxsb3dbcFtyeF1bY3ldLTFdID0gMDsKICAgICAgICB9CgogICAgaW50IG5vbnplcm8gPSAwOwogICAgaW50IHJlc3VsdCAgPSAwOwogICAgZm9yKGludCBpID0gMDsgaSA8IDk7ICsraSkKICAgICAgICBpZiAoYWxsb3dbaV0pCiAgICAgICAgewogICAgICAgICAgICBpZiAoKytub256ZXJvID4gMSkgYnJlYWs7CiAgICAgICAgICAgIHJlc3VsdCA9IGFsbG93W2ldOwogICAgICAgIH0KICAgIGlmIChub256ZXJvICE9IDEpIHJldHVybiAwOwogICAgcmV0dXJuIHJlc3VsdDsKfQoKaW5saW5lIGludCBTdWRva3U6OmNoZWNrQ291bnQoaW50IHIsIGludCBjKSBjb25zdCAvKkZPTEQwMCovCnsKICAgIGludCBhbGxvd1s5XSA9IHsxLDIsMyw0LDUsNiw3LDgsOX07CiAgICAvLyA/PyA/PwogICAgZm9yKGludCB4ID0gMDsgeCA8IDk7ICsreCkKICAgIHsKICAgICAgICBpZiAocFt4XVtjXSAmJiAociAhPSB4KSkgYWxsb3dbcFt4XVtjXS0xXSA9IDA7CiAgICAgICAgaWYgKHBbcl1beF0gJiYgKGMgIT0geCkpIGFsbG93W3Bbcl1beF0tMV0gPSAwOwogICAgfQogICAgLy8gPz8gCiAgICBpbnQgcnEgPSAoci8zKSozOwogICAgaW50IGNxID0gKGMvMykqMzsKICAgIGZvcihpbnQgeCA9IDA7IHggPCAzOyArK3gpCiAgICAgICAgZm9yKGludCB5ID0gMDsgeSA8IDM7ICsreSkKICAgICAgICB7CiAgICAgICAgICAgIGludCByeCA9IHJxICsgeDsKICAgICAgICAgICAgaW50IGN5ID0gY3EgKyB5OwoKICAgICAgICAgICAgaWYgKHBbcnhdW2N5XSAmJiAoKHJ4ICE9IHIpIHx8IChjeSAhPSBjKSkpCiAgICAgICAgICAgICAgICBhbGxvd1twW3J4XVtjeV0tMV0gPSAwOwogICAgICAgIH0KCiAgICBpbnQgbm9uemVybyA9IDA7CiAgICBmb3IoaW50IGkgPSAwOyBpIDwgOTsgKytpKQogICAgICAgIGlmIChhbGxvd1tpXSkKICAgICAgICB7CiAgICAgICAgICAgICsrbm9uemVybzsKICAgICAgICB9CiAgICByZXR1cm4gbm9uemVybzsKfQoKU3Vkb2t1IFN1ZG9rdTo6c29saWRTb2x2ZSgpIGNvbnN0IC8qZm9sZDAwKi8KewogICAgU3Vkb2t1IHMoKnRoaXMpOwogICAgd2hpbGUocy56ZXJvcygpKQogICAgewogICAgICAgIGJvb2wgZm91bmQgPSBmYWxzZTsKICAgICAgICBmb3IoaW50IGkgPSAwOyBpIDwgOTsgKytpKQogICAgICAgICAgICBmb3IoaW50IGogPSAwOyBqIDwgOTsgKytqKQogICAgICAgICAgICAgICAgaWYgKHMucFtpXVtqXSA9PSAwKQogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGludCByZXMgPSBzLmNoZWNrKGksaik7CiAgICAgICAgICAgICAgICAgICAgaWYgKHJlcykKICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgIGZvdW5kID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgcy5wW2ldW2pdID0gcmVzOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICBpZiAoIWZvdW5kKSBicmVhazsKICAgIH0KICAgIHJldHVybiBzOwp9CgoKClN1ZG9rdTo6U3Vkb2t1KGNvbnN0IGNoYXIgKiBzKSAvKkZPTEQwMCovCnsKICAgIGZvcihpbnQgciA9IDA7IHIgPCA5OyArK3IpCiAgICAgICAgZm9yKGludCBjID0gMDsgYyA8IDk7ICsrYykKICAgICAgICB7CiAgICAgICAgICAgIHdoaWxlKCFpc2RpZ2l0KCpzKSkgKytzOwogICAgICAgICAgICBwW3JdW2NdID0gKnMgLSAnMCc7CiAgICAgICAgICAgICsrczsKICAgICAgICB9Cn0KCgpTdWRva3U6OlN1ZG9rdShib29sIGNsZWFuKSAvKkZPTEQwMCovCnsKICAgIHN0YXRpYyBpbnQgc2RbOV1bOV0gPSB7CiAgICAgICAgezEsMiwzLDQsNSw2LDcsOCw5fSwKICAgICAgICB7NCw1LDYsNyw4LDksMSwyLDN9LAogICAgICAgIHs3LDgsOSwxLDIsMyw0LDUsNn0sCiAgICAgICAgezIsMywxLDUsNiw0LDgsOSw3fSwKICAgICAgICB7NSw2LDQsOCw5LDcsMiwzLDF9LAogICAgICAgIHs4LDksNywyLDMsMSw1LDYsNH0sCiAgICAgICAgezMsMSwyLDYsNCw1LDksNyw4fSwKICAgICAgICB7Niw0LDUsOSw3LDgsMywxLDJ9LAogICAgICAgIHs5LDcsOCwzLDEsMiw2LDQsNX0KICAgIH07CgogICAgaWYgKGNsZWFuKQogICAgewogICAgICAgIGZvcihpbnQgaSA9IDA7IGkgPCA5OyArK2kpCiAgICAgICAgICAgIGZvcihpbnQgaiA9IDA7IGogPCA5OyArK2opCiAgICAgICAgICAgICAgICBwW2ldW2pdID0gMDsKICAgIH0KICAgIGVsc2UKICAgIHsKICAgICAgICBHZW5lcmF0ZSgpOwogICAgICAgIC8vZm9yKGludCBpID0gMDsgaSA8IDk7ICsraSkKICAgICAgICAvLyAgICBmb3IoaW50IGogPSAwOyBqIDwgOTsgKytqKQogICAgICAgIC8vICAgICAgICBwW2ldW2pdID0gc2RbaV1bal07CiAgICAgICAgLy9zaHVmZmxlKCk7CiAgICB9Cn0KCnZvaWQgU3Vkb2t1OjpwZXJtdXQgKGludCpwZXJtKSAvKkZPTEQwMCovCnsKICAgIGZvcihpbnQgaSA9IDA7IGkgPCA5OyArK2kpCiAgICAgICAgZm9yKGludCBqID0gMDsgaiA8IDk7ICsraikKICAgICAgICAgICAgcFtpXVtqXSA9IHBlcm1bcFtpXVtqXS0xXTsKfQoKdm9pZCBTdWRva3U6Om91dCgpIGNvbnN0IC8qZm9sZDAwKi8KewogICAgZm9yKGludCBpID0gMDsgaSA8IDk7ICsraSkKICAgIHsKICAgICAgICBmb3IoaW50IGogPSAwOyBqIDwgOTsgKytqKQogICAgICAgICAgICBwcmludGYoIiVkIixwW2ldW2pdKTsKICAgICAgICBwcmludGYoIlxuIik7CiAgICB9Cn0KCnZvaWQgU3Vkb2t1OjpzaHVmZmxlKGludCBjb3VudCkgLypGT0xEMDAqLwp7CiAgICBpbnQgcGVybVs5XSA9IHsxLDIsMyw0LDUsNiw3LDgsOX07CiAgICBmb3IoaW50IGsgPSA4OyBrID4gMDsgLS1rKQogICAgewogICAgICAgIHN3YXAocGVybVtrXSxwZXJtW3JhbmQoKSVrXSk7CiAgICB9CiAgICBpbnQgaSxqLGw7CiAgICBmb3IoaW50IGsgPSAwOyBrIDwgY291bnQ7IGsrKykKICAgIHsKICAgICAgICBpID0gcmFuZCgpJTM7IGogPSByYW5kKCklMzsgIHN3YXBTcVIoaSxqKTsKICAgICAgICBpID0gcmFuZCgpJTM7IGogPSByYW5kKCklMzsgIHN3YXBTcUMoaSxqKTsKICAgICAgICBpID0gcmFuZCgpJTM7IGogPSByYW5kKCklMzsgIGwgPSByYW5kKCklMzsgc3dhcFJvdyhpK2wqMyxqK2wqMyk7CiAgICAgICAgaSA9IHJhbmQoKSUzOyBqID0gcmFuZCgpJTM7ICBsID0gcmFuZCgpJTM7IHN3YXBDb2woaStsKjMsaitsKjMpOwogICAgICAgIHBlcm11dChwZXJtKTsKICAgIH0KfQoKdm9pZCBTdWRva3U6OnN3YXBTcVIoaW50IGksIGludCBqKSAvKmZvbGQwMCovCnsKICAgIGlmICgoaT49MCkmJihpPD0yKSYmCiAgICAgICAgKGo+PTApJiYoajw9MikmJgogICAgICAgIChpICE9IGopKQogICAgewogICAgICAgIGZvcihpbnQgciA9IDA7IHIgPCAzOyArK3IpCiAgICAgICAgICAgIGZvcihpbnQgYyA9IDA7IGMgPCA5OyArK2MpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIHN3YXAocFtpKjMrcl1bY10scFtqKjMrcl1bY10pOwogICAgICAgICAgICB9CiAgICB9Cn0Kdm9pZCBTdWRva3U6OnN3YXBTcUMoaW50IGksIGludCBqKSAvKmZvbGQwMCovCnsKICAgIGlmICgoaT49MCkmJihpPD0yKSYmCiAgICAgICAgKGo+PTApJiYoajw9MikmJgogICAgICAgIChpICE9IGopKQogICAgewogICAgICAgIGZvcihpbnQgYyA9IDA7IGMgPCAzOyArK2MpCiAgICAgICAgICAgIGZvcihpbnQgciA9IDA7IHIgPCA5OyArK3IpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIHN3YXAocFtyXVtpKjMrY10scFtyXVtqKjMrY10pOwogICAgICAgICAgICB9CiAgICB9Cn0Kdm9pZCBTdWRva3U6OnN3YXBSb3coaW50IGksIGludCBqKSAvKmZvbGQwMCovCnsKICAgIGlmICgoaT49MCkmJihpPD04KSYmCiAgICAgICAgKGo+PTApJiYoajw9OCkmJgogICAgICAgIChpLzMgPT0gai8zKSYmCiAgICAgICAgKGkgIT0gaikpCiAgICB7CiAgICAgICAgZm9yKGludCBjID0gMDsgYyA8IDk7ICsrYykKICAgICAgICAgICAgc3dhcChwW2ldW2NdLHBbal1bY10pOwogICAgfQp9CnZvaWQgU3Vkb2t1Ojpzd2FwQ29sKGludCBpLCBpbnQgaikgLypmb2xkMDAqLwp7CiAgICBpZiAoKGk+PTApJiYoaTw9OCkmJgogICAgICAgIChqPj0wKSYmKGo8PTgpJiYKICAgICAgICAoaS8zID09IGovMykmJgogICAgICAgIChpICE9IGopKQogICAgewogICAgICAgIGZvcihpbnQgciA9IDA7IHIgPCA5OyArK3IpCiAgICAgICAgICAgIHN3YXAocFtyXVtpXSxwW3JdW2pdKTsKICAgIH0KfQoKaW50ICBTdWRva3U6Om9wZXJhdG9yKCkoaW50IHIsIGludCBjKSBjb25zdCAvKmZvbGQwMCovCnsKICAgIGlmIChyIDwgMCkgcmV0dXJuIC0xOwogICAgaWYgKGMgPCAwKSByZXR1cm4gLTE7CiAgICBpZiAociA+IDgpIHJldHVybiAtMTsKICAgIGlmIChjID4gOCkgcmV0dXJuIC0xOwogICAgcmV0dXJuIHBbcl1bY107Cn0KClN1ZG9rdSBTdWRva3U6OmFkZFplcm9zKGludCBtYXgpIGNvbnN0IC8qRk9MRDAwKi8KewogICAgU3Vkb2t1IHMoKnRoaXMpOyAvLyA/CiAgICB3aGlsZShzLnplcm9zKCkgPCBtYXgpCiAgICB7CiAgICAgICAgaW50IG5vbnplcm9zID0gODEgLSBzLnplcm9zKCk7CiAgICAgICAgYm9vbCBhZGRlZCA9IGZhbHNlOwogICAgICAgIC8vcHJpbnRmKCJaZXJvcyA9ICVkXG4iLHMuemVyb3MoKSk7CiAgICAgICAgZm9yKGludCBpID0gMDsgaSA8IG5vbnplcm9zOyArK2kpIC8vID8uLi4KICAgICAgICB7CiAgICAgICAgICAgIFN1ZG9rdSB0KHMpOyAvLyA/CiAgICAgICAgICAgIGludCBxID0gcmFuZCgpJW5vbnplcm9zOwogICAgICAgICAgICBmb3IoaW50IHIgPSAwOyByIDwgOTsgKytyKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBmb3IoaW50IGMgPSAwOyBjIDwgOTsgKytjKQogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGlmICh0LnBbcl1bY10gPT0gMCkgY29udGludWU7CiAgICAgICAgICAgICAgICAgICAgaWYgKHEgPiAwKQogICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgLS1xOwogICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgdC5wW3JdW2NdID0gMDsKICAgICAgICAgICAgICAgICAgICBpbnQgY291bnQgPSAxOwogICAgICAgICAgICAgICAgICAgIC8vU3Vkb2t1IHNvbCA9IHQuc29saWRTb2x2ZSgpOwogICAgICAgICAgICAgICAgICAgIFN1ZG9rdSBzb2wgPSB0LnNvbGlkU29sdmUoKTsKICAgICAgICAgICAgICAgICAgICBpZiAoKHNvbC5vaygpID09IDEpJiYoY291bnQgPT0gMSkpCiAgICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICAgICBhZGRlZCA9IHRydWU7CiAgICAgICAgICAgICAgICAgICAgICAgIC8vcHJpbnRmKCJzLnplcm9zKCkgPSAlZFxuIixzLnplcm9zKCkpOwogICAgICAgICAgICAgICAgICAgICAgICAvL3ByaW50ZigiQWRkZWQuLi5cbiIpOwogICAgICAgICAgICAgICAgICAgICAgICBzID0gdDsKICAgICAgICAgICAgICAgICAgICAgICAgLy9wcmludGYoInMuemVyb3MoKSA9ICVkXG4iLHMuemVyb3MoKSk7CiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGlmIChhZGRlZCkgYnJlYWs7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGFkZGVkKSBicmVhazsKICAgICAgICB9CiAgICAgICAgaWYgKCFhZGRlZCkgLy8gPyAgLi4uID8/IAogICAgICAgIHsKICAgICAgICAgICAgZm9yKGludCBpID0gMDsgaSA8IG5vbnplcm9zOyArK2kpIC8vID8uLi4KICAgICAgICAgICAgewogICAgICAgICAgICAgICAgU3Vkb2t1IHQocyk7IC8vID8KICAgICAgICAgICAgICAgIGludCBxID0gcmFuZCgpJW5vbnplcm9zOwogICAgICAgICAgICAgICAgZm9yKGludCByID0gMDsgciA8IDk7ICsrcikKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBmb3IoaW50IGMgPSAwOyBjIDwgOTsgKytjKQogICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHQucFtyXVtjXSA9PSAwKSBjb250aW51ZTsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHEgPiAwKQogICAgICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAtLXE7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICB0LnBbcl1bY10gPSAwOwogICAgICAgICAgICAgICAgICAgICAgICBpbnQgY291bnQ7CiAgICAgICAgICAgICAgICAgICAgICAgIFN1ZG9rdSBzb2wgPSB0LnNvbHZlKGNvdW50KTsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKChzb2wub2soKSA9PSAxKSYmKGNvdW50ID09IDEpKQogICAgICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRlZCA9IHRydWU7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL3ByaW50Zigicy56ZXJvcygpID0gJWRcbiIscy56ZXJvcygpKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vcHJpbnRmKCJBZGRlZC4uLlxuIik7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzID0gdDsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vcHJpbnRmKCJzLnplcm9zKCkgPSAlZFxuIixzLnplcm9zKCkpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgaWYgKGFkZGVkKSBicmVhazsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGlmIChhZGRlZCkgYnJlYWs7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaWYgKCFhZGRlZCkgYnJlYWs7CiAgICB9CiAgICByZXR1cm4gczsKfQoKClN1ZG9rdSBTdWRva3U6OnNvbHZlKGludCZjb3VudCkgY29uc3QgLypGT0xEMDAqLwp7CiAgICBTdWRva3UgcyA9IHNvbGlkU29sdmUoKTsKICAgIGlmIChzLm9rKCkgPT0gMSkKICAgIHsKICAgICAgICBjb3VudCA9IDE7CiAgICAgICAgcmV0dXJuIHM7CiAgICB9CiAgICBzID0gKnRoaXM7CiAgICBjb3VudCA9IDA7CiAgICBTdWRva3UgcmVzID0gczsKICAgIHRyeVNvbHZlKHMscmVzLGNvdW50KTsKICAgIHJldHVybiByZXM7Cn0KCmludCBsZXZlbCA9IDA7Cgp2b2lkIFN1ZG9rdTo6dHJ5U29sdmUoU3Vkb2t1JnMsIFN1ZG9rdSZyZXMsIGludCZjb3VudCkgLypGT0xEMDAqLwp7CiAgICBpZiAocy56ZXJvcygpID09IDApIHJldHVybjsgLy8gID8KICAgIGlmIChjb3VudCA+IDEpICAgICAgcmV0dXJuOwoKICAgICsrbGV2ZWw7CiAgICAvL3ByaW50ZigiICAgICAgICAgICAgIExldmVsICUzZCwgemVyb3MgJTNkLCBjb3VudCAlMmRcciIsbGV2ZWwscy56ZXJvcygpLCBjb3VudCk7CiAgICAvL2ZmbHVzaChzdGRvdXQpOwoKICAgIC8vID8gCiAgICBpbnQgciA9IC0xLCBjID0gLTE7CiAgICBpbnQgY250ID0gOTsKICAgIGZvcihpbnQgeCA9IDA7IHggPCA5OyArK3gpCiAgICB7CiAgICAgICAgZm9yKGludCB5ID0gMDsgeSA8IDk7ICsreSkKICAgICAgICB7CiAgICAgICAgICAgIGlmIChzLnBbeF1beV0pIGNvbnRpbnVlOwogICAgICAgICAgICBpbnQgY291bnQgPSBzLmNoZWNrQ291bnQoeCx5KTsKICAgICAgICAgICAgaWYgKGNudCA+PSBjb3VudCkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgciA9IHg7CiAgICAgICAgICAgICAgICBjID0geTsKICAgICAgICAgICAgICAgIGNudCA9IGNvdW50OwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIGFzc2VydCgociA+PSAwKSAmJiAoYyA+PSAwKSk7CgogICAgLy8gPz8gPyA/ID8KICAgIGludCBhbGxvd1s5XSA9IHsgMSwyLDMsNCw1LDYsNyw4LDkgfTsKICAgIGZvcihpbnQgeCA9IDA7IHggPCA5OyArK3gpCiAgICB7CiAgICAgICAgaWYgKHMucFtyXVt4XSkgYWxsb3dbcy5wW3JdW3hdLTFdID0gMDsKICAgICAgICBpZiAocy5wW3hdW2NdKSBhbGxvd1tzLnBbeF1bY10tMV0gPSAwOwogICAgfQogICAgZm9yKGludCB4ID0gMDsgeCA8IDM7ICsreCkKICAgICAgICBmb3IoaW50IHkgPSAwOyB5IDwgMzsgKyt5KQogICAgICAgICAgICBpZiAocy5wWyhyLzMpKjMreF1bKGMvMykqMyt5XSkKICAgICAgICAgICAgICAgIGFsbG93W3MucFsoci8zKSozK3hdWyhjLzMpKjMreV0tMV0gPSAwOwoKICAgIGZvcihpbnQgaSA9IDA7IGkgPCA5OyArK2kpCiAgICB7CiAgICAgICAgaWYgKGFsbG93W2ldID09IDApIGNvbnRpbnVlOwogICAgICAgIHMucFtyXVtjXSA9IGFsbG93W2ldOwogICAgICAgIFN1ZG9rdSB2ID0gcy5zb2xpZFNvbHZlKCk7CiAgICAgICAgaWYgKHYub2soKSA9PSAxKSAvLyA/IAogICAgICAgIHsKICAgICAgICAgICAgcmVzID0gdjsKICAgICAgICAgICAgY291bnQrKzsKICAgICAgICAgICAgaWYgKGNvdW50ID4gMSkgYnJlYWs7CiAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgIH0KICAgICAgICB0cnlTb2x2ZShzLHJlcyxjb3VudCk7CiAgICAgICAgaWYgKGNvdW50ID4gMSkgYnJlYWs7CiAgICB9CiAgICBzLnBbcl1bY10gPSAwOwogICAgLS1sZXZlbDsKfQoKCnZvaWQgU3Vkb2t1OjpHZW5lcmF0ZSgpCnsKICAgIGZvcihpbnQgciA9IDA7IHIgPCA5OyArK3IpCiAgICAgICAgZm9yKGludCBjID0gMDsgYyA8IDk7ICsrYykKICAgICAgICAgICAgcFtyXVtjXSA9IChyID09IDApID8gYyArIDEgOiAwOwogICAgR2VuKCk7CiAgICBzaHVmZmxlKCk7Cn0KCmJvb2wgU3Vkb2t1OjpHZW4oKQp7CiAgICBpZiAoemVyb3MoKSA9PSAwKSByZXR1cm4gdHJ1ZTsKICAgIC8vID8gID8KICAgIGludCByLCBjOwogICAgZm9yKGludCB4ID0gMDsgeCA8IDk7ICsreCkKICAgICAgICBmb3IoaW50IHkgPSAwOyB5IDwgOTsgKyt5KQogICAgICAgIHsKICAgICAgICAgICAgaWYgKHBbeF1beV0pIGNvbnRpbnVlOwogICAgICAgICAgICByID0geDsKICAgICAgICAgICAgYyA9IHk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgIH0KCiAgICAvLyA/PyA/ID8gPwogICAgaW50IGFsbG93WzldID0geyAxLDIsMyw0LDUsNiw3LDgsOSB9OwogICAgZm9yKGludCB4ID0gMDsgeCA8IDk7ICsreCkKICAgIHsKICAgICAgICBpZiAocFtyXVt4XSkgYWxsb3dbcFtyXVt4XS0xXSA9IDA7CiAgICAgICAgaWYgKHBbeF1bY10pIGFsbG93W3BbeF1bY10tMV0gPSAwOwogICAgfQogICAgZm9yKGludCB4ID0gMDsgeCA8IDM7ICsreCkKICAgICAgICBmb3IoaW50IHkgPSAwOyB5IDwgMzsgKyt5KQogICAgICAgICAgICBpZiAocFsoci8zKSozK3hdWyhjLzMpKjMreV0pCiAgICAgICAgICAgICAgICBhbGxvd1twWyhyLzMpKjMreF1bKGMvMykqMyt5XS0xXSA9IDA7CgogICAgLy8gPz8gID8gPwogICAgZm9yKGludCBrID0gODsgayA+IDA7IC0taykKICAgICAgICBzd2FwKGFsbG93W2tdLGFsbG93W3JhbmQoKSVrXSk7CiAgICBmb3IoaW50IGsgPSAwOyBrIDwgOTsgKytrKQogICAgewogICAgICAgIGlmIChhbGxvd1trXSA9PSAwKSBjb250aW51ZTsKICAgICAgICBwW3JdW2NdID0gYWxsb3dba107CiAgICAgICAgaWYgKHplcm9zKCkgPT0gMCkKICAgICAgICB7CiAgICAgICAgICAgIGlmIChvaygpID09IDEpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIC8vcHJpbnRmKCItLS0tLS0tLS1cbiIpOwogICAgICAgICAgICAgICAgLy9vdXQoKTsKICAgICAgICAgICAgICAgIC8vcHJpbnRmKCItLS0tLS0tLS1cbiIpOwogICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaWYgKEdlbigpKSByZXR1cm4gdHJ1ZTsKICAgIH0KICAgIHBbcl1bY10gPSAwOwogICAgcmV0dXJuIGZhbHNlOwp9CgppbnQgbWFpbihpbnQgYXJnYywgY29uc3QgY2hhciAqIGFyZ3ZbXSkgLypGT0xEMDAqLwp7CgogICAgbXVUaW1lciBtdDsKICAgIHNyYW5kKHRpbWUoMCkpOwogICAgU3Vkb2t1IHMoIjgwMDAwMDAwMDAwMzYwMDAwMDA3MDA5MDIwMDA1MDAwNzAwMDAwMDA0NTcwMDAwMDEwMDAzMDAwMTAwMDA2ODAwODUwMDAxMDA5MDAwMDQwMCIpOwogICAgaW50IGNvdW50OwogICAgcyA9IHMuc29sdmUoY291bnQpOwogICAgbXQuc3RvcCgpOwogICAgcy5vdXQoKTsKICAgIHByaW50ZigiQ291bnQgPSAlZFxuIixjb3VudCk7CiAgICBwcmludGYoIlplcm9zID0gJWRcbiIscy56ZXJvcygpKTsKCiAgICBwcmludGYoIiVsbHUgbWtzXG4iLG10LmR1cmF0aW9uKCkpOwoKICAgIGV4aXQoMCk7CiAgICBTdWRva3UgdCA9IHM7CiAgICB0LkdlbmVyYXRlKCk7CiAgICB0Lm91dCgpOwogICAgcHJpbnRmKCJaZXJvcyA9ICVkLCBvayA9ICVkXG4iLHQuemVyb3MoKSwgdC5vaygpKTsKfQo=