import java.util.*;
import java.util.stream.*;
import java.lang.*;
import java.io.*;
import static java.
lang.
Math.
*;
};
return sw.toString();
}
public static int rangecheck
(int x,
int min,
int max,
String what
) { if (x < min || x > max) throw BadArgf("Bad %s: %d, should be [%d; %d].", what, x, min, max);
return x;
}
}
class Bitfield2D {
int[] data;
int w, h;
static final int BASE
= Integer.
SIZE; static final int SANE_BITS_LIMIT = 1_000_000_000;
static final int SANE_DIMENSION_LIMIT = 100_000_000;
public Bitfield2D(int w, int h) { init(null, w, h); }
Bitfield2D(int[] data, int w, int h) { init(data, w, h); }
private void init(int[] data, int w, int h) {
validateSize(w, h);
assert data == null || data.length >= (w*h + (BASE - 1)) / BASE;
this.data = data != null ? data : new int[(w*h + (BASE - 1)) / BASE];
this.w = w;
this.h = h;
}
static void validateSize(int w, int h) {
if (w < 0 || h < 0 || w > SANE_DIMENSION_LIMIT || h > SANE_DIMENSION_LIMIT
|| w > 0 && h > SANE_BITS_LIMIT / w)
throw Util.
BadArgf("Bad bitfield size: %d×%d.", w, h
); }
public boolean validCoord(int x, int y) {
return x >= 0 && y >= 0 && x < w && y < h;
}
public void validateCoord(int x, int y) {
if (!validCoord(x, y))
throw Util.
BadArgf("Bad coord of bitfield %d×%d: (%d, %d).",
this.
w,
this.
h, x, y
); }
void validateRect(int x, int y, int w, int h) {
if (x < 0 || y < 0 || w < 0 || h < 0 || x + w > this.w || y + h > this.h)
throw Util.
BadArgf("Bad rect of bitfield %d×%d: (%d, %d) ~ (%d, %d).",
this.w, this.h, x, y, x+w, y+h);
}
boolean rawget(int index) { return (data[index / BASE] & (1 << (index % BASE))) != 0; }
void rawset(int index) { data[index / BASE] |= 1 << (index % BASE); }
void rawunset(int index) { data[index / BASE] &= ~(1 << (index % BASE)); }
void rawset(int index, boolean value) { if (value) rawset(index); else rawunset(index); }
public boolean get(int x, int y) { validateCoord(x, y); return rawget(y*w+x); }
public void set(int x, int y) { validateCoord(x, y); rawset(y*w+x); }
public void unset(int x, int y) { validateCoord(x, y); rawunset(y*w+x); }
public void set(int x, int y, boolean value) { validateCoord(x, y); rawset(y*w+x, value); }
public int width() { return w; }
public int height() { return h; }
// For functions like or() that apply one bitfield to another,
// reduces potentially out-of-borders input to its valid part.
static class CoordWarden {
int srcX, srcY, w, h, destX, destY;
CoordWarden(Bitfield2D dest, Bitfield2D src, int aSrcX, int aSrcY, int aW, int aH, int aDestX, int aDestY) {
src.validateRect(aSrcX, aSrcY, aW, aH);
srcX = aSrcX; srcY = aSrcY; w = aW; h = aH; destX = aDestX; destY = aDestY;
if (destX < 0) { srcX -= destX; w += destX; destX = 0; }
if (destX + w > dest.w) { w = dest.w - destX; }
if (destY < 0) { srcY -= destY; h += destY; destY = 0; }
if (destY + h > dest.h) { h = dest.h - destY; }
}
}
public void or(Bitfield2D b, int destX, int destY) {
or(b, 0, 0, b.w, b.h, destX, destY);
}
public void or(Bitfield2D b, int bx, int by, int w, int h, int destX, int destY) {
var ward = new CoordWarden(this, b, bx, by, w, h, destX, destY);
int thisOfs = ward.destY*this.w + ward.destX, bOfs = ward.srcY*b.w + ward.srcX;
for (by = 0; by < ward.h; by++, thisOfs += this.w - ward.w, bOfs += b.w - ward.w) {
for (bx = 0; bx < ward.w; bx++, thisOfs++, bOfs++)
if (b.rawget(bOfs)) this.rawset(thisOfs);
}
}
public void andNot(Bitfield2D b, int destX, int destY) {
andNot(b, 0, 0, b.w, b.h, destX, destY);
}
public void andNot(Bitfield2D b, int bx, int by, int w, int h, int destX, int destY) {
var ward = new CoordWarden(this, b, bx, by, w, h, destX, destY);
int thisOfs = ward.destY*this.w + ward.destX, bOfs = ward.srcY*b.w + ward.srcX;
for (by = 0; by < ward.h; by++, thisOfs += this.w - ward.w, bOfs += b.w - ward.w) {
for (bx = 0; bx < ward.w; bx++, thisOfs++, bOfs++)
if (b.rawget(bOfs)) this.rawunset(thisOfs);
}
}
public Bitfield2D copyFrom(Bitfield2D b, int destX, int destY) {
return copyFrom(b, 0, 0, b.w, b.h, destX, destY);
}
public Bitfield2D copyFrom(Bitfield2D b, int bx, int by, int w, int h, int destX, int destY) {
var ward = new CoordWarden(this, b, bx, by, w, h, destX, destY);
int thisOfs = ward.destY*this.w + ward.destX, bOfs = ward.srcY*b.w + ward.srcX;
for (by = 0; by < ward.h; by++, thisOfs += this.w, bOfs += b.w) {
copyBits(b.data, bOfs, this.data, thisOfs, ward.w);
}
return this;
}
static int readBitsSmall(int[] src, int srcPos, int count) {
assert count > 0 && count < BASE;
// 0 1 2 3 4 5 6
// src = ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
// ^srcPos=5
// ^srcPos+count=11
int bits = src[srcPos / BASE] >>> (srcPos % BASE); // FGH
if (count > BASE - srcPos % BASE)
bits |= src[srcPos / BASE + 1] << (BASE - srcPos % BASE); // FGH | 000IJKLMNOP = FGHIJKLMNOP
return bits & ((1 << count) - 1); // FGHIJK
}
static void writeBits1(int bits, int[] dst, int dstPos, int count) {
assert count > 0 && count < BASE - dstPos % BASE && bits < 1 << count;
// bits = qwer
// 0 1 2 3 4 5 6
// src = ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
// ^dstPos=3
// ^dstPos+count=7
dst[dstPos / BASE] = dst[dstPos / BASE] // ABCDEFGH
& ~(((1 << count) - 1) << (dstPos % BASE)) // ABC0000H
| (bits << (dstPos % BASE)); // ABCqwerH
}
static void copyBits(int[] src, int srcPos, int[] dst, int dstPos, int count) {
// Imagine BASE=8 (as if byte[] instead of int[]), srcPos = 3, dstPos = 2, count=25.
//
// 0 1 2 3 4 5 6
// src = ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
// ^srcPos=3 ^srcPos+count=28
// dst = ...............................................
// 0 ^dstPos=2 2 3 4 5
//
// First we align dstPos to the multiple of BASE by reading
// first BASE - dstPos%BASE bits with readBitsSmall() and writing them
// into the first cell of dst[] with writeBits1.
//
// We'll get:
// 0 1 2 3 4 5 6
// src = ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
// ^srcPos=9 ^srcPos+count=28
// dst = ..DEFGHI.......................................
// 0 1 2 3 4 5
// ^dstPos=8
if (dstPos % BASE != 0) {
int n = min(count, BASE - dstPos % BASE);
if (n > 0) writeBits1(readBitsSmall(src, srcPos, n), dst, dstPos, n);
srcPos += n;
dstPos += n;
count -= n;
}
// Now we fill whole cells while possible.
// We'll get:
// src = ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
// ^srcPos=25
// ^srcPos+count=28
// dst = ..DEFGHIJKLMNOPQRSTUVWXY.......................
// 0 1 2 3 4 5
// ^dstPos=24
if (srcPos % BASE == 0) {
// Aligned case. This is not even an optimization, because 'int' shifts are restricted to 0..31.
System.
arraycopy(src, srcPos
/ BASE, dst, dstPos
/ BASE, count
/ BASE
); } else {
// Unaligned case.
// src: ...ABCDE FGH.....
// ^srcPos
// dst: ........
for (int iSrc = srcPos / BASE, iDst = dstPos / BASE, iDstEd = iDst + count / BASE; iDst < iDstEd; iDst++, iSrc++)
dst[iDst] =
(src[iSrc] >>> (srcPos % BASE)) // ABCDE
| (src[iSrc + 1] << (BASE - srcPos % BASE)); // ABCDE | 00000FGH = ABCDEFGH
}
srcPos += count - count % BASE;
dstPos += count - count % BASE;
count %= BASE;
// Append the tail.
if (count > 0)
writeBits1(readBitsSmall(src, srcPos, count), dst, dstPos, count);
}
@Override
return toString("##", "..");
}
var sb = new StringBuilder();
for (int ofs = 0, y = 0; y < h; y++) {
if (y > 0) sb.append("\n");
for (int x = 0; x < w; x++, ofs++)
sb.append(rawget(ofs) ? one : zero);
}
return sb.toString();
}
static Bitfield2D parse
(String src
) { return parse
(src,
"##"); }
if (one.
isEmpty()) throw Util.
BadArgf("'one' can't be empty."); if (one.
indexOf('\n') >= 0) throw Util.
BadArgf("Bad 'one': \"%s\". Shouldn't contain EOL.", one
); // Prepass for size.
int w = 0, h = 0;
for (int pos = 0; pos < src.length(); ) {
int eolp = src.indexOf("\n", pos);
if (eolp < 0) eolp = src.length();
if ((eolp - pos) % one.length() != 0)
throw Util.
BadArgf("Line %d:\n%s\ncontains %d character%s, which is not multiple of len(%s) = %d.",
h, src.substring(pos, eolp), eolp - pos, eolp - pos != 1 ? "s" : "", one, one.length());
w = max(w, (eolp - pos) / one.length());
h++;
pos = eolp + "\n".length();
}
var r = new Bitfield2D(w, h);
for (int y = 0, x = 0, ofs = 0, pos = 0; pos < src.length(); )
if (src.charAt(pos) == '\n') {
ofs += r.w - x;
x = 0; y++;
pos += "\n".length();
} else {
if (src.startsWith(one, pos)) r.rawset(ofs);
pos += one.length();
x++; ofs++;
}
return r;
}
}
class Ideone
{
// Auto-growing bitfield for procedural generation when resulting size is impractical to predict.
static class ProcBitfield2D {
Bitfield2D b = new Bitfield2D(0, 0);
int ax, ay, bx, by, boundAx, boundAy, boundBx, boundBy;
void set(int x, int y) {
if (boundAx == boundBx) {
ax = x; ay = y; bx = x; by = y;
boundAx = x; boundAy = y; boundBx = x; boundBy = y;
}
if (x < ax || y < ay || x >= bx || y >= by)
grow(
x < ax ? growStgy(ax - x, bx - ax) : 0,
y < ay ? growStgy(ay - y, by - ay) : 0,
x >= bx ? growStgy(x - bx + 1, bx - ax) : 0,
y >= by ? growStgy(y - by + 1, by - ay) : 0);
if (x < boundAx) boundAx = x;
if (x >= boundBx) boundBx = x + 1;
if (y < boundAy) boundAy = y;
if (y >= boundBy) boundBy = y + 1;
b.set(x-ax, y-ay);
}
void unset(int x, int y) {
if (x >= boundAx && x < boundBx && x >= boundAy && x < boundBy)
b.unset(x-ax, y-ay);
}
void set(int x, int y, boolean value) { if (value) set(x, y); else unset(x, y); }
static int growStgy(int atLeast, int present) {
return max(max(8, present / 2), atLeast);
}
void grow(int Lx, int Ly, int Rx, int Ry) {
this.b = new Bitfield2D((bx - ax) + Lx + Rx, (by - ay) + Ly + Ry).copyFrom(
this.b, boundAx - ax, boundAy - ay, boundBx - boundAx, boundBy - boundAy, (boundAx - ax) + Lx, (boundAy - ay) + Ly);
ax -= Lx; ay -= Ly; bx += Rx; by += Ry;
}
Bitfield2D bake() {
return new Bitfield2D(boundBx - boundAx, boundBy - boundAy).copyFrom(
this.b, boundAx - ax, boundAy - ay, boundBx - boundAx, boundBy - boundAy, 0, 0);
}
}
static Bitfield2D makeSpruce(int size) {
Util.
rangecheck(size,
1,
20,
"size"); var r = new ProcBitfield2D();
int nSegs = 3+size/4, trunkWidth = 1+size/3*2;
int y = 0;
for (int iSeg = 0; iSeg < nSegs; iSeg++) {
int maxSegWidth = trunkWidth + 2 * (size + iSeg * size / 2);
int segWidth = iSeg == 0 ? 1 : trunkWidth + (size + iSeg)/3*2;
for (; segWidth < maxSegWidth; segWidth += 2) {
for (int x = -segWidth/2; x < (segWidth+1)/2; x++)
r.set(x, y);
y += 1;
}
}
for (int yTrunk = 0; yTrunk < size; yTrunk++) {
for (int x = -trunkWidth/2; x < (trunkWidth + 1)/2; x++)
r.set(x, y);
y++;
}
return r.bake();
}
{
try {
var r = new Bitfield2D(50, 40);
var moon = Bitfield2D.parse(
"....######..........\n" +
"..####..............\n" +
"####................\n" +
"####................\n" +
"####................\n" +
"####..............##\n" +
"######..........####\n" +
"..################..\n" +
"....############", "##");
r.or(moon, 11, 4);
r.or(makeSpruce(4), -1, 15);
r.or(makeSpruce(3), 29, 17);
r.or(makeSpruce(2), 18, 18);
r.or(makeSpruce(5), 32, 16);
for (int iSnowflake = 0; iSnowflake < 25; iSnowflake++) {
int x = rand.nextInt(r.width()),
y = min(r.height() - 1, (int) (r.height() * pow(rand.nextFloat(), 2.0)));
r.set(x, y, !r.get(x, y));
}
System.
out.
printf("%s\n\n", r
); }
}
}
aW1wb3J0IGphdmEudXRpbC4qOwppbXBvcnQgamF2YS51dGlsLnN0cmVhbS4qOwppbXBvcnQgamF2YS5sYW5nLio7CmltcG9ydCBqYXZhLmlvLio7CmltcG9ydCBzdGF0aWMgamF2YS5sYW5nLk1hdGguKjsKCmNsYXNzIFV0aWwgewoJcHVibGljIHN0YXRpYyBJbGxlZ2FsQXJndW1lbnRFeGNlcHRpb24gQmFkQXJnZihTdHJpbmcgZm10LCBPYmplY3QuLi4gYXJncykgewoJCXJldHVybiBuZXcgSWxsZWdhbEFyZ3VtZW50RXhjZXB0aW9uKFN0cmluZy5mb3JtYXQoZm10LCBhcmdzKSk7Cgl9OwoKCXB1YmxpYyBzdGF0aWMgU3RyaW5nIHRyYWNlKEV4Y2VwdGlvbiBlKSB7CgkJU3RyaW5nV3JpdGVyIHN3ID0gbmV3IFN0cmluZ1dyaXRlcigpOwoJCWUucHJpbnRTdGFja1RyYWNlKG5ldyBQcmludFdyaXRlcihzdykpOwoJCXJldHVybiBzdy50b1N0cmluZygpOwoJfQoKCXB1YmxpYyBzdGF0aWMgaW50IHJhbmdlY2hlY2soaW50IHgsIGludCBtaW4sIGludCBtYXgsIFN0cmluZyB3aGF0KSB7CgkJaWYgKHggPCBtaW4gfHwgeCA+IG1heCkgdGhyb3cgQmFkQXJnZigiQmFkICVzOiAlZCwgc2hvdWxkIGJlIFslZDsgJWRdLiIsIHdoYXQsIHgsIG1pbiwgbWF4KTsKCQlyZXR1cm4geDsKCX0KfQoKY2xhc3MgQml0ZmllbGQyRCB7CglpbnRbXSBkYXRhOwoJaW50IHcsIGg7CglzdGF0aWMgZmluYWwgaW50IEJBU0UgPSBJbnRlZ2VyLlNJWkU7CglzdGF0aWMgZmluYWwgaW50IFNBTkVfQklUU19MSU1JVCA9IDFfMDAwXzAwMF8wMDA7CglzdGF0aWMgZmluYWwgaW50IFNBTkVfRElNRU5TSU9OX0xJTUlUID0gMTAwXzAwMF8wMDA7CgoJcHVibGljIEJpdGZpZWxkMkQoaW50IHcsIGludCBoKSB7IGluaXQobnVsbCwgdywgaCk7IH0KCUJpdGZpZWxkMkQoaW50W10gZGF0YSwgaW50IHcsIGludCBoKSB7IGluaXQoZGF0YSwgdywgaCk7IH0KCglwcml2YXRlIHZvaWQgaW5pdChpbnRbXSBkYXRhLCBpbnQgdywgaW50IGgpIHsKCQl2YWxpZGF0ZVNpemUodywgaCk7CgkJYXNzZXJ0IGRhdGEgPT0gbnVsbCB8fCBkYXRhLmxlbmd0aCA+PSAodypoICsgKEJBU0UgLSAxKSkgLyBCQVNFOwoJCXRoaXMuZGF0YSA9IGRhdGEgIT0gbnVsbCA/IGRhdGEgOiBuZXcgaW50Wyh3KmggKyAoQkFTRSAtIDEpKSAvIEJBU0VdOwoJCXRoaXMudyA9IHc7CgkJdGhpcy5oID0gaDsKCX0KCglzdGF0aWMgdm9pZCB2YWxpZGF0ZVNpemUoaW50IHcsIGludCBoKSB7CgkJaWYgKHcgPCAwIHx8IGggPCAwIHx8IHcgPiBTQU5FX0RJTUVOU0lPTl9MSU1JVCB8fCBoID4gU0FORV9ESU1FTlNJT05fTElNSVQKCQkJfHwgdyA+IDAgJiYgaCA+IFNBTkVfQklUU19MSU1JVCAvIHcpCgkJCXRocm93IFV0aWwuQmFkQXJnZigiQmFkIGJpdGZpZWxkIHNpemU6ICVkw5clZC4iLCB3LCBoKTsKCX0KCglwdWJsaWMgYm9vbGVhbiB2YWxpZENvb3JkKGludCB4LCBpbnQgeSkgewoJCXJldHVybiB4ID49IDAgJiYgeSA+PSAwICYmIHggPCB3ICYmIHkgPCBoOwoJfQoKCXB1YmxpYyB2b2lkIHZhbGlkYXRlQ29vcmQoaW50IHgsIGludCB5KSB7CgkJaWYgKCF2YWxpZENvb3JkKHgsIHkpKQoJCQl0aHJvdyBVdGlsLkJhZEFyZ2YoIkJhZCBjb29yZCBvZiBiaXRmaWVsZCAlZMOXJWQ6ICglZCwgJWQpLiIsIHRoaXMudywgdGhpcy5oLCB4LCB5KTsKCX0KCgl2b2lkIHZhbGlkYXRlUmVjdChpbnQgeCwgaW50IHksIGludCB3LCBpbnQgaCkgewoJCWlmICh4IDwgMCB8fCB5IDwgMCB8fCB3IDwgMCB8fCBoIDwgMCB8fCB4ICsgdyA+IHRoaXMudyB8fCB5ICsgaCA+IHRoaXMuaCkKCQkJdGhyb3cgVXRpbC5CYWRBcmdmKCJCYWQgcmVjdCBvZiBiaXRmaWVsZCAlZMOXJWQ6ICglZCwgJWQpIH4gKCVkLCAlZCkuIiwKCQkJCXRoaXMudywgdGhpcy5oLCB4LCB5LCB4K3csIHkraCk7Cgl9CgoJYm9vbGVhbiByYXdnZXQoaW50IGluZGV4KSB7IHJldHVybiAoZGF0YVtpbmRleCAvIEJBU0VdICYgKDEgPDwgKGluZGV4ICUgQkFTRSkpKSAhPSAwOyB9Cgl2b2lkIHJhd3NldChpbnQgaW5kZXgpIHsgZGF0YVtpbmRleCAvIEJBU0VdIHw9IDEgPDwgKGluZGV4ICUgQkFTRSk7IH0KCXZvaWQgcmF3dW5zZXQoaW50IGluZGV4KSB7IGRhdGFbaW5kZXggLyBCQVNFXSAmPSB+KDEgPDwgKGluZGV4ICUgQkFTRSkpOyB9Cgl2b2lkIHJhd3NldChpbnQgaW5kZXgsIGJvb2xlYW4gdmFsdWUpIHsgaWYgKHZhbHVlKSByYXdzZXQoaW5kZXgpOyBlbHNlIHJhd3Vuc2V0KGluZGV4KTsgfQoKCXB1YmxpYyBib29sZWFuIGdldChpbnQgeCwgaW50IHkpIHsgdmFsaWRhdGVDb29yZCh4LCB5KTsgcmV0dXJuIHJhd2dldCh5KncreCk7IH0KCXB1YmxpYyB2b2lkIHNldChpbnQgeCwgaW50IHkpIHsgdmFsaWRhdGVDb29yZCh4LCB5KTsgcmF3c2V0KHkqdyt4KTsgfQoJcHVibGljIHZvaWQgdW5zZXQoaW50IHgsIGludCB5KSB7IHZhbGlkYXRlQ29vcmQoeCwgeSk7IHJhd3Vuc2V0KHkqdyt4KTsgfQoJcHVibGljIHZvaWQgc2V0KGludCB4LCBpbnQgeSwgYm9vbGVhbiB2YWx1ZSkgeyB2YWxpZGF0ZUNvb3JkKHgsIHkpOyByYXdzZXQoeSp3K3gsIHZhbHVlKTsgfQoJcHVibGljIGludCB3aWR0aCgpIHsgcmV0dXJuIHc7IH0KCXB1YmxpYyBpbnQgaGVpZ2h0KCkgeyByZXR1cm4gaDsgfQoKCS8vIEZvciBmdW5jdGlvbnMgbGlrZSBvcigpIHRoYXQgYXBwbHkgb25lIGJpdGZpZWxkIHRvIGFub3RoZXIsCgkvLyByZWR1Y2VzIHBvdGVudGlhbGx5IG91dC1vZi1ib3JkZXJzIGlucHV0IHRvIGl0cyB2YWxpZCBwYXJ0LgoJc3RhdGljIGNsYXNzIENvb3JkV2FyZGVuIHsKCQlpbnQgc3JjWCwgc3JjWSwgdywgaCwgZGVzdFgsIGRlc3RZOwoJCUNvb3JkV2FyZGVuKEJpdGZpZWxkMkQgZGVzdCwgQml0ZmllbGQyRCBzcmMsIGludCBhU3JjWCwgaW50IGFTcmNZLCBpbnQgYVcsIGludCBhSCwgaW50IGFEZXN0WCwgaW50IGFEZXN0WSkgewoJCQlzcmMudmFsaWRhdGVSZWN0KGFTcmNYLCBhU3JjWSwgYVcsIGFIKTsKCQkJc3JjWCA9IGFTcmNYOyBzcmNZID0gYVNyY1k7IHcgPSBhVzsgaCA9IGFIOyBkZXN0WCA9IGFEZXN0WDsgZGVzdFkgPSBhRGVzdFk7CgkJCWlmIChkZXN0WCA8IDApIHsgc3JjWCAtPSBkZXN0WDsgdyArPSBkZXN0WDsgZGVzdFggPSAwOyB9CgkJCWlmIChkZXN0WCArIHcgPiBkZXN0LncpIHsgdyA9IGRlc3QudyAtIGRlc3RYOyB9CgkJCWlmIChkZXN0WSA8IDApIHsgc3JjWSAtPSBkZXN0WTsgaCArPSBkZXN0WTsgZGVzdFkgPSAwOyB9CgkJCWlmIChkZXN0WSArIGggPiBkZXN0LmgpIHsgaCA9IGRlc3QuaCAtIGRlc3RZOyB9CgkJfQoJfQoKCXB1YmxpYyB2b2lkIG9yKEJpdGZpZWxkMkQgYiwgaW50IGRlc3RYLCBpbnQgZGVzdFkpIHsKCQlvcihiLCAwLCAwLCBiLncsIGIuaCwgZGVzdFgsIGRlc3RZKTsKCX0KCglwdWJsaWMgdm9pZCBvcihCaXRmaWVsZDJEIGIsIGludCBieCwgaW50IGJ5LCBpbnQgdywgaW50IGgsIGludCBkZXN0WCwgaW50IGRlc3RZKSB7CgkJdmFyIHdhcmQgPSBuZXcgQ29vcmRXYXJkZW4odGhpcywgYiwgYngsIGJ5LCB3LCBoLCBkZXN0WCwgZGVzdFkpOwoJCWludCB0aGlzT2ZzID0gd2FyZC5kZXN0WSp0aGlzLncgKyB3YXJkLmRlc3RYLCBiT2ZzID0gd2FyZC5zcmNZKmIudyArIHdhcmQuc3JjWDsKCQlmb3IgKGJ5ID0gMDsgYnkgPCB3YXJkLmg7IGJ5KyssIHRoaXNPZnMgKz0gdGhpcy53IC0gd2FyZC53LCBiT2ZzICs9IGIudyAtIHdhcmQudykgewoJCQlmb3IgKGJ4ID0gMDsgYnggPCB3YXJkLnc7IGJ4KyssIHRoaXNPZnMrKywgYk9mcysrKQoJCQkJaWYgKGIucmF3Z2V0KGJPZnMpKSB0aGlzLnJhd3NldCh0aGlzT2ZzKTsKCQl9Cgl9CgoJcHVibGljIHZvaWQgYW5kTm90KEJpdGZpZWxkMkQgYiwgaW50IGRlc3RYLCBpbnQgZGVzdFkpIHsKCQlhbmROb3QoYiwgMCwgMCwgYi53LCBiLmgsIGRlc3RYLCBkZXN0WSk7Cgl9CgoJcHVibGljIHZvaWQgYW5kTm90KEJpdGZpZWxkMkQgYiwgaW50IGJ4LCBpbnQgYnksIGludCB3LCBpbnQgaCwgaW50IGRlc3RYLCBpbnQgZGVzdFkpIHsKCQl2YXIgd2FyZCA9IG5ldyBDb29yZFdhcmRlbih0aGlzLCBiLCBieCwgYnksIHcsIGgsIGRlc3RYLCBkZXN0WSk7CgkJaW50IHRoaXNPZnMgPSB3YXJkLmRlc3RZKnRoaXMudyArIHdhcmQuZGVzdFgsIGJPZnMgPSB3YXJkLnNyY1kqYi53ICsgd2FyZC5zcmNYOwoJCWZvciAoYnkgPSAwOyBieSA8IHdhcmQuaDsgYnkrKywgdGhpc09mcyArPSB0aGlzLncgLSB3YXJkLncsIGJPZnMgKz0gYi53IC0gd2FyZC53KSB7CgkJCWZvciAoYnggPSAwOyBieCA8IHdhcmQudzsgYngrKywgdGhpc09mcysrLCBiT2ZzKyspCgkJCQlpZiAoYi5yYXdnZXQoYk9mcykpIHRoaXMucmF3dW5zZXQodGhpc09mcyk7CgkJfQoJfQoKCXB1YmxpYyBCaXRmaWVsZDJEIGNvcHlGcm9tKEJpdGZpZWxkMkQgYiwgaW50IGRlc3RYLCBpbnQgZGVzdFkpIHsKCQlyZXR1cm4gY29weUZyb20oYiwgMCwgMCwgYi53LCBiLmgsIGRlc3RYLCBkZXN0WSk7Cgl9CgoJcHVibGljIEJpdGZpZWxkMkQgY29weUZyb20oQml0ZmllbGQyRCBiLCBpbnQgYngsIGludCBieSwgaW50IHcsIGludCBoLCBpbnQgZGVzdFgsIGludCBkZXN0WSkgewoJCXZhciB3YXJkID0gbmV3IENvb3JkV2FyZGVuKHRoaXMsIGIsIGJ4LCBieSwgdywgaCwgZGVzdFgsIGRlc3RZKTsKCQlpbnQgdGhpc09mcyA9IHdhcmQuZGVzdFkqdGhpcy53ICsgd2FyZC5kZXN0WCwgYk9mcyA9IHdhcmQuc3JjWSpiLncgKyB3YXJkLnNyY1g7CgkJZm9yIChieSA9IDA7IGJ5IDwgd2FyZC5oOyBieSsrLCB0aGlzT2ZzICs9IHRoaXMudywgYk9mcyArPSBiLncpIHsKCQkJY29weUJpdHMoYi5kYXRhLCBiT2ZzLCB0aGlzLmRhdGEsIHRoaXNPZnMsIHdhcmQudyk7CgkJfQoJCXJldHVybiB0aGlzOwoJfQoKCXN0YXRpYyBpbnQgcmVhZEJpdHNTbWFsbChpbnRbXSBzcmMsIGludCBzcmNQb3MsIGludCBjb3VudCkgewoJCWFzc2VydCBjb3VudCA+IDAgJiYgY291bnQgPCBCQVNFOwoJCS8vICAgICAgIDAgICAgICAgMSAgICAgICAyICAgICAgIDMgICAgICAgNCAgICAgICA1ICAgICAgIDYKCQkvLyBzcmMgPSBBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6CgkJLy8gICAgICAgICAgICBec3JjUG9zPTUKCQkvLyAgICAgICAgICAgICAgICAgIF5zcmNQb3MrY291bnQ9MTEKCQlpbnQgYml0cyA9IHNyY1tzcmNQb3MgLyBCQVNFXSA+Pj4gKHNyY1BvcyAlIEJBU0UpOyAvLyBGR0gKCQlpZiAoY291bnQgPiBCQVNFIC0gc3JjUG9zICUgQkFTRSkKCQkJYml0cyB8PSBzcmNbc3JjUG9zIC8gQkFTRSArIDFdIDw8IChCQVNFIC0gc3JjUG9zICUgQkFTRSk7IC8vIEZHSCB8IDAwMElKS0xNTk9QID0gRkdISUpLTE1OT1AKCQlyZXR1cm4gYml0cyAmICgoMSA8PCBjb3VudCkgLSAxKTsgLy8gRkdISUpLCgl9CgoJc3RhdGljIHZvaWQgd3JpdGVCaXRzMShpbnQgYml0cywgaW50W10gZHN0LCBpbnQgZHN0UG9zLCBpbnQgY291bnQpIHsKCQlhc3NlcnQgY291bnQgPiAwICYmIGNvdW50IDwgQkFTRSAtIGRzdFBvcyAlIEJBU0UgJiYgYml0cyA8IDEgPDwgY291bnQ7CgkJLy8gYml0cyA9IHF3ZXIKCQkvLyAgICAgICAwICAgICAgIDEgICAgICAgMiAgICAgICAzICAgICAgIDQgICAgICAgNSAgICAgICA2CgkJLy8gc3JjID0gQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5egoJCS8vICAgICAgICAgIF5kc3RQb3M9MwoJCS8vICAgICAgICAgICAgICBeZHN0UG9zK2NvdW50PTcKCQlkc3RbZHN0UG9zIC8gQkFTRV0gPSBkc3RbZHN0UG9zIC8gQkFTRV0gLy8gQUJDREVGR0gKCQkJJiB+KCgoMSA8PCBjb3VudCkgLSAxKSA8PCAoZHN0UG9zICUgQkFTRSkpIC8vIEFCQzAwMDBICgkJCXwgKGJpdHMgPDwgKGRzdFBvcyAlIEJBU0UpKTsgLy8gQUJDcXdlckgKCX0KCglzdGF0aWMgdm9pZCBjb3B5Qml0cyhpbnRbXSBzcmMsIGludCBzcmNQb3MsIGludFtdIGRzdCwgaW50IGRzdFBvcywgaW50IGNvdW50KSB7CgkJLy8gSW1hZ2luZSBCQVNFPTggKGFzIGlmIGJ5dGVbXSBpbnN0ZWFkIG9mIGludFtdKSwgc3JjUG9zID0gMywgZHN0UG9zID0gMiwgY291bnQ9MjUuCgkJLy8KCQkvLyAgICAgICAwICAgICAgIDEgICAgICAgMiAgICAgICAzICAgICAgIDQgICAgICAgNSAgICAgICA2CgkJLy8gc3JjID0gQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5egoJCS8vICAgICAgICAgIF5zcmNQb3M9MyAgICAgICAgICAgICAgICBec3JjUG9zK2NvdW50PTI4CgkJLy8gZHN0ID0gLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4KCQkvLyAgICAgICAwIF5kc3RQb3M9MiAgICAgMiAgICAgICAzICAgICAgIDQgICAgICAgNQoJCS8vCgkJLy8gRmlyc3Qgd2UgYWxpZ24gZHN0UG9zIHRvIHRoZSBtdWx0aXBsZSBvZiBCQVNFIGJ5IHJlYWRpbmcKCQkvLyBmaXJzdCBCQVNFIC0gZHN0UG9zJUJBU0UgYml0cyB3aXRoIHJlYWRCaXRzU21hbGwoKSBhbmQgd3JpdGluZyB0aGVtCgkJLy8gaW50byB0aGUgZmlyc3QgY2VsbCBvZiBkc3RbXSB3aXRoIHdyaXRlQml0czEuCgkJLy8KCQkvLyBXZSdsbCBnZXQ6CgkJLy8gICAgICAgMCAgICAgICAxICAgICAgIDIgICAgICAgMyAgICAgICA0ICAgICAgIDUgICAgICAgNgoJCS8vIHNyYyA9IEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoKCQkvLyAgICAgICAgICAgICAgICBec3JjUG9zPTkgICAgICAgICAgXnNyY1Bvcytjb3VudD0yOAoJCS8vIGRzdCA9IC4uREVGR0hJLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uCgkJLy8gICAgICAgMCAgICAgICAxICAgICAgIDIgICAgICAgMyAgICAgICA0ICAgICAgIDUKCQkvLyAgICAgICAgICAgICAgIF5kc3RQb3M9OAoJCWlmIChkc3RQb3MgJSBCQVNFICE9IDApIHsKCQkJaW50IG4gPSBtaW4oY291bnQsIEJBU0UgLSBkc3RQb3MgJSBCQVNFKTsKCQkJaWYgKG4gPiAwKSB3cml0ZUJpdHMxKHJlYWRCaXRzU21hbGwoc3JjLCBzcmNQb3MsIG4pLCBkc3QsIGRzdFBvcywgbik7CgkJCXNyY1BvcyArPSBuOwoJCQlkc3RQb3MgKz0gbjsKCQkJY291bnQgLT0gbjsKCQl9CgoJCS8vIE5vdyB3ZSBmaWxsIHdob2xlIGNlbGxzIHdoaWxlIHBvc3NpYmxlLgoJCS8vIFdlJ2xsIGdldDoKCQkvLyBzcmMgPSBBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6CgkJLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIF5zcmNQb3M9MjUKCQkvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXnNyY1Bvcytjb3VudD0yOAoJCS8vIGRzdCA9IC4uREVGR0hJSktMTU5PUFFSU1RVVldYWS4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uCgkJLy8gICAgICAgMCAgICAgICAxICAgICAgIDIgICAgICAgMyAgICAgICA0ICAgICAgIDUKCQkvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBeZHN0UG9zPTI0CgkJaWYgKHNyY1BvcyAlIEJBU0UgPT0gMCkgewoJCQkvLyBBbGlnbmVkIGNhc2UuIFRoaXMgaXMgbm90IGV2ZW4gYW4gb3B0aW1pemF0aW9uLCBiZWNhdXNlICdpbnQnIHNoaWZ0cyBhcmUgcmVzdHJpY3RlZCB0byAwLi4zMS4KCQkJU3lzdGVtLmFycmF5Y29weShzcmMsIHNyY1BvcyAvIEJBU0UsIGRzdCwgZHN0UG9zIC8gQkFTRSwgY291bnQgLyBCQVNFKTsKCQl9IGVsc2UgewoJCQkvLyBVbmFsaWduZWQgY2FzZS4KCQkJLy8gc3JjOiAuLi5BQkNERSBGR0guLi4uLgoJCQkvLyAgICAgICAgIF5zcmNQb3MKCQkJLy8gZHN0OiAuLi4uLi4uLgoJCQlmb3IgKGludCBpU3JjID0gc3JjUG9zIC8gQkFTRSwgaURzdCA9IGRzdFBvcyAvIEJBU0UsIGlEc3RFZCA9IGlEc3QgKyBjb3VudCAvIEJBU0U7IGlEc3QgPCBpRHN0RWQ7IGlEc3QrKywgaVNyYysrKQoJCQkJZHN0W2lEc3RdID0KCQkJCQkoc3JjW2lTcmNdID4+PiAoc3JjUG9zICUgQkFTRSkpIC8vIEFCQ0RFCgkJCQkJfCAoc3JjW2lTcmMgKyAxXSA8PCAoQkFTRSAtIHNyY1BvcyAlIEJBU0UpKTsgLy8gQUJDREUgfCAwMDAwMEZHSCA9IEFCQ0RFRkdICgkJfQoJCXNyY1BvcyArPSBjb3VudCAtIGNvdW50ICUgQkFTRTsKCQlkc3RQb3MgKz0gY291bnQgLSBjb3VudCAlIEJBU0U7CgkJY291bnQgJT0gQkFTRTsKCgkJLy8gQXBwZW5kIHRoZSB0YWlsLgoJCWlmIChjb3VudCA+IDApCgkJCXdyaXRlQml0czEocmVhZEJpdHNTbWFsbChzcmMsIHNyY1BvcywgY291bnQpLCBkc3QsIGRzdFBvcywgY291bnQpOwoJfQoKCUBPdmVycmlkZQoJcHVibGljIFN0cmluZyB0b1N0cmluZygpIHsKCQlyZXR1cm4gdG9TdHJpbmcoIiMjIiwgIi4uIik7Cgl9CgoJcHVibGljIFN0cmluZyB0b1N0cmluZyhTdHJpbmcgb25lLCBTdHJpbmcgemVybykgewoJCXZhciBzYiA9IG5ldyBTdHJpbmdCdWlsZGVyKCk7CgkJZm9yIChpbnQgb2ZzID0gMCwgeSA9IDA7IHkgPCBoOyB5KyspIHsKCQkJaWYgKHkgPiAwKSBzYi5hcHBlbmQoIlxuIik7CgkJCWZvciAoaW50IHggPSAwOyB4IDwgdzsgeCsrLCBvZnMrKykKCQkJCXNiLmFwcGVuZChyYXdnZXQob2ZzKSA/IG9uZSA6IHplcm8pOwoJCX0KCQlyZXR1cm4gc2IudG9TdHJpbmcoKTsKCX0KCglzdGF0aWMgQml0ZmllbGQyRCBwYXJzZShTdHJpbmcgc3JjKSB7IHJldHVybiBwYXJzZShzcmMsICIjIyIpOyB9CgoJc3RhdGljIEJpdGZpZWxkMkQgcGFyc2UoU3RyaW5nIHNyYywgU3RyaW5nIG9uZSkgewoJCWlmIChvbmUuaXNFbXB0eSgpKSB0aHJvdyBVdGlsLkJhZEFyZ2YoIidvbmUnIGNhbid0IGJlIGVtcHR5LiIpOwoJCWlmIChvbmUuaW5kZXhPZignXG4nKSA+PSAwKSB0aHJvdyBVdGlsLkJhZEFyZ2YoIkJhZCAnb25lJzogXCIlc1wiLiBTaG91bGRuJ3QgY29udGFpbiBFT0wuIiwgb25lKTsKCQkvLyBQcmVwYXNzIGZvciBzaXplLgoJCWludCB3ID0gMCwgaCA9IDA7CgkJZm9yIChpbnQgcG9zID0gMDsgcG9zIDwgc3JjLmxlbmd0aCgpOyApIHsKCQkJaW50IGVvbHAgPSBzcmMuaW5kZXhPZigiXG4iLCBwb3MpOwoJCQlpZiAoZW9scCA8IDApIGVvbHAgPSBzcmMubGVuZ3RoKCk7CgkJCWlmICgoZW9scCAtIHBvcykgJSBvbmUubGVuZ3RoKCkgIT0gMCkKCQkJCXRocm93IFV0aWwuQmFkQXJnZigiTGluZSAlZDpcbiVzXG5jb250YWlucyAlZCBjaGFyYWN0ZXIlcywgd2hpY2ggaXMgbm90IG11bHRpcGxlIG9mIGxlbiglcykgPSAlZC4iLAoJCQkJCWgsIHNyYy5zdWJzdHJpbmcocG9zLCBlb2xwKSwgZW9scCAtIHBvcywgZW9scCAtIHBvcyAhPSAxID8gInMiIDogIiIsIG9uZSwgb25lLmxlbmd0aCgpKTsKCQkJdyA9IG1heCh3LCAoZW9scCAtIHBvcykgLyBvbmUubGVuZ3RoKCkpOwoJCQloKys7CgkJCXBvcyA9IGVvbHAgKyAiXG4iLmxlbmd0aCgpOwoJCX0KCQl2YXIgciA9IG5ldyBCaXRmaWVsZDJEKHcsIGgpOwoKCQlmb3IgKGludCB5ID0gMCwgeCA9IDAsIG9mcyA9IDAsIHBvcyA9IDA7IHBvcyA8IHNyYy5sZW5ndGgoKTsgKQoJCQlpZiAoc3JjLmNoYXJBdChwb3MpID09ICdcbicpIHsKCQkJCW9mcyArPSByLncgLSB4OwoJCQkJeCA9IDA7IHkrKzsKCQkJCXBvcyArPSAiXG4iLmxlbmd0aCgpOwoJCQl9IGVsc2UgewoJCQkJaWYgKHNyYy5zdGFydHNXaXRoKG9uZSwgcG9zKSkgci5yYXdzZXQob2ZzKTsKCQkJCXBvcyArPSBvbmUubGVuZ3RoKCk7CgkJCQl4Kys7IG9mcysrOwoJCQl9CgkJcmV0dXJuIHI7Cgl9Cn0KCmNsYXNzIElkZW9uZQp7CgkvLyBBdXRvLWdyb3dpbmcgYml0ZmllbGQgZm9yIHByb2NlZHVyYWwgZ2VuZXJhdGlvbiB3aGVuIHJlc3VsdGluZyBzaXplIGlzIGltcHJhY3RpY2FsIHRvIHByZWRpY3QuCglzdGF0aWMgY2xhc3MgUHJvY0JpdGZpZWxkMkQgewoJCUJpdGZpZWxkMkQgYiA9IG5ldyBCaXRmaWVsZDJEKDAsIDApOwoJCWludCBheCwgYXksIGJ4LCBieSwgYm91bmRBeCwgYm91bmRBeSwgYm91bmRCeCwgYm91bmRCeTsKCgkJdm9pZCBzZXQoaW50IHgsIGludCB5KSB7CgkJCWlmIChib3VuZEF4ID09IGJvdW5kQngpIHsKCQkJCWF4ID0geDsgYXkgPSB5OyBieCA9IHg7IGJ5ID0geTsKCQkJCWJvdW5kQXggPSB4OyBib3VuZEF5ID0geTsgYm91bmRCeCA9IHg7IGJvdW5kQnkgPSB5OwoJCQl9CgkJCWlmICh4IDwgYXggfHwgeSA8IGF5IHx8IHggPj0gYnggfHwgeSA+PSBieSkKCQkJCWdyb3coCgkJCQkJeCA8IGF4ID8gZ3Jvd1N0Z3koYXggLSB4LCBieCAtIGF4KSA6IDAsCgkJCQkJeSA8IGF5ID8gZ3Jvd1N0Z3koYXkgLSB5LCBieSAtIGF5KSA6IDAsCgkJCQkJeCA+PSBieCA/IGdyb3dTdGd5KHggLSBieCArIDEsIGJ4IC0gYXgpIDogMCwKCQkJCQl5ID49IGJ5ID8gZ3Jvd1N0Z3koeSAtIGJ5ICsgMSwgYnkgLSBheSkgOiAwKTsKCQkJaWYgKHggPCBib3VuZEF4KSBib3VuZEF4ID0geDsKCQkJaWYgKHggPj0gYm91bmRCeCkgYm91bmRCeCA9IHggKyAxOwoJCQlpZiAoeSA8IGJvdW5kQXkpIGJvdW5kQXkgPSB5OwoJCQlpZiAoeSA+PSBib3VuZEJ5KSBib3VuZEJ5ID0geSArIDE7CgkJCWIuc2V0KHgtYXgsIHktYXkpOwoJCX0KCgkJdm9pZCB1bnNldChpbnQgeCwgaW50IHkpIHsKCQkJaWYgKHggPj0gYm91bmRBeCAmJiB4IDwgYm91bmRCeCAmJiB4ID49IGJvdW5kQXkgJiYgeCA8IGJvdW5kQnkpCgkJCQliLnVuc2V0KHgtYXgsIHktYXkpOwoJCX0KCgkJdm9pZCBzZXQoaW50IHgsIGludCB5LCBib29sZWFuIHZhbHVlKSB7IGlmICh2YWx1ZSkgc2V0KHgsIHkpOyBlbHNlIHVuc2V0KHgsIHkpOyB9CgoJCXN0YXRpYyBpbnQgZ3Jvd1N0Z3koaW50IGF0TGVhc3QsIGludCBwcmVzZW50KSB7CgkJCXJldHVybiBtYXgobWF4KDgsIHByZXNlbnQgLyAyKSwgYXRMZWFzdCk7CgkJfQoKCQl2b2lkIGdyb3coaW50IEx4LCBpbnQgTHksIGludCBSeCwgaW50IFJ5KSB7CgkJCXRoaXMuYiA9IG5ldyBCaXRmaWVsZDJEKChieCAtIGF4KSArIEx4ICsgUngsIChieSAtIGF5KSArIEx5ICsgUnkpLmNvcHlGcm9tKAoJCQkJdGhpcy5iLCBib3VuZEF4IC0gYXgsIGJvdW5kQXkgLSBheSwgYm91bmRCeCAtIGJvdW5kQXgsIGJvdW5kQnkgLSBib3VuZEF5LCAoYm91bmRBeCAtIGF4KSArIEx4LCAoYm91bmRBeSAtIGF5KSArIEx5KTsKCQkJYXggLT0gTHg7IGF5IC09IEx5OyBieCArPSBSeDsgYnkgKz0gUnk7CgkJfQoKCQlCaXRmaWVsZDJEIGJha2UoKSB7CgkJCXJldHVybiBuZXcgQml0ZmllbGQyRChib3VuZEJ4IC0gYm91bmRBeCwgYm91bmRCeSAtIGJvdW5kQXkpLmNvcHlGcm9tKAoJCQkJdGhpcy5iLCBib3VuZEF4IC0gYXgsIGJvdW5kQXkgLSBheSwgYm91bmRCeCAtIGJvdW5kQXgsIGJvdW5kQnkgLSBib3VuZEF5LCAwLCAwKTsKCQl9Cgl9CgoJc3RhdGljIEJpdGZpZWxkMkQgbWFrZVNwcnVjZShpbnQgc2l6ZSkgewoJCVV0aWwucmFuZ2VjaGVjayhzaXplLCAxLCAyMCwgInNpemUiKTsKCQl2YXIgciA9IG5ldyBQcm9jQml0ZmllbGQyRCgpOwoJCWludCBuU2VncyA9IDMrc2l6ZS80LCB0cnVua1dpZHRoID0gMStzaXplLzMqMjsKCQlpbnQgeSA9IDA7CgkJZm9yIChpbnQgaVNlZyA9IDA7IGlTZWcgPCBuU2VnczsgaVNlZysrKSB7CgkJCWludCBtYXhTZWdXaWR0aCA9IHRydW5rV2lkdGggKyAyICogKHNpemUgKyBpU2VnICogc2l6ZSAvIDIpOwoJCQlpbnQgc2VnV2lkdGggPSBpU2VnID09IDAgPyAxIDogdHJ1bmtXaWR0aCArIChzaXplICsgaVNlZykvMyoyOwoJCQlmb3IgKDsgc2VnV2lkdGggPCBtYXhTZWdXaWR0aDsgc2VnV2lkdGggKz0gMikgewoJCQkJZm9yIChpbnQgeCA9IC1zZWdXaWR0aC8yOyB4IDwgKHNlZ1dpZHRoKzEpLzI7IHgrKykKCQkJCQlyLnNldCh4LCB5KTsKCQkJCXkgKz0gMTsKCQkJfQoJCX0KCQlmb3IgKGludCB5VHJ1bmsgPSAwOyB5VHJ1bmsgPCBzaXplOyB5VHJ1bmsrKykgewoJCQlmb3IgKGludCB4ID0gLXRydW5rV2lkdGgvMjsgeCA8ICh0cnVua1dpZHRoICsgMSkvMjsgeCsrKQoJCQkJci5zZXQoeCwgeSk7CgkJCXkrKzsKCQl9CgkJcmV0dXJuIHIuYmFrZSgpOwoJfQoKCXB1YmxpYyBzdGF0aWMgdm9pZCBtYWluIChTdHJpbmdbXSBhcmdzKSB0aHJvd3MgamF2YS5sYW5nLkV4Y2VwdGlvbgoJewoJCXRyeSB7CgkJCXZhciByID0gbmV3IEJpdGZpZWxkMkQoNTAsIDQwKTsKCQkJdmFyIG1vb24gPSBCaXRmaWVsZDJELnBhcnNlKAoJCQkJIi4uLi4jIyMjIyMuLi4uLi4uLi4uXG4iICsKCQkJCSIuLiMjIyMuLi4uLi4uLi4uLi4uLlxuIiArCgkJCQkiIyMjIy4uLi4uLi4uLi4uLi4uLi5cbiIgKwoJCQkJIiMjIyMuLi4uLi4uLi4uLi4uLi4uXG4iICsKCQkJCSIjIyMjLi4uLi4uLi4uLi4uLi4uLlxuIiArCgkJCQkiIyMjIy4uLi4uLi4uLi4uLi4uIyNcbiIgKwoJCQkJIiMjIyMjIy4uLi4uLi4uLi4jIyMjXG4iICsKCQkJCSIuLiMjIyMjIyMjIyMjIyMjIyMuLlxuIiArCgkJCQkiLi4uLiMjIyMjIyMjIyMjIyIsICIjIyIpOwoJCQlyLm9yKG1vb24sIDExLCA0KTsKCQkJci5vcihtYWtlU3BydWNlKDQpLCAtMSwgMTUpOwoJCQlyLm9yKG1ha2VTcHJ1Y2UoMyksIDI5LCAxNyk7CgkJCXIub3IobWFrZVNwcnVjZSgyKSwgMTgsIDE4KTsKCQkJci5vcihtYWtlU3BydWNlKDUpLCAzMiwgMTYpOwoJCQl2YXIgcmFuZCA9IG5ldyBSYW5kb20oNyk7CgkJCWZvciAoaW50IGlTbm93Zmxha2UgPSAwOyBpU25vd2ZsYWtlIDwgMjU7IGlTbm93Zmxha2UrKykgewoJCQkJaW50IHggPSByYW5kLm5leHRJbnQoci53aWR0aCgpKSwKCQkJCQl5ID0gbWluKHIuaGVpZ2h0KCkgLSAxLCAoaW50KSAoci5oZWlnaHQoKSAqIHBvdyhyYW5kLm5leHRGbG9hdCgpLCAyLjApKSk7CgkJCQlyLnNldCh4LCB5LCAhci5nZXQoeCwgeSkpOwoJCQl9CgkJCVN5c3RlbS5vdXQucHJpbnRmKCIlc1xuXG4iLCByKTsKCQl9IGNhdGNoIChFeGNlcHRpb24gZSkgewoJCQlTeXN0ZW0ub3V0LnByaW50bG4oVXRpbC50cmFjZShlKSk7CgkJfQoJfQp9