import java.awt.geom.Line2D ;
import java.io.BufferedReader ;
import java.io.IOException ;
import java.io.InputStreamReader ;
import java.util.ArrayList ;
import java.util.LinkedList ;
import java.util.List ;
import static java.
lang .
Double .
max ; import static java.
lang .
Double .
min ;
public class Main {
private static final double G = 9.80665 ;
static class Building {
int x, y, z;
boolean visited;
int steps = 0 ;
int i, j;
Building( int x, int y, int z, int i, int j) {
this .x = x;
this .y = y;
this .z = z;
this .i = i;
this .j = j;
}
@Override
return "Building{" +
"x=" + x +
", y=" + y +
", z=" + z +
'}' ;
}
}
double x1, y1, x2, y2;
public Segment ( double x1,
double y1,
double x2,
double y2
) { this .x1 = x1;
this .y1 = y1;
this .x2 = x2;
this .y2 = y2;
}
@Override
return "(" + x1 + ", " + y1 + ") -> (" + x2 + ", " + y2 + ")" ;
}
// https://g...content-available-to-author-only...b.com/baobabKoodaa/CodeForcesLibrary/blob/ad6972b1ccd87c9100171122692562704c695703/src/baobab/A.java#L767
// Returns true if segment 1-2 intersects segment 3-4
double x3 = s.x1 , x4 = s.x2 , y3 = s.y1 , y4 = s.y2 ;
if ( x1 == x2 && x3 == x4) {
// Both segments are vertical
if ( x1 != x3) {
return null ;
}
if ( min( y1, y2) < min( y3, y4) ) {
if ( max( y1, y2) >= min( y3, y4) ) {
return OVERLAP;
} else {
return null ;
}
} else {
if ( max( y3, y4) >= min( y1, y2) ) {
return OVERLAP;
} else {
return null ;
}
}
}
if ( x1 == x2) {
// Only segment 1-2 is vertical. Does segment 3-4 cross it? y = a*x + b
double a34 = ( y4 - y3) / ( x4 - x3) ;
double b34 = y3 - a34 * x3;
double y = a34 * x1 + b34;
if ( y >= min( y1, y2) - 1e- 6 && y <= max( y1, y2) + 1e- 6 && x1 >= min( x3, x4) - 1e- 6 && x1 <= max( x3, x4) + 1e- 6) {
} else {
return null ;
}
}
if ( x3 == x4) {
// Only segment 3-4 is vertical. Does segment 1-2 cross it? y = a*x + b
double a12 = ( y2 - y1) / ( x2 - x1) ;
double b12 = y1 - a12 * x1;
double y = a12 * x3 + b12;
if ( y >= min( y3, y4) - 1e- 6 && y <= max( y3, y4) + 1e- 6 && x3 >= min( x1, x2) - 1e- 6 && x3 <= max( x1, x2) + 1e- 6) {
} else {
return null ;
}
}
double a12 = ( y2 - y1) / ( x2 - x1) ;
double b12 = y1 - a12 * x1;
double a34 = ( y4 - y3) / ( x4 - x3) ;
double b34 = y3 - a34 * x3;
if ( closeToZero( a12 - a34) ) {
// Parallel lines
if ( closeToZero( b12 - b34) ) {
return OVERLAP;
} else {
return null ;
}
}
// Non parallel non vertical lines intersect at x. Is x part of both segments?
double x = - ( b12 - b34) / ( a12 - a34) ;
if ( x >= min( x1, x2) - 1e- 6 && x <= max( x1, x2) + 1e- 6 && x >= min( x3, x4) - 1e- 6 && x <= max( x3, x4) + 1e- 6) {
return new Point ( x, a12
* x
+ b12
) ; } else {
return null ;
}
}
boolean closeToZero( double v) {
// Check if double is close to zero, considering precision issues.
return Math .
abs ( v
) <= 0.0000000000001 ; }
}
double x, y;
public Point ( double x,
double y
) { this .x = x;
this .y = y;
}
@Override
return "(" + x + ", " + y + ")" ;
}
}
int [ ] v = readArrayLine( br.readLine ( ) , 6 ) ;
int m = v[ 0 ] , n = v[ 1 ] ;
double w = v[ 2 ] , speed = v[ 3 ] ;
int lx = v[ 4 ] - 1 , ly = v[ 5 ] - 1 ;
Building[ ] [ ] b = new Building[ n] [ m] ;
int currentX;
int currentY = 0 ;
for ( int i = 0 ; i < n; i++ ) {
v = readArrayLine( br.readLine ( ) , m) ;
currentX = 0 ;
for ( int j = 0 ; j < m; j++ ) {
b[ i] [ j] = new Building( currentX, currentY, v[ j] , i, j) ;
currentX += w;
}
currentY += w;
}
// Segment[] horizontal = new Segment[n - 1];
// Segment[] vertical = new Segment[m - 1];
// for (int i = 0; i < n - 1; i++) {
// double hy = w / 2 + w * i;
// horizontal[i] = new Segment(0, hy, w * (n - 1), hy);
// }
//
// for (int i = 0; i < m - 1; i++) {
// double vx = w / 2 + w * i;
// vertical[i] = new Segment(vx, 0, vx, w * (m - 1));
// }
Building root = b[ ly] [ lx] ;
LinkedList< Building> queue = new LinkedList<> ( ) ;
queue.add ( root) ;
root.visited = true ;
while ( ! queue.isEmpty ( ) ) {
root = queue.poll ( ) ;
if ( root == null ) {
break ;
}
for ( int i = 0 ; i < n; i++ ) {
for ( int j = 0 ; j < m; j++ ) {
Building dest = b[ i] [ j] ;
if ( dest.visited ) {
continue ;
}
// if (canJump(root, dest, speed, vertical, horizontal, w, b)) {
if ( canJumpSmart( root, dest, speed, w, b) ) {
dest.steps = root.steps + 1 ;
dest.visited = true ;
queue.add ( dest) ;
}
}
}
}
for ( int i = 0 ; i < n; i++ ) {
for ( int j = 0 ; j < m; j++ ) {
if ( b[ i] [ j] .steps == 0 && ( i != ly || j != lx) ) {
} else {
System .
out .
print ( b
[ i
] [ j
] .
steps + " " ) ; }
}
}
}
// private static boolean canJump(Building root, Building dest, double speed, Segment[] vertical, Segment[] horizontal, double w, Building b[][]) {
// double dist = getHorizontalDistBetweenSquared(root, dest);
// int heightDiff = dest.z - root.z;
//
// double launchAngle = getAngle(speed, Math.sqrt(dist), heightDiff);
// if (launchAngle > 0) {
// return checkTrajectory(b, speed, root, dest, Math.tan(launchAngle), vertical, horizontal, w);
// }
// return false;
// }
private static boolean canJumpSmart( Building root, Building dest, double speed, double w, Building b[ ] [ ] ) {
double dist = getHorizontalDistBetweenSquared( root, dest) ;
int heightDiff = dest.z - root.z ;
double tangentOfLaunchAngle
= getTangentOfLaunchAngle
( speed,
Math .
sqrt ( dist
) , heightDiff,
1 ) ; double tangentOfLaunchAngle1
= getTangentOfLaunchAngle
( speed,
Math .
sqrt ( dist
) , heightDiff,
- 1 ) ;
boolean check1 = false ;
if ( tangentOfLaunchAngle > 0 ) {
check1 = checkTrajectorySimple( b, speed, root, dest,tangentOfLaunchAngle, w) ;
}
boolean check2 = false ;
if ( tangentOfLaunchAngle1 > 0 ) {
check2 = checkTrajectorySimple( b, speed, root, dest, tangentOfLaunchAngle1, w) ;
}
return check1 || check2;
}
private static boolean isAboveBuilding
( Building b,
double speed,
double tangentOfLaunchAngle,
Point intersection,
int h0
) { double xDist = b.x - intersection.x ;
double yDist = b.y - intersection.y ;
double dist
= Math .
sqrt ( xDist
* xDist
+ yDist
* yDist
) ; double computedHeight = computeHeightForDistAndTan( h0, speed, tangentOfLaunchAngle, dist) ;
return computedHeight >= b.z - 1e- 9;
}
private static boolean checkTrajectorySimple( Building[ ] [ ] b, double speed, Building root, Building dest, double tan, double w) {
int h0 = root.z ;
for ( int i = 0 ; i < b.length ; i ++ ) {
for ( int j = 0 ; j < b[ i] .length ; j++ ) {
double x = b[ i] [ j] .x ;
double y = b[ i] [ j] .y ;
List< Point> polygon = new ArrayList<> ( ) ;
polygon.
add ( new Point ( x
- w
/ 2 , y
- w
/ 2 ) ) ; polygon.
add ( new Point ( x
+ w
/ 2 , y
- w
/ 2 ) ) ; polygon.
add ( new Point ( x
+ w
/ 2 , y
+ w
/ 2 ) ) ; polygon.
add ( new Point ( x
- w
/ 2 , y
+ w
/ 2 ) ) ;
for ( int k = 0 ; k < 4 ; k ++ ) {
Point p1
= polygon.
get ( k
) ; Point p2
= polygon.
get ( ( k
+ 1 ) % polygon.
size ( ) ) ; intersect = s.intersect ( polySeg) ;
boolean inter
= Line2D .
linesIntersect ( p1.
x , p1.
y , p2.
x , p2.
y , s.
x1 , s.
y1 , s.
x2 , s.
y2 ) ; if ( intersect
!= null && intersect
!= Segment .
OVERLAP ) { if ( ! inter) {
throw null ;
}
if ( ! isAboveBuilding( b[ i] [ j] , speed, tan, intersect, h0) ) {
return false ;
}
} else {
if ( inter) {
// System.out.println(s + " " + polySeg + " " + intersect);
throw null ;
}
}
}
}
}
return true ;
}
// private static boolean checkTrajectory(Building[][] b, double speed, Building root, Building dest, double tan, Segment[] verticals, Segment[] horizontals, double w) {
//
// Segment s = new Segment(root.x, root.y, dest.x, dest.y);
// Map<Segment, Point> segmentPointMap = new HashMap<>();
// int h0 = root.z;
// for (int i = 0; i < horizontals.length; i++) {
// Segment segment = horizontals[i];
// Point intersect = s.intersect(segment);
// if (intersect != null && intersect != Segment.OVERLAP) {
//// System.out.println(intersect + " = " + ("[" + root.i + ", " + root.j + "]") + " " + ("[" + dest.i + ", " + dest.j + "]") + " ----> " + segment);
// segmentPointMap.put(segment, intersect);
// if (verticals.length > 0) {
// if (intersect.x >= verticals[0].x1 - w && intersect.x <= verticals[0].x1) {
//// System.out.println(("-> [" + i + ", " + 0 + "]") + " " + ("[" + (i + 1) + ", " + 0 + "]"));
// if (!isAboveBuilding(b[i][0], speed, tan, intersect, h0)
// || !isAboveBuilding(b[i + 1][0], speed, tan, intersect, h0)) {
// return false;
// }
// }
// for (int j = 0; j < verticals.length; j++) {
// if (intersect.x >= verticals[j].x1 && intersect.x <= verticals[j].x1 + w) {
//// System.out.println(("-> [" + i + ", " + (j + 1) + "]") + " " + ("[" + (i + 1) + ", " + (j + 1) + "]"));
// if (!isAboveBuilding(b[i][j + 1], speed, tan, intersect, h0)
// || !isAboveBuilding(b[i + 1][j + 1], speed, tan, intersect, h0)) {
// return false;
// }
// }
// }
// } else {
//// System.out.println(("-> [" + i + ", " + 0 + "]") + " " + ("[" + (i + 1) + ", " + 0 + "]"));
// if (!isAboveBuilding(b[i][0], speed, tan, intersect, h0)
// || !isAboveBuilding(b[i + 1][0], speed, tan, intersect, h0)) {
// return false;
// }
// }
// }
// }
//
// for (int i = 0; i < verticals.length; i++) {
// Segment segment = verticals[i];
// Point intersect = s.intersect(segment);
// if (intersect != null && intersect != Segment.OVERLAP) {
//// System.out.println(intersect + " = " + ("[" + root.i + ", " + root.j + "]") + " " + ("[" + dest.i + ", " + dest.j + "]") + " ----> " + segment);
// segmentPointMap.put(segment, intersect);
// if (horizontals.length > 0) {
// if (intersect.y >= horizontals[0].y1 - w && intersect.y <= horizontals[0].y1) {
//// System.out.println(("-< [" + 0 + ", " + i + "]") + " " + ("[" + 0 + ", " + (i + 1) + "]"));
// if (!isAboveBuilding(b[0][i], speed, tan, intersect, h0)
// || !isAboveBuilding(b[0][i + 1], speed, tan, intersect, h0)) {
// return false;
// }
// }
// for (int j = 0; j < horizontals.length; j++) {
// if (intersect.y >= horizontals[j].y1 && intersect.y <= horizontals[j].y1 + w) {
//// System.out.println(("-< [" + (j + 1) + ", " + i + "]") + " " + ("[" + (j + 1) + ", " + (i + 1) + "]"));
// if (!isAboveBuilding(b[j + 1][i], speed, tan, intersect, h0)
// || !isAboveBuilding(b[j + 1][i + 1], speed, tan, intersect, h0)) {
// return false;
// }
// }
// }
// } else {
//// System.out.println(("-< [" + 0 + ", " + i + "]") + " " + ("[" + 0 + ", " + (i + 1) + "]"));
// if (!isAboveBuilding(b[0][i], speed, tan, intersect, h0)
// || !isAboveBuilding(b[0][i + 1], speed, tan, intersect, h0)) {
// return false;
// }
// }
// }
// }
//
//// System.out.println("end for " + ("[" + root.i + ", " + root.j + "]") + " " + ("[" + dest.i + ", " + dest.j + "]"));
//// System.out.println();
// return true;
// }
private static double getHorizontalDistBetweenSquared( Building b1, Building b2) {
return ( b1.x - b2.x ) * ( b1.x - b2.x ) + ( b1.y - b2.y ) * ( b1.y - b2.y ) ;
}
private static double getTangentOfLaunchAngle( double speed, double dist, double h, int coef) {
double a = G * dist * dist / ( 2 * speed * speed) ;
double b = - dist;
double c = a + h;
double delta = b * b - 4 * a * c;
if ( delta < 0 ) {
return - 1 ;
}
return ( - b
+ coef
* Math .
sqrt ( delta
) ) / ( 2 * a
) ; }
private static double getAngle( double v, double dist, double h) {
double start
= Math .
PI / 2 ; double end
= Math .
PI / 4 ; double computedY
= Double .
MAX_VALUE ; double x = 0 ;
while ( Math .
abs ( computedY
- h
) > 0.000005 ) { x = ( start + end) / 2 ;
if ( start == x || end == x) {
return - 1 ;
}
double vy
= v
* Math .
sin ( x
) ; double timeToHighest = vy / G;
double vx
= v
* Math .
cos ( x
) ; double timeToDist = dist / vx;
if ( timeToDist < timeToHighest - 1e- 9) {
end = x;
continue ;
}
computedY
= computeHeightForDistAndTan
( 0 , v,
Math .
tan ( x
) , dist
) ; if ( start - end < 0.00000000000000000000001 ) {
return - 1 ;
}
if ( computedY < h) {
start = x;
} else {
end = x;
}
}
return x;
}
private static double computeHeightForDistAndTan( int h0, double speed, double tan, double dist) {
return h0 + dist * tan - G * dist * dist * ( 1 + tan * tan) / ( 2 * speed * speed) ;
}
public static int [ ] readArrayLine
( String line,
int n
) { return readArrayLine( line, n, null , 0 ) ;
}
private static int [ ] readArrayLine
( String line,
int n,
int array
[ ] ,
int pos
) { int [ ] ret = array == null ? new int [ n] : array;
int start = 0 ;
int end = line.indexOf ( ' ' , start) ;
for ( int i = pos; i < pos + n; i++ ) {
if ( end > 0 )
ret
[ i
] = Integer .
parseInt ( line.
substring ( start, end
) ) ; else
ret
[ i
] = Integer .
parseInt ( line.
substring ( start
) ) ; start = end + 1 ;
end = line.indexOf ( ' ' , start) ;
}
return ret;
}
}
CgppbXBvcnQgamF2YS5hd3QuZ2VvbS5MaW5lMkQ7CmltcG9ydCBqYXZhLmlvLkJ1ZmZlcmVkUmVhZGVyOwppbXBvcnQgamF2YS5pby5JT0V4Y2VwdGlvbjsKaW1wb3J0IGphdmEuaW8uSW5wdXRTdHJlYW1SZWFkZXI7CmltcG9ydCBqYXZhLnV0aWwuQXJyYXlMaXN0OwppbXBvcnQgamF2YS51dGlsLkxpbmtlZExpc3Q7CmltcG9ydCBqYXZhLnV0aWwuTGlzdDsKCmltcG9ydCBzdGF0aWMgamF2YS5sYW5nLkRvdWJsZS5tYXg7CmltcG9ydCBzdGF0aWMgamF2YS5sYW5nLkRvdWJsZS5taW47CgpwdWJsaWMgY2xhc3MgTWFpbiB7CgogICAgcHJpdmF0ZSBzdGF0aWMgZmluYWwgZG91YmxlIEcgPSA5LjgwNjY1OwoKICAgIHN0YXRpYyBjbGFzcyBCdWlsZGluZyB7CiAgICAgICAgaW50IHgsIHksIHo7CiAgICAgICAgYm9vbGVhbiB2aXNpdGVkOwogICAgICAgIGludCBzdGVwcyA9IDA7CiAgICAgICAgaW50IGksIGo7CgogICAgICAgIEJ1aWxkaW5nKGludCB4LCBpbnQgeSwgaW50IHosIGludCBpLCBpbnQgaikgewogICAgICAgICAgICB0aGlzLnggPSB4OwogICAgICAgICAgICB0aGlzLnkgPSB5OwogICAgICAgICAgICB0aGlzLnogPSB6OwogICAgICAgICAgICB0aGlzLmkgPSBpOwogICAgICAgICAgICB0aGlzLmogPSBqOwogICAgICAgIH0KCiAgICAgICAgQE92ZXJyaWRlCiAgICAgICAgcHVibGljIFN0cmluZyB0b1N0cmluZygpIHsKICAgICAgICAgICAgcmV0dXJuICJCdWlsZGluZ3siICsKICAgICAgICAgICAgICAgICAgICAieD0iICsgeCArCiAgICAgICAgICAgICAgICAgICAgIiwgeT0iICsgeSArCiAgICAgICAgICAgICAgICAgICAgIiwgej0iICsgeiArCiAgICAgICAgICAgICAgICAgICAgJ30nOwogICAgICAgIH0KICAgIH0KCiAgICBzdGF0aWMgY2xhc3MgU2VnbWVudCB7CiAgICAgICAgZG91YmxlIHgxLCB5MSwgeDIsIHkyOwoKICAgICAgICBwdWJsaWMgU2VnbWVudChkb3VibGUgeDEsIGRvdWJsZSB5MSwgZG91YmxlIHgyLCBkb3VibGUgeTIpIHsKICAgICAgICAgICAgdGhpcy54MSA9IHgxOwogICAgICAgICAgICB0aGlzLnkxID0geTE7CiAgICAgICAgICAgIHRoaXMueDIgPSB4MjsKICAgICAgICAgICAgdGhpcy55MiA9IHkyOwogICAgICAgIH0KCiAgICAgICAgQE92ZXJyaWRlCiAgICAgICAgcHVibGljIFN0cmluZyB0b1N0cmluZygpIHsKICAgICAgICAgICAgcmV0dXJuICIoIiArIHgxICsgIiwgIiArIHkxICsgIikgLT4gKCIgKyB4MiArICIsICIgKyB5MiArICIpIjsKICAgICAgICB9CgogICAgICAgIC8vICAgICAgICBodHRwczovL2cuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLmIuY29tL2Jhb2JhYktvb2RhYS9Db2RlRm9yY2VzTGlicmFyeS9ibG9iL2FkNjk3MmIxY2NkODdjOTEwMDE3MTEyMjY5MjU2MjcwNGM2OTU3MDMvc3JjL2Jhb2JhYi9BLmphdmEjTDc2NwogICAgICAgIHN0YXRpYyBmaW5hbCBQb2ludCBPVkVSTEFQID0gbmV3IFBvaW50KDAsIDApOwoKICAgICAgICBQb2ludCBpbnRlcnNlY3QoU2VnbWVudCBzKSB7CiAgICAgICAgICAgIC8vIFJldHVybnMgdHJ1ZSBpZiBzZWdtZW50IDEtMiBpbnRlcnNlY3RzIHNlZ21lbnQgMy00CiAgICAgICAgICAgIGRvdWJsZSB4MyA9IHMueDEsIHg0ID0gcy54MiwgeTMgPSBzLnkxLCB5NCA9IHMueTI7CgogICAgICAgICAgICBpZiAoeDEgPT0geDIgJiYgeDMgPT0geDQpIHsKICAgICAgICAgICAgICAgIC8vIEJvdGggc2VnbWVudHMgYXJlIHZlcnRpY2FsCiAgICAgICAgICAgICAgICBpZiAoeDEgIT0geDMpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGlmIChtaW4oeTEsIHkyKSA8IG1pbih5MywgeTQpKSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKG1heCh5MSwgeTIpID49IG1pbih5MywgeTQpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBPVkVSTEFQOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBudWxsOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgaWYgKG1heCh5MywgeTQpID49IG1pbih5MSwgeTIpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBPVkVSTEFQOwogICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBudWxsOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoeDEgPT0geDIpIHsKICAgICAgICAgICAgICAgIC8vIE9ubHkgc2VnbWVudCAxLTIgaXMgdmVydGljYWwuIERvZXMgc2VnbWVudCAzLTQgY3Jvc3MgaXQ/IHkgPSBhKnggKyBiCiAgICAgICAgICAgICAgICBkb3VibGUgYTM0ID0gKHk0IC0geTMpIC8gKHg0IC0geDMpOwogICAgICAgICAgICAgICAgZG91YmxlIGIzNCA9IHkzIC0gYTM0ICogeDM7CiAgICAgICAgICAgICAgICBkb3VibGUgeSA9IGEzNCAqIHgxICsgYjM0OwogICAgICAgICAgICAgICAgaWYgKHkgPj0gbWluKHkxLCB5MikgLSAxZS02ICYmIHkgPD0gbWF4KHkxLCB5MikgICsgMWUtNiAmJiB4MSA+PSBtaW4oeDMsIHg0KSAtIDFlLTYgJiYgeDEgPD0gbWF4KHgzLCB4NCkgKyAxZS02KSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBQb2ludCh4MSwgeSk7CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIHJldHVybiBudWxsOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmICh4MyA9PSB4NCkgewogICAgICAgICAgICAgICAgLy8gT25seSBzZWdtZW50IDMtNCBpcyB2ZXJ0aWNhbC4gRG9lcyBzZWdtZW50IDEtMiBjcm9zcyBpdD8geSA9IGEqeCArIGIKICAgICAgICAgICAgICAgIGRvdWJsZSBhMTIgPSAoeTIgLSB5MSkgLyAoeDIgLSB4MSk7CiAgICAgICAgICAgICAgICBkb3VibGUgYjEyID0geTEgLSBhMTIgKiB4MTsKICAgICAgICAgICAgICAgIGRvdWJsZSB5ID0gYTEyICogeDMgKyBiMTI7CiAgICAgICAgICAgICAgICBpZiAoeSA+PSBtaW4oeTMsIHk0KSAtIDFlLTYgJiYgeSA8PSBtYXgoeTMsIHk0KSArIDFlLTYgJiYgeDMgPj0gbWluKHgxLCB4MikgLSAxZS02ICYmIHgzIDw9IG1heCh4MSwgeDIpICsgMWUtNikgewogICAgICAgICAgICAgICAgICAgIHJldHVybiBuZXcgUG9pbnQoeDMsIHkpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBkb3VibGUgYTEyID0gKHkyIC0geTEpIC8gKHgyIC0geDEpOwogICAgICAgICAgICBkb3VibGUgYjEyID0geTEgLSBhMTIgKiB4MTsKICAgICAgICAgICAgZG91YmxlIGEzNCA9ICh5NCAtIHkzKSAvICh4NCAtIHgzKTsKICAgICAgICAgICAgZG91YmxlIGIzNCA9IHkzIC0gYTM0ICogeDM7CiAgICAgICAgICAgIGlmIChjbG9zZVRvWmVybyhhMTIgLSBhMzQpKSB7CiAgICAgICAgICAgICAgICAvLyBQYXJhbGxlbCBsaW5lcwogICAgICAgICAgICAgICAgaWYgKGNsb3NlVG9aZXJvKGIxMiAtIGIzNCkpIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gT1ZFUkxBUDsKICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG51bGw7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gTm9uIHBhcmFsbGVsIG5vbiB2ZXJ0aWNhbCBsaW5lcyBpbnRlcnNlY3QgYXQgeC4gSXMgeCBwYXJ0IG9mIGJvdGggc2VnbWVudHM/CiAgICAgICAgICAgIGRvdWJsZSB4ID0gLShiMTIgLSBiMzQpIC8gKGExMiAtIGEzNCk7CiAgICAgICAgICAgIGlmICh4ID49IG1pbih4MSwgeDIpIC0gMWUtNiAmJiB4IDw9IG1heCh4MSwgeDIpICsgMWUtNiAmJiB4ID49IG1pbih4MywgeDQpIC0gMWUtNiAmJiB4IDw9IG1heCh4MywgeDQpICsgMWUtNikgewogICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBQb2ludCh4LCBhMTIgKiB4ICsgYjEyKTsKICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIHJldHVybiBudWxsOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICBib29sZWFuIGNsb3NlVG9aZXJvKGRvdWJsZSB2KSB7CiAgICAgICAgICAgIC8vIENoZWNrIGlmIGRvdWJsZSBpcyBjbG9zZSB0byB6ZXJvLCBjb25zaWRlcmluZyBwcmVjaXNpb24gaXNzdWVzLgogICAgICAgICAgICByZXR1cm4gTWF0aC5hYnModikgPD0gMC4wMDAwMDAwMDAwMDAxOwogICAgICAgIH0KICAgIH0KCiAgICBzdGF0aWMgY2xhc3MgUG9pbnQgewogICAgICAgIGRvdWJsZSB4LCB5OwoKICAgICAgICBwdWJsaWMgUG9pbnQoZG91YmxlIHgsIGRvdWJsZSB5KSB7CiAgICAgICAgICAgIHRoaXMueCA9IHg7CiAgICAgICAgICAgIHRoaXMueSA9IHk7CiAgICAgICAgfQoKICAgICAgICBAT3ZlcnJpZGUKICAgICAgICBwdWJsaWMgU3RyaW5nIHRvU3RyaW5nKCkgewogICAgICAgICAgICByZXR1cm4gIigiICsgeCArICIsICIgKyB5ICsgIikiOwogICAgICAgIH0KICAgIH0KCiAgICBwdWJsaWMgc3RhdGljIHZvaWQgbWFpbihTdHJpbmdbXSBhcmdzKSB0aHJvd3MgSU9FeGNlcHRpb24gewoKICAgICAgICBCdWZmZXJlZFJlYWRlciBiciA9IG5ldyBCdWZmZXJlZFJlYWRlcihuZXcgSW5wdXRTdHJlYW1SZWFkZXIoU3lzdGVtLmluKSwgMTAyNCAqIDEwMjQgKiAyKTsKCiAgICAgICAgaW50W10gdiA9IHJlYWRBcnJheUxpbmUoYnIucmVhZExpbmUoKSwgNik7CiAgICAgICAgaW50IG0gPSB2WzBdLCBuID0gdlsxXTsKICAgICAgICBkb3VibGUgdyA9IHZbMl0sIHNwZWVkID0gdlszXTsKICAgICAgICBpbnQgbHggPSB2WzRdIC0gMSwgbHkgPSB2WzVdIC0gMTsKCiAgICAgICAgQnVpbGRpbmdbXVtdIGIgPSBuZXcgQnVpbGRpbmdbbl1bbV07CgogICAgICAgIGludCBjdXJyZW50WDsKICAgICAgICBpbnQgY3VycmVudFkgPSAwOwogICAgICAgIGZvciAoaW50IGkgPSAwOyBpIDwgbjsgaSsrKSB7CiAgICAgICAgICAgIHYgPSByZWFkQXJyYXlMaW5lKGJyLnJlYWRMaW5lKCksIG0pOwogICAgICAgICAgICBjdXJyZW50WCA9IDA7CiAgICAgICAgICAgIGZvciAoaW50IGogPSAwOyBqIDwgbTsgaisrKSB7CiAgICAgICAgICAgICAgICBiW2ldW2pdID0gbmV3IEJ1aWxkaW5nKGN1cnJlbnRYLCBjdXJyZW50WSwgdltqXSwgaSwgaik7CiAgICAgICAgICAgICAgICBjdXJyZW50WCArPSB3OwogICAgICAgICAgICB9CiAgICAgICAgICAgIGN1cnJlbnRZICs9IHc7CiAgICAgICAgfQoKLy8gICAgICAgIFNlZ21lbnRbXSBob3Jpem9udGFsID0gbmV3IFNlZ21lbnRbbiAtIDFdOwovLyAgICAgICAgU2VnbWVudFtdIHZlcnRpY2FsID0gbmV3IFNlZ21lbnRbbSAtIDFdOwovLyAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCBuIC0gMTsgaSsrKSB7Ci8vICAgICAgICAgICAgZG91YmxlIGh5ID0gdyAvIDIgKyB3ICogaTsKLy8gICAgICAgICAgICBob3Jpem9udGFsW2ldID0gbmV3IFNlZ21lbnQoMCwgaHksIHcgKiAobiAtIDEpLCBoeSk7Ci8vICAgICAgICB9Ci8vCi8vICAgICAgICBmb3IgKGludCBpID0gMDsgaSA8IG0gLSAxOyBpKyspIHsKLy8gICAgICAgICAgICBkb3VibGUgdnggPSB3IC8gMiArIHcgKiBpOwovLyAgICAgICAgICAgIHZlcnRpY2FsW2ldID0gbmV3IFNlZ21lbnQodngsIDAsIHZ4LCB3ICogKG0gLSAxKSk7Ci8vICAgICAgICB9CgogICAgICAgIEJ1aWxkaW5nIHJvb3QgPSBiW2x5XVtseF07CiAgICAgICAgTGlua2VkTGlzdDxCdWlsZGluZz4gcXVldWUgPSBuZXcgTGlua2VkTGlzdDw+KCk7CiAgICAgICAgcXVldWUuYWRkKHJvb3QpOwogICAgICAgIHJvb3QudmlzaXRlZCA9IHRydWU7CgogICAgICAgIHdoaWxlICghcXVldWUuaXNFbXB0eSgpKSB7CiAgICAgICAgICAgIHJvb3QgPSBxdWV1ZS5wb2xsKCk7CgogICAgICAgICAgICBpZiAocm9vdCA9PSBudWxsKSB7CiAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCBuOyBpKyspIHsKICAgICAgICAgICAgICAgIGZvciAoaW50IGogPSAwOyBqIDwgbTsgaisrKSB7CiAgICAgICAgICAgICAgICAgICAgQnVpbGRpbmcgZGVzdCA9IGJbaV1bal07CiAgICAgICAgICAgICAgICAgICAgaWYgKGRlc3QudmlzaXRlZCkgewogICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgICAgICAgICB9CgovLyAgICAgICAgICAgICAgICAgICAgaWYgKGNhbkp1bXAocm9vdCwgZGVzdCwgc3BlZWQsIHZlcnRpY2FsLCBob3Jpem9udGFsLCB3LCBiKSkgewogICAgICAgICAgICAgICAgICAgIGlmIChjYW5KdW1wU21hcnQocm9vdCwgZGVzdCwgc3BlZWQsIHcsIGIpKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIGRlc3Quc3RlcHMgPSByb290LnN0ZXBzICsgMTsKICAgICAgICAgICAgICAgICAgICAgICAgZGVzdC52aXNpdGVkID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgcXVldWUuYWRkKGRlc3QpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCBuOyBpKyspIHsKICAgICAgICAgICAgZm9yIChpbnQgaiA9IDA7IGogPCBtOyBqKyspIHsKICAgICAgICAgICAgICAgIGlmIChiW2ldW2pdLnN0ZXBzID09IDAgJiYgKGkgIT0gbHkgfHwgaiAhPSBseCkpIHsKICAgICAgICAgICAgICAgICAgICBTeXN0ZW0ub3V0LnByaW50KCJYICIpOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICBTeXN0ZW0ub3V0LnByaW50KGJbaV1bal0uc3RlcHMgKyAiICIpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigpOwogICAgICAgIH0KICAgIH0KCgovLyAgICBwcml2YXRlIHN0YXRpYyBib29sZWFuIGNhbkp1bXAoQnVpbGRpbmcgcm9vdCwgQnVpbGRpbmcgZGVzdCwgZG91YmxlIHNwZWVkLCBTZWdtZW50W10gdmVydGljYWwsIFNlZ21lbnRbXSBob3Jpem9udGFsLCBkb3VibGUgdywgQnVpbGRpbmcgYltdW10pIHsKLy8gICAgICAgIGRvdWJsZSBkaXN0ID0gZ2V0SG9yaXpvbnRhbERpc3RCZXR3ZWVuU3F1YXJlZChyb290LCBkZXN0KTsKLy8gICAgICAgIGludCBoZWlnaHREaWZmID0gZGVzdC56IC0gcm9vdC56OwovLwovLyAgICAgICAgZG91YmxlIGxhdW5jaEFuZ2xlID0gZ2V0QW5nbGUoc3BlZWQsIE1hdGguc3FydChkaXN0KSwgaGVpZ2h0RGlmZik7Ci8vICAgICAgICBpZiAobGF1bmNoQW5nbGUgPiAwKSB7Ci8vICAgICAgICAgICAgcmV0dXJuIGNoZWNrVHJhamVjdG9yeShiLCBzcGVlZCwgcm9vdCwgZGVzdCwgTWF0aC50YW4obGF1bmNoQW5nbGUpLCB2ZXJ0aWNhbCwgaG9yaXpvbnRhbCwgdyk7Ci8vICAgICAgICB9Ci8vICAgICAgICByZXR1cm4gZmFsc2U7Ci8vICAgIH0KCiAgICBwcml2YXRlIHN0YXRpYyBib29sZWFuIGNhbkp1bXBTbWFydChCdWlsZGluZyByb290LCBCdWlsZGluZyBkZXN0LCBkb3VibGUgc3BlZWQsIGRvdWJsZSB3LCBCdWlsZGluZyBiW11bXSkgewogICAgICAgIGRvdWJsZSBkaXN0ID0gZ2V0SG9yaXpvbnRhbERpc3RCZXR3ZWVuU3F1YXJlZChyb290LCBkZXN0KTsKICAgICAgICBpbnQgaGVpZ2h0RGlmZiA9IGRlc3QueiAtIHJvb3QuejsKCiAgICAgICAgZG91YmxlIHRhbmdlbnRPZkxhdW5jaEFuZ2xlID0gZ2V0VGFuZ2VudE9mTGF1bmNoQW5nbGUoc3BlZWQsIE1hdGguc3FydChkaXN0KSwgaGVpZ2h0RGlmZiwgMSk7CiAgICAgICAgZG91YmxlIHRhbmdlbnRPZkxhdW5jaEFuZ2xlMSA9IGdldFRhbmdlbnRPZkxhdW5jaEFuZ2xlKHNwZWVkLCBNYXRoLnNxcnQoZGlzdCksIGhlaWdodERpZmYsIC0xKTsKCiAgICAgICAgYm9vbGVhbiBjaGVjazEgPSBmYWxzZTsKICAgICAgICBpZiAodGFuZ2VudE9mTGF1bmNoQW5nbGUgPiAwKSB7CiAgICAgICAgICAgIGNoZWNrMSA9IGNoZWNrVHJhamVjdG9yeVNpbXBsZShiLCBzcGVlZCwgcm9vdCwgZGVzdCx0YW5nZW50T2ZMYXVuY2hBbmdsZSwgdyk7CiAgICAgICAgfQoKICAgICAgICBib29sZWFuIGNoZWNrMiA9IGZhbHNlOwogICAgICAgIGlmICh0YW5nZW50T2ZMYXVuY2hBbmdsZTEgPiAwKSB7CiAgICAgICAgICAgIGNoZWNrMiA9IGNoZWNrVHJhamVjdG9yeVNpbXBsZShiLCBzcGVlZCwgcm9vdCwgZGVzdCwgdGFuZ2VudE9mTGF1bmNoQW5nbGUxLCB3KTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGNoZWNrMSB8fCBjaGVjazI7CiAgICB9CgogICAgcHJpdmF0ZSBzdGF0aWMgYm9vbGVhbiBpc0Fib3ZlQnVpbGRpbmcoQnVpbGRpbmcgYiwgZG91YmxlIHNwZWVkLCBkb3VibGUgdGFuZ2VudE9mTGF1bmNoQW5nbGUsIFBvaW50IGludGVyc2VjdGlvbiwgaW50IGgwKSB7CiAgICAgICAgZG91YmxlIHhEaXN0ID0gYi54IC0gaW50ZXJzZWN0aW9uLng7CiAgICAgICAgZG91YmxlIHlEaXN0ID0gYi55IC0gaW50ZXJzZWN0aW9uLnk7CiAgICAgICAgZG91YmxlIGRpc3QgPSBNYXRoLnNxcnQoeERpc3QgKiB4RGlzdCArIHlEaXN0ICogeURpc3QpOwogICAgICAgIGRvdWJsZSBjb21wdXRlZEhlaWdodCA9IGNvbXB1dGVIZWlnaHRGb3JEaXN0QW5kVGFuKGgwLCBzcGVlZCwgdGFuZ2VudE9mTGF1bmNoQW5nbGUsIGRpc3QpOwogICAgICAgIHJldHVybiBjb21wdXRlZEhlaWdodCA+PSBiLnogLSAxZS05OwogICAgfQoKICAgIHByaXZhdGUgc3RhdGljIGJvb2xlYW4gY2hlY2tUcmFqZWN0b3J5U2ltcGxlKEJ1aWxkaW5nW11bXSBiLCBkb3VibGUgc3BlZWQsIEJ1aWxkaW5nIHJvb3QsIEJ1aWxkaW5nIGRlc3QsIGRvdWJsZSB0YW4sIGRvdWJsZSB3KSB7CiAgICAgICAgU2VnbWVudCBzID0gbmV3IFNlZ21lbnQocm9vdC54LCByb290LnksIGRlc3QueCwgZGVzdC55KTsKICAgICAgICBpbnQgaDAgPSByb290Lno7CiAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCBiLmxlbmd0aCA7IGkgKyspIHsKICAgICAgICAgICAgZm9yIChpbnQgaiA9IDAgOyBqIDwgYltpXS5sZW5ndGggOyBqKyspIHsKICAgICAgICAgICAgICAgIGRvdWJsZSB4ID0gYltpXVtqXS54OwogICAgICAgICAgICAgICAgZG91YmxlIHkgPSBiW2ldW2pdLnk7CiAgICAgICAgICAgICAgICBMaXN0PFBvaW50PiBwb2x5Z29uID0gbmV3IEFycmF5TGlzdDw+KCk7CiAgICAgICAgICAgICAgICBwb2x5Z29uLmFkZChuZXcgUG9pbnQoeCAtIHcvMiwgeSAtIHcvMikpOwogICAgICAgICAgICAgICAgcG9seWdvbi5hZGQobmV3IFBvaW50KHggKyB3LzIsIHkgLSB3LzIpKTsKICAgICAgICAgICAgICAgIHBvbHlnb24uYWRkKG5ldyBQb2ludCh4ICsgdy8yLCB5ICsgdy8yKSk7CiAgICAgICAgICAgICAgICBwb2x5Z29uLmFkZChuZXcgUG9pbnQoeCAtIHcvMiwgeSArIHcvMikpOwoKICAgICAgICAgICAgICAgIFBvaW50IGludGVyc2VjdCA9IG51bGw7CiAgICAgICAgICAgICAgICBmb3IgKGludCBrID0gMCA7IGsgPCA0IDsgayArKykgewogICAgICAgICAgICAgICAgICAgIFBvaW50IHAxID0gcG9seWdvbi5nZXQoayk7CiAgICAgICAgICAgICAgICAgICAgUG9pbnQgcDIgPSBwb2x5Z29uLmdldCgoaysxKSVwb2x5Z29uLnNpemUoKSk7CiAgICAgICAgICAgICAgICAgICAgU2VnbWVudCBwb2x5U2VnID0gbmV3IFNlZ21lbnQocDEueCwgcDEueSwgcDIueCwgcDIueSk7CiAgICAgICAgICAgICAgICAgICAgaW50ZXJzZWN0ID0gcy5pbnRlcnNlY3QocG9seVNlZyk7CiAgICAgICAgICAgICAgICAgICAgYm9vbGVhbiBpbnRlciA9IExpbmUyRC5saW5lc0ludGVyc2VjdChwMS54LCBwMS55LCBwMi54LCBwMi55LCBzLngxLCBzLnkxLCBzLngyLCBzLnkyKTsKICAgICAgICAgICAgICAgICAgICBpZiAoaW50ZXJzZWN0ICE9IG51bGwgJiYgaW50ZXJzZWN0ICE9IFNlZ21lbnQuT1ZFUkxBUCkgewogICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWludGVyKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBudWxsOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghaXNBYm92ZUJ1aWxkaW5nKGJbaV1bal0sIHNwZWVkLCB0YW4sIGludGVyc2VjdCwgaDApKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICBpZiAoaW50ZXIpIHsKLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKHMgKyAiICIgKyBwb2x5U2VnICsgIiAiICArIGludGVyc2VjdCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBudWxsOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KCi8vICAgIHByaXZhdGUgc3RhdGljIGJvb2xlYW4gY2hlY2tUcmFqZWN0b3J5KEJ1aWxkaW5nW11bXSBiLCBkb3VibGUgc3BlZWQsIEJ1aWxkaW5nIHJvb3QsIEJ1aWxkaW5nIGRlc3QsIGRvdWJsZSB0YW4sIFNlZ21lbnRbXSB2ZXJ0aWNhbHMsIFNlZ21lbnRbXSBob3Jpem9udGFscywgZG91YmxlIHcpIHsKLy8KLy8gICAgICAgIFNlZ21lbnQgcyA9IG5ldyBTZWdtZW50KHJvb3QueCwgcm9vdC55LCBkZXN0LngsIGRlc3QueSk7Ci8vICAgICAgICBNYXA8U2VnbWVudCwgUG9pbnQ+IHNlZ21lbnRQb2ludE1hcCA9IG5ldyBIYXNoTWFwPD4oKTsKLy8gICAgICAgIGludCBoMCA9IHJvb3QuejsKLy8gICAgICAgIGZvciAoaW50IGkgPSAwOyBpIDwgaG9yaXpvbnRhbHMubGVuZ3RoOyBpKyspIHsKLy8gICAgICAgICAgICBTZWdtZW50IHNlZ21lbnQgPSBob3Jpem9udGFsc1tpXTsKLy8gICAgICAgICAgICBQb2ludCBpbnRlcnNlY3QgPSBzLmludGVyc2VjdChzZWdtZW50KTsKLy8gICAgICAgICAgICBpZiAoaW50ZXJzZWN0ICE9IG51bGwgJiYgaW50ZXJzZWN0ICE9IFNlZ21lbnQuT1ZFUkxBUCkgewovLy8vICAgICAgICAgICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbihpbnRlcnNlY3QgKyAiID0gIiArICgiWyIgKyByb290LmkgKyAiLCAiICsgcm9vdC5qICsgIl0iKSArICIgIiArICgiWyIgKyBkZXN0LmkgKyAiLCAiICsgZGVzdC5qICsgIl0iKSArICIgLS0tLT4gIiArIHNlZ21lbnQpOwovLyAgICAgICAgICAgICAgICBzZWdtZW50UG9pbnRNYXAucHV0KHNlZ21lbnQsIGludGVyc2VjdCk7Ci8vICAgICAgICAgICAgICAgIGlmICh2ZXJ0aWNhbHMubGVuZ3RoID4gMCkgewovLyAgICAgICAgICAgICAgICAgICAgaWYgKGludGVyc2VjdC54ID49IHZlcnRpY2Fsc1swXS54MSAtIHcgJiYgaW50ZXJzZWN0LnggPD0gdmVydGljYWxzWzBdLngxKSB7Ci8vLy8gICAgICAgICAgICAgICAgICAgICAgICBTeXN0ZW0ub3V0LnByaW50bG4oKCItPiBbIiArIGkgKyAiLCAiICsgMCArICJdIikgKyAiICIgKyAoIlsiICsgKGkgKyAxKSArICIsICIgKyAwICsgIl0iKSk7Ci8vICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFpc0Fib3ZlQnVpbGRpbmcoYltpXVswXSwgc3BlZWQsIHRhbiwgaW50ZXJzZWN0LCBoMCkKLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHx8ICFpc0Fib3ZlQnVpbGRpbmcoYltpICsgMV1bMF0sIHNwZWVkLCB0YW4sIGludGVyc2VjdCwgaDApKSB7Ci8vICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKLy8gICAgICAgICAgICAgICAgICAgICAgICB9Ci8vICAgICAgICAgICAgICAgICAgICB9Ci8vICAgICAgICAgICAgICAgICAgICBmb3IgKGludCBqID0gMDsgaiA8IHZlcnRpY2Fscy5sZW5ndGg7IGorKykgewovLyAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpbnRlcnNlY3QueCA+PSB2ZXJ0aWNhbHNbal0ueDEgJiYgaW50ZXJzZWN0LnggPD0gdmVydGljYWxzW2pdLngxICsgdykgewovLy8vICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigoIi0+IFsiICsgaSArICIsICIgKyAoaiArIDEpICsgIl0iKSArICIgIiArICgiWyIgKyAoaSArIDEpICsgIiwgIiArIChqICsgMSkgKyAiXSIpKTsKLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFpc0Fib3ZlQnVpbGRpbmcoYltpXVtqICsgMV0sIHNwZWVkLCB0YW4sIGludGVyc2VjdCwgaDApCi8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfHwgIWlzQWJvdmVCdWlsZGluZyhiW2kgKyAxXVtqICsgMV0sIHNwZWVkLCB0YW4sIGludGVyc2VjdCwgaDApKSB7Ci8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7Ci8vICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KLy8gICAgICAgICAgICAgICAgICAgICAgICB9Ci8vICAgICAgICAgICAgICAgICAgICB9Ci8vICAgICAgICAgICAgICAgIH0gZWxzZSB7Ci8vLy8gICAgICAgICAgICAgICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigoIi0+IFsiICsgaSArICIsICIgKyAwICsgIl0iKSArICIgIiArICgiWyIgKyAoaSArIDEpICsgIiwgIiArIDAgKyAiXSIpKTsKLy8gICAgICAgICAgICAgICAgICAgIGlmICghaXNBYm92ZUJ1aWxkaW5nKGJbaV1bMF0sIHNwZWVkLCB0YW4sIGludGVyc2VjdCwgaDApCi8vICAgICAgICAgICAgICAgICAgICAgICAgICAgIHx8ICFpc0Fib3ZlQnVpbGRpbmcoYltpICsgMV1bMF0sIHNwZWVkLCB0YW4sIGludGVyc2VjdCwgaDApKSB7Ci8vICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwovLyAgICAgICAgICAgICAgICAgICAgfQovLyAgICAgICAgICAgICAgICB9Ci8vICAgICAgICAgICAgfQovLyAgICAgICAgfQovLwovLyAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCB2ZXJ0aWNhbHMubGVuZ3RoOyBpKyspIHsKLy8gICAgICAgICAgICBTZWdtZW50IHNlZ21lbnQgPSB2ZXJ0aWNhbHNbaV07Ci8vICAgICAgICAgICAgUG9pbnQgaW50ZXJzZWN0ID0gcy5pbnRlcnNlY3Qoc2VnbWVudCk7Ci8vICAgICAgICAgICAgaWYgKGludGVyc2VjdCAhPSBudWxsICYmIGludGVyc2VjdCAhPSBTZWdtZW50Lk9WRVJMQVApIHsKLy8vLyAgICAgICAgICAgICAgICBTeXN0ZW0ub3V0LnByaW50bG4oaW50ZXJzZWN0ICsgIiA9ICIgKyAoIlsiICsgcm9vdC5pICsgIiwgIiArIHJvb3QuaiArICJdIikgKyAiICIgKyAoIlsiICsgZGVzdC5pICsgIiwgIiArIGRlc3QuaiArICJdIikgKyAiIC0tLS0+ICIgKyBzZWdtZW50KTsKLy8gICAgICAgICAgICAgICAgc2VnbWVudFBvaW50TWFwLnB1dChzZWdtZW50LCBpbnRlcnNlY3QpOwovLyAgICAgICAgICAgICAgICBpZiAoaG9yaXpvbnRhbHMubGVuZ3RoID4gMCkgewovLyAgICAgICAgICAgICAgICAgICAgaWYgKGludGVyc2VjdC55ID49IGhvcml6b250YWxzWzBdLnkxIC0gdyAmJiBpbnRlcnNlY3QueSA8PSBob3Jpem9udGFsc1swXS55MSkgewovLy8vICAgICAgICAgICAgICAgICAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCgiLTwgWyIgKyAwICsgIiwgIiArIGkgKyAiXSIpICsgIiAiICsgKCJbIiArIDAgKyAiLCAiICsgKGkgKyAxKSArICJdIikpOwovLyAgICAgICAgICAgICAgICAgICAgICAgIGlmICghaXNBYm92ZUJ1aWxkaW5nKGJbMF1baV0sIHNwZWVkLCB0YW4sIGludGVyc2VjdCwgaDApCi8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8fCAhaXNBYm92ZUJ1aWxkaW5nKGJbMF1baSArIDFdLCBzcGVlZCwgdGFuLCBpbnRlcnNlY3QsIGgwKSkgewovLyAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7Ci8vICAgICAgICAgICAgICAgICAgICAgICAgfQovLyAgICAgICAgICAgICAgICAgICAgfQovLyAgICAgICAgICAgICAgICAgICAgZm9yIChpbnQgaiA9IDA7IGogPCBob3Jpem9udGFscy5sZW5ndGg7IGorKykgewovLyAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpbnRlcnNlY3QueSA+PSBob3Jpem9udGFsc1tqXS55MSAmJiBpbnRlcnNlY3QueSA8PSBob3Jpem9udGFsc1tqXS55MSArIHcpIHsKLy8vLyAgICAgICAgICAgICAgICAgICAgICAgICAgICBTeXN0ZW0ub3V0LnByaW50bG4oKCItPCBbIiArIChqICsgMSkgKyAiLCAiICsgaSArICJdIikgKyAiICIgKyAoIlsiICsgKGogKyAxKSArICIsICIgKyAoaSArIDEpICsgIl0iKSk7Ci8vICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghaXNBYm92ZUJ1aWxkaW5nKGJbaiArIDFdW2ldLCBzcGVlZCwgdGFuLCBpbnRlcnNlY3QsIGgwKQovLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHx8ICFpc0Fib3ZlQnVpbGRpbmcoYltqICsgMV1baSArIDFdLCBzcGVlZCwgdGFuLCBpbnRlcnNlY3QsIGgwKSkgewovLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwovLyAgICAgICAgICAgICAgICAgICAgICAgICAgICB9Ci8vICAgICAgICAgICAgICAgICAgICAgICAgfQovLyAgICAgICAgICAgICAgICAgICAgfQovLyAgICAgICAgICAgICAgICB9IGVsc2UgewovLy8vICAgICAgICAgICAgICAgICAgICBTeXN0ZW0ub3V0LnByaW50bG4oKCItPCBbIiArIDAgKyAiLCAiICsgaSArICJdIikgKyAiICIgKyAoIlsiICsgMCArICIsICIgKyAoaSArIDEpICsgIl0iKSk7Ci8vICAgICAgICAgICAgICAgICAgICBpZiAoIWlzQWJvdmVCdWlsZGluZyhiWzBdW2ldLCBzcGVlZCwgdGFuLCBpbnRlcnNlY3QsIGgwKQovLyAgICAgICAgICAgICAgICAgICAgICAgICAgICB8fCAhaXNBYm92ZUJ1aWxkaW5nKGJbMF1baSArIDFdLCBzcGVlZCwgdGFuLCBpbnRlcnNlY3QsIGgwKSkgewovLyAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKLy8gICAgICAgICAgICAgICAgICAgIH0KLy8gICAgICAgICAgICAgICAgfQovLyAgICAgICAgICAgIH0KLy8gICAgICAgIH0KLy8KLy8vLyAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCJlbmQgZm9yICIgKyAoIlsiICsgcm9vdC5pICsgIiwgIiArIHJvb3QuaiArICJdIikgKyAiICIgKyAoIlsiICsgZGVzdC5pICsgIiwgIiArIGRlc3QuaiArICJdIikpOwovLy8vICAgICAgICBTeXN0ZW0ub3V0LnByaW50bG4oKTsKLy8gICAgICAgIHJldHVybiB0cnVlOwovLyAgICB9CgogICAgcHJpdmF0ZSBzdGF0aWMgZG91YmxlIGdldEhvcml6b250YWxEaXN0QmV0d2VlblNxdWFyZWQoQnVpbGRpbmcgYjEsIEJ1aWxkaW5nIGIyKSB7CiAgICAgICAgcmV0dXJuIChiMS54IC0gYjIueCkgKiAoYjEueCAtIGIyLngpICsgKGIxLnkgLSBiMi55KSAqIChiMS55IC0gYjIueSk7CiAgICB9CgogICAgcHJpdmF0ZSBzdGF0aWMgZG91YmxlIGdldFRhbmdlbnRPZkxhdW5jaEFuZ2xlKGRvdWJsZSBzcGVlZCwgZG91YmxlIGRpc3QsIGRvdWJsZSBoLCBpbnQgY29lZikgewogICAgICAgIGRvdWJsZSBhID0gRyAqIGRpc3QgKiBkaXN0IC8gKDIgKiBzcGVlZCAqIHNwZWVkKTsKICAgICAgICBkb3VibGUgYiA9IC1kaXN0OwogICAgICAgIGRvdWJsZSBjID0gYSArIGg7CgogICAgICAgIGRvdWJsZSBkZWx0YSA9IGIgKiBiIC0gNCAqIGEgKiBjOwoKICAgICAgICBpZiAoZGVsdGEgPCAwKSB7CiAgICAgICAgICAgIHJldHVybiAtMTsKICAgICAgICB9CgogICAgICAgIHJldHVybiAoLWIgKyBjb2VmICogTWF0aC5zcXJ0KGRlbHRhKSkgLyAoMiAqIGEpOwogICAgfQoKICAgIHByaXZhdGUgc3RhdGljIGRvdWJsZSBnZXRBbmdsZShkb3VibGUgdiwgZG91YmxlIGRpc3QsIGRvdWJsZSBoKSB7CiAgICAgICAgZG91YmxlIHN0YXJ0ID0gTWF0aC5QSSAvIDI7CiAgICAgICAgZG91YmxlIGVuZCA9IE1hdGguUEkgLyA0OwogICAgICAgIGRvdWJsZSBjb21wdXRlZFkgPSBEb3VibGUuTUFYX1ZBTFVFOwogICAgICAgIGRvdWJsZSB4ID0gMDsKCiAgICAgICAgd2hpbGUgKE1hdGguYWJzKGNvbXB1dGVkWSAtIGgpID4gMC4wMDAwMDUpIHsKICAgICAgICAgICAgeCA9IChzdGFydCArIGVuZCkgLyAyOwogICAgICAgICAgICBpZiAoc3RhcnQgPT0geCB8fCBlbmQgPT0geCkgewogICAgICAgICAgICAgICAgcmV0dXJuIC0xOwogICAgICAgICAgICB9CgogICAgICAgICAgICBkb3VibGUgdnkgPSB2ICogTWF0aC5zaW4oeCk7CiAgICAgICAgICAgIGRvdWJsZSB0aW1lVG9IaWdoZXN0ID0gdnkgLyBHOwogICAgICAgICAgICBkb3VibGUgdnggPSB2ICogTWF0aC5jb3MoeCk7CiAgICAgICAgICAgIGRvdWJsZSB0aW1lVG9EaXN0ID0gZGlzdCAvIHZ4OwoKICAgICAgICAgICAgaWYgKHRpbWVUb0Rpc3QgPCB0aW1lVG9IaWdoZXN0IC0gMWUtOSkgewogICAgICAgICAgICAgICAgZW5kID0geDsKICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICB9CgogICAgICAgICAgICBjb21wdXRlZFkgPSBjb21wdXRlSGVpZ2h0Rm9yRGlzdEFuZFRhbigwLCB2LCBNYXRoLnRhbih4KSwgZGlzdCk7CiAgICAgICAgICAgIGlmIChzdGFydCAtIGVuZCA8IDAuMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEpIHsKICAgICAgICAgICAgICAgIHJldHVybiAtMTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoY29tcHV0ZWRZIDwgaCkgewogICAgICAgICAgICAgICAgc3RhcnQgPSB4OwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgZW5kID0geDsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4geDsKICAgIH0KCiAgICBwcml2YXRlIHN0YXRpYyBkb3VibGUgY29tcHV0ZUhlaWdodEZvckRpc3RBbmRUYW4oaW50IGgwLCBkb3VibGUgc3BlZWQsIGRvdWJsZSB0YW4sIGRvdWJsZSBkaXN0KSB7CiAgICAgICAgcmV0dXJuIGgwICsgZGlzdCAqIHRhbiAtIEcgKiBkaXN0ICogZGlzdCAqICgxICsgdGFuICogdGFuKSAvICgyICogc3BlZWQgKiBzcGVlZCk7CiAgICB9CgogICAgcHVibGljIHN0YXRpYyBpbnRbXSByZWFkQXJyYXlMaW5lKFN0cmluZyBsaW5lLCBpbnQgbikgewogICAgICAgIHJldHVybiByZWFkQXJyYXlMaW5lKGxpbmUsIG4sIG51bGwsIDApOwogICAgfQoKICAgIHByaXZhdGUgc3RhdGljIGludFtdIHJlYWRBcnJheUxpbmUoU3RyaW5nIGxpbmUsIGludCBuLCBpbnQgYXJyYXlbXSwgaW50IHBvcykgewogICAgICAgIGludFtdIHJldCA9IGFycmF5ID09IG51bGwgPyBuZXcgaW50W25dIDogYXJyYXk7CiAgICAgICAgaW50IHN0YXJ0ID0gMDsKICAgICAgICBpbnQgZW5kID0gbGluZS5pbmRleE9mKCcgJywgc3RhcnQpOwogICAgICAgIGZvciAoaW50IGkgPSBwb3M7IGkgPCBwb3MgKyBuOyBpKyspIHsKICAgICAgICAgICAgaWYgKGVuZCA+IDApCiAgICAgICAgICAgICAgICByZXRbaV0gPSBJbnRlZ2VyLnBhcnNlSW50KGxpbmUuc3Vic3RyaW5nKHN0YXJ0LCBlbmQpKTsKICAgICAgICAgICAgZWxzZQogICAgICAgICAgICAgICAgcmV0W2ldID0gSW50ZWdlci5wYXJzZUludChsaW5lLnN1YnN0cmluZyhzdGFydCkpOwogICAgICAgICAgICBzdGFydCA9IGVuZCArIDE7CiAgICAgICAgICAgIGVuZCA9IGxpbmUuaW5kZXhPZignICcsIHN0YXJ0KTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHJldDsKICAgIH0KfQo=