import static java.
lang.
Math.
max; import static java.
lang.
Math.
min;
class KthLargestTwoArrays {
/**
* Given two sorted arrays of equal sizes, finds the median of the
* array that comes out after `a` and `b` being merged. Runs in
* linear time and does not require any extra space.
*
* The algorithm is similar to the arrays merging, but it
* does not save the merged array, it just iterates through both
* of them by n+1 items (thus stopping in the middle of an imaginary
* merged array) and memorizes two consecutive elements. These
* are the two elements laying exactly in the middle of merged array.
*
* (Since the length of the merged array is even, its median
* is an average value of two elements in the middle.)
*
* @param a a sorted array
* @param b a sorted array
*/
static double medianTwoArraysLinear(double[] a, double[] b) {
if (a.length != b.length) {
"Expected: len(a) == len(b)."
+ " Got: len(a) = %d, len(b) = %d",
a.length, b.length
));
}
final int n = a.length;
int i = 0, j = 0;
// two consecutive elements of the merged array
for (int k = 0; k < n + 1; k++) {
// here we also handle a special case when every element
// of the first array is smaller than the smallest element
// of the second array (and vice versa)
if (j == n || i < n && a[i] < b[j]) {
// put the previous value into the buffer
mid1 = mid2;
mid2 = a[i];
i++;
} else {
mid1 = mid2;
mid2 = b[j];
j++;
}
}
return (mid1 + mid2) / 2;
}
/**
* A logarithmic-time algorithm that solves the same problem.
* The basic idea is to compute the medians of both of the
* arrays (well, these are not exactly "medians", in case the
* array length is even, mid = A[n / 2], not the average value):
* A = [a1, a2, ..., mid1, ..., an]
* B = [b1, b2, ..., mid2, ..., bn]
* and after that there are three cases to consider:
*
* - mid1 == mid2, which means (given len(A) == len(B)) that
* in every array there are n/2 elemets on the left side
* from the mid, so in the merged array mid1 and mid2 would
* be on n/2 + n/2 = n and n+1 positions (thus mid1 is the
* median of the merged array)
*
* - mid1 < mid2 means that the greatest element of the left
* side of the array A (A_left) is at most as large as the
* greatest element of B_left. And similarly the smallest
* element of B_right is at least as large as the smallest
* element of A_right.
*
* This means that the left side of the imaginary merged array
* for sure would not end with an element from A_left, and
* the right side will not start with an value from B_right.
* (It can be easily seen from the example down below, just
* follow the steps of the merge algorithm.)
*
* Thus the desired median elements are somewhere in
* A_right or B_left. When computing the median we can get rid
* of the same amount of elements on the right as on the left side
* and the result will not change in case the elements on the left
* are smaller than the median, meanwhile elements on the right
* are greater. So we can do here: A_left and B_right can be
* thrown away leaving us with just A_right and B_left -
* now we have the same problem but of half of the size.
*
* Example:
* a = [ 1, 2, 3, 4, 8 ]
* b = [ 0, 3, 4, 5, 6 ]
* Merged: [ 0, 1*, 2*, 3, 3* | 4, 4*, 5, 6, 8* ]
* (elements from the first array are marked with asterisks)
*
* - mid1 > mid2 case is handled similarly. */
static double medianTwoArrays(double[] a, double[] b) {
if (a.length != b.length) {
"Expected: len(a) == len(b)."
+ "Got: len(a) = %d, len(b) = %d",
a.length, b.length
));
}
final int n = a.length;
int lo1 = 0, hi1 = n; // left subarray
int lo2 = 0, hi2 = n; // right subarray
while (hi1 - lo1 > 2) {
double mid1 = a[lo1 + hi1 - 1 >>> 1];
double mid2 = b[lo2 + hi2 - 1 >>> 1];
if (mid1 > mid2) {
// swap(a, b); swap(lo1, lo2); swap(hi1, hi2);
double[] arraySwap = a; a = b; b = arraySwap;
int swap = lo1; lo1 = lo2; lo2 = swap;
swap = hi1; hi1 = hi2; hi2 = swap;
} else if (a[lo1 + hi1 >>> 1] == b[lo2 + hi2 - 1 >>> 1]) {
return a[lo1 + hi1 >>> 1];
} else if (a[lo1 + hi1 - 1 >>> 1] == b[lo2 + hi2 >>> 1]) {
return a[lo1 + hi1 >>> 1];
}
int cutLength = hi1 - lo1 - 1 >>> 1;
lo1 += cutLength;
hi2 -= cutLength;
}
if (hi1 - lo1 == 1) {
return (a[lo1] + b[lo2]) / 2;
} else {
assert hi1 - lo1 == 2;
// [a0, a1] [b0, b1] case
// possible merged arrays:
// a0 < b0
// [a0, a1, b0, b1] mid = avg(a1, b0) -- a1 < b0 < b1
// [a0, b0, a1, b1] mid = avg(a1, b0) -- a1 < b1
// [a0, b0, b1, a1] mid = avg(b1, b0) -- a1 > b1
//
// a0 > b0
// [b0, a0, b1, a1] mid = avg(a0, b1) -- a1 > b1
// [b0, a0, a1, b1] mid = avg(a0, a1) -- a1 < b1
// [b0, b1, a0, a1] mid = avg(a0, b1) -- a1 > a0 > b1
return (max(a[lo1], b[lo2])
+ min(a[lo1 + 1], b[lo2 + 1])) / 2;
}
}
/**
* A linear solution of the same problem but now with
* not necesserily equal-length sorted arrays.
* @param a a sorted array
* @param b a sorted array
*/
static double medianTwoDifferentSizeArraysLinear(double[] a,
double[] b) {
assert isSorted(a) && isSorted(b);
// if n := len(a) + len(b) is even, then the median of the
// merged array equals to avg(mrgd[mid - 1], mrgd[mid])
//
// otherwise the median is just mrgd[mid]
final int n = a.length + b.length;
int mid = n >>> 1;
// a and b iterators respectively
int i = 0, j = 0;
for (int k = 0; k < mid + 1; k++) {
median1 = median2;
if (j == b.length || i < a.length && a[i] < b[j]) {
median2 = a[i];
i++;
} else {
median2 = b[j];
j++;
}
}
if (n % 2 == 0) {
return (median1 + median2) / 2;
} else {
return median2;
}
}
/**
* Computes the median of two sorted not necessarily equal
* length arrays. Runs in logarithmic time and does not
* require any extra space.
*/
static double medianTwoDifferentSizeArrays(double[] a, double[] b) {
assert isSorted(a) && isSorted(b);
int lo1 = 0, hi1 = a.length;
int lo2 = 0, hi2 = b.length;
while (hi1 - lo1 > 2 && hi2 - lo2 > 2) {
double median1 = a[lo1 + hi1 - 1 >>> 1];
double median2 = b[lo2 + hi2 - 1 >>> 1];
if (median1 > median2) {
// swap(a, b); swap(lo1, lo2); swap(hi1, hi2);
double[] arraySwap = a; a = b; b = arraySwap;
int swap = lo1; lo1 = lo2; lo2 = swap;
swap = hi1; hi1 = hi2; hi2 = swap;
} else if (a[lo1 + hi1 >>> 1] == b[lo2 + hi2 - 1 >>> 1]) {
return a[lo1 + hi1 >>> 1];
} else if (a[lo1 + hi1 - 1 >>> 1] == b[lo2 + hi2 >>> 1]) {
return a[lo1 + hi1 - 1 >>> 1];
}
// -1 to cut [a0, a1, a2, a3] to [a1, a2, a3]
// not to just [a2, a3]
int cutLength = min((hi1 - lo1 - 1) >>> 1,
(hi2 - lo2 - 1) >>> 1);
lo1 += cutLength;
hi2 -= cutLength;
}
return medianBaseCase(a, lo1, hi1, b, lo2, hi2);
}
/**
* A method designed to handle the base cases when calculating
* the median of two sorted arrays.
*/
private static double medianBaseCase(
double[] a, int lo1, int hi1,
double[] b, int lo2, int hi2) {
assert hi1 - lo1 <= 2 || hi2 - lo2 <= 2;
assert isSorted(a, lo1, hi1) && isSorted(b, lo2, hi2);
assert rangeCheck(a, lo1, hi1) && rangeCheck(a, lo1, hi1);
if (hi1 - lo1 > hi2 - lo2) {
// swap(a, b); swap(lo1, lo2); swap(hi1, hi2);
double[] arraySwap = a; a = b; b = arraySwap;
int swap = hi1; hi1 = hi2; hi2 = swap;
swap = lo1; lo1 = lo2; lo2 = swap;
}
int aLength = hi1 - lo1;
int bLength = hi2 - lo2;
if (aLength == 0 && bLength == 0) {
}
if (aLength == 2 && bLength == 2) {
return twoTwoMedian(a, lo1, hi1, b, lo2, hi2);
}
if (aLength == 1 && bLength == 1) {
return (a[lo1] + b[lo2]) / 2;
}
if (aLength == 1 && bLength == 2) {
return oneTwoMedian(a, lo1, hi1, b, lo2, hi2);
}
int mid = (lo2 + hi2) >>> 1;
if (aLength == 0) {
if (bLength % 2 == 0) {
return (b[mid - 1] + b[mid]) / 2;
} else {
return b[mid];
}
}
if (aLength == 1) {
// [1, 3, 5, 7] -> (insert 2, 4, 6)
// [1, 2*, 3, 5, 7], [1, 3, 4*, 5, 7] or [1, 3, 5, 6*, 7]
if (bLength % 2 == 0) {
if (a[lo1] < b[mid - 1]) {
return b[mid - 1];
} else if (b[mid - 1] < a[lo1] && a[lo1] < b[mid]) {
return a[lo1];
} else {
return b[mid];
}
// [1, 3, 5] -> (insert 0, 2, 4, 6)
// [0*, 1, 3, 5], [1, 2*, 3, 5],
// [1, 3, 4*, 5], [1, 3, 5, 6*]
} else {
if (a[lo1] < b[mid - 1]) {
return (b[mid - 1] + b[mid]) / 2;
} else if (b[mid - 1] < a[lo1] && a[lo1] < b[mid + 1]) {
return (b[mid] + a[lo1]) / 2;
} else {
return (b[mid] + b[mid + 1]) / 2;
}
}
}
if (aLength == 2) {
// [2, 5, 8, 11] -> (insert [0, 1], [3, 4], [6, 7]...)
// [0*, 1*, 2, 5, 8, 11], [2, 3*, 4*, 5, 8, 11]
// [2, 5, 6*, 7*, 8, 11], [2, 5, 8, 9*, 10*, 11]
// [2, 5, 8, 11, 12*, 13*]
if (bLength % 2 == 0) {
if (a[lo1 + 1] < b[mid - 2]) {
return (b[mid - 2] + b[mid - 1]) / 2;
} else if (b[mid + 1] < a[lo1]) {
return (b[mid] + b[mid + 1]) / 2;
} else {
return twoTwoMedian(a, lo1, hi1, b, mid - 1, mid + 1);
}
// [2, 5, 8] -> (insert [0, 1], [3, 4], [6, 7], [9, 10])
// [0*, 1*, 2, 5, 8], [2, 3*, 4*, 5, 8]
// [2, 5, 6*, 7*, 8], [2, 5, 8, 9*, 10*]
} else {
if (a[lo1 + 1] < b[mid - 1]) {
return b[mid - 1];
} else if (b[mid + 1] < a[lo1]) {
return b[mid + 1];
} else {
return oneTwoMedian(b, mid, mid + 1, a, lo1, hi1);
}
}
}
}
/**
* Returns the k-th largest element among two sorted arrays
* a and b. Runs in linear time.
*/
static double kthLargestLinear(double[] a, double[] b, int k) {
assert isSorted(a) && isSorted(b);
if (k < 0 || k >= a.length + b.length) {
"Got: len(a) = %d, len(b) = %d, k = %d",
a.length, b.length, k
));
}
int indexA = 0, indexB = 0;
for (int i = 0; i < k + 1; i++) {
if (indexB == b.length
|| indexA < a.length && a[indexA] < b[indexB]) {
last = a[indexA];
indexA++;
} else {
last = b[indexB];
indexB++;
}
}
return last;
}
/**
* Finds the k-th largest element among two sorted arrays.
* Runs in O(lgk) time.
*/
static double kthLargest(double[] a, double[] b, int k) {
assert isSorted(a) && isSorted(b);
if (k < 0 || k >= a.length + b.length) {
"Got: len(a) = %d, len(b) = %d, k = %d",
a.length, b.length, k
));
}
int lo1 = 0, hi1 = a.length;
int lo2 = 0, hi2 = b.length;
while (k >= 0) {
// in case one of the arrays is empty, return the k-th
// element of the non-empty array
if (lo1 == hi1) {
return b[lo2 + k];
}
if (lo2 == hi2) {
return a[lo1 + k];
}
// (at this point each array contains at least 1 element)
if (k == 0) {
return min(a[lo1], b[lo2]);
}
// keep the reference to the smaller array in the variable `a`
// for simplicity
if (hi1 - lo1 > hi2 - lo2) {
// swap(a, b); swap(lo1, lo2); swap(hi1, hi2);
double[] arraySwap = a; a = b; b = arraySwap;
int swap = lo1; lo1 = lo2; lo2 = swap;
swap = hi1; hi1 = hi2; hi2 = swap;
}
// if one of the arrays' length is <= k + 1 / 2, it might be
// the case that all the elements from this array are
// less than the k-th largest element of the two arrays
if (hi1 - lo1 <= (k + 1) / 2) {
if (a[hi1 - 1] < b[lo2 + k - (hi1 - lo1)]) {
return b[lo2 + k - (hi1 - lo1)];
} else {
lo2 += (k + 1) / 2;
k -= (k + 1) / 2;
}
} else {
if (a[lo1 + k / 2] == b[lo2 + k / 2]) {
return a[lo1 + k / 2];
}
if (a[lo1 + k / 2] > b[lo2 + k / 2]) {
// swap(a, b); swap(lo1, lo2); swap(hi1, hi2);
double[] arraySwap = a; a = b; b = arraySwap;
int swap = lo1; lo1 = lo2; lo2 = swap;
swap = hi1; hi1 = hi2; hi2 = swap;
}
lo1 += (k + 1) / 2;
k -= (k + 1) / 2;
}
}
}
private static double oneTwoMedian(
double[] a, int lo1, int hi1,
double[] b, int lo2, int hi2) {
assert hi1 - lo1 == 1 && hi2 - lo2 == 2;
// return a0 + b0 + b1 - min(a0, b0) - max(a0, b1);
// return max(a0, b0) + min(0, b1 - a0);
return max(a[lo1], b[lo2]) + min(0, b[lo2 + 1] - a[lo1]);
}
private static double twoTwoMedian(
double[] a, int lo1, int hi1,
double[] b, int lo2, int hi2) {
assert hi1 - lo1 == 2 && hi2 - lo2 == 2;
return (max(a[lo1], b[lo2]) + min(a[lo1 + 1], b[lo2 + 1])) / 2;
}
/**
* Checks if the array of doubles is sorted.
* Used solely for assertions tests.
*/
private static boolean isSorted(double[] a, int lo, int hi) {
assert rangeCheck(a, lo, hi)
: String.
format("len(a) = %d, lo = %d, hi = %d",
a.length, lo, hi);
for (int i = lo; i < hi - 1; i++) {
if (a[i] > a[i + 1]) {
return false;
}
}
return true;
}
private static boolean isSorted(double[] a) {
return isSorted(a, 0, a.length);
}
/**
* Checks if the specified interval belongs to the array.
* Returns false in case it does not, the interval is defined
* incorrectly (empty intervals are acceptable) or a == null.
*
* Used solely for assertions tests.
*/
private static boolean rangeCheck(double[] a, int lo, int hi) {
if (a == null) {
return false;
} else if (lo < 0 || lo >= a.length && lo != 0
|| hi < 0 || hi > a.length) {
return false;
} else if (lo > hi) {
return false;
}
return true;
}
public static void main
(String[] args
) { double[] a = { 0, 2, 4, 6, 8 };
double[] b = { 1, 3, 5, 7, 9 };
int k = 4;
System.
out.
println(medianTwoArraysLinear
(a, b
)); System.
out.
println(medianTwoArrays
(a, b
));
System.
out.
println(medianTwoDifferentSizeArraysLinear
(a, b
)); System.
out.
println(medianTwoDifferentSizeArrays
(a, b
));
System.
out.
println(kthLargestLinear
(a, b, k
)); System.
out.
println(kthLargest
(a, b, k
)); }
}
aW1wb3J0IHN0YXRpYyBqYXZhLmxhbmcuTWF0aC5tYXg7CmltcG9ydCBzdGF0aWMgamF2YS5sYW5nLk1hdGgubWluOwoKY2xhc3MgS3RoTGFyZ2VzdFR3b0FycmF5cyB7CiAgICAvKioKICAgICAqIEdpdmVuIHR3byBzb3J0ZWQgYXJyYXlzIG9mIGVxdWFsIHNpemVzLCBmaW5kcyB0aGUgbWVkaWFuIG9mIHRoZQogICAgICogYXJyYXkgdGhhdCBjb21lcyBvdXQgYWZ0ZXIgYGFgIGFuZCBgYmAgYmVpbmcgbWVyZ2VkLiBSdW5zIGluCiAgICAgKiBsaW5lYXIgdGltZSBhbmQgZG9lcyBub3QgcmVxdWlyZSBhbnkgZXh0cmEgc3BhY2UuCiAgICAgKgogICAgICogVGhlIGFsZ29yaXRobSBpcyBzaW1pbGFyIHRvIHRoZSBhcnJheXMgbWVyZ2luZywgYnV0IGl0CiAgICAgKiBkb2VzIG5vdCBzYXZlIHRoZSBtZXJnZWQgYXJyYXksIGl0IGp1c3QgaXRlcmF0ZXMgdGhyb3VnaCBib3RoCiAgICAgKiBvZiB0aGVtIGJ5IG4rMSBpdGVtcyAodGh1cyBzdG9wcGluZyBpbiB0aGUgbWlkZGxlIG9mIGFuIGltYWdpbmFyeQogICAgICogbWVyZ2VkIGFycmF5KSBhbmQgbWVtb3JpemVzIHR3byBjb25zZWN1dGl2ZSBlbGVtZW50cy4gVGhlc2UKICAgICAqIGFyZSB0aGUgdHdvIGVsZW1lbnRzIGxheWluZyBleGFjdGx5IGluIHRoZSBtaWRkbGUgb2YgbWVyZ2VkIGFycmF5LgogICAgICoKICAgICAqIChTaW5jZSB0aGUgbGVuZ3RoIG9mIHRoZSBtZXJnZWQgYXJyYXkgaXMgZXZlbiwgaXRzIG1lZGlhbgogICAgICogaXMgYW4gYXZlcmFnZSB2YWx1ZSBvZiB0d28gZWxlbWVudHMgaW4gdGhlIG1pZGRsZS4pCiAgICAgKgogICAgICogQHBhcmFtIGEgYSBzb3J0ZWQgYXJyYXkKICAgICAqIEBwYXJhbSBiIGEgc29ydGVkIGFycmF5CiAgICAgKi8KICAgIHN0YXRpYyBkb3VibGUgbWVkaWFuVHdvQXJyYXlzTGluZWFyKGRvdWJsZVtdIGEsIGRvdWJsZVtdIGIpIHsKICAgICAgICBpZiAoYS5sZW5ndGggIT0gYi5sZW5ndGgpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IElsbGVnYWxBcmd1bWVudEV4Y2VwdGlvbihTdHJpbmcuZm9ybWF0KAogICAgICAgICAgICAgICAgIkV4cGVjdGVkOiBsZW4oYSkgPT0gbGVuKGIpLiIKICAgICAgICAgICAgICAgICsgIiBHb3Q6IGxlbihhKSA9ICVkLCBsZW4oYikgPSAlZCIsCiAgICAgICAgICAgICAgICBhLmxlbmd0aCwgYi5sZW5ndGgKICAgICAgICAgICAgKSk7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIGZpbmFsIGludCBuID0gYS5sZW5ndGg7CiAgICAgICAgaW50IGkgPSAwLCBqID0gMDsKICAgICAgICAvLyB0d28gY29uc2VjdXRpdmUgZWxlbWVudHMgb2YgdGhlIG1lcmdlZCBhcnJheQogICAgICAgIGRvdWJsZSBtaWQxID0gRG91YmxlLk5hTiwgbWlkMiA9IERvdWJsZS5OYU47CiAgICAgICAgZm9yIChpbnQgayA9IDA7IGsgPCBuICsgMTsgaysrKSB7CiAgICAgICAgICAgIC8vIGhlcmUgd2UgYWxzbyBoYW5kbGUgYSBzcGVjaWFsIGNhc2Ugd2hlbiBldmVyeSBlbGVtZW50CiAgICAgICAgICAgIC8vIG9mIHRoZSBmaXJzdCBhcnJheSBpcyBzbWFsbGVyIHRoYW4gdGhlIHNtYWxsZXN0IGVsZW1lbnQKICAgICAgICAgICAgLy8gb2YgdGhlIHNlY29uZCBhcnJheSAoYW5kIHZpY2UgdmVyc2EpCiAgICAgICAgICAgIGlmIChqID09IG4gfHwgaSA8IG4gJiYgYVtpXSA8IGJbal0pIHsKICAgICAgICAgICAgICAgIC8vIHB1dCB0aGUgcHJldmlvdXMgdmFsdWUgaW50byB0aGUgYnVmZmVyCiAgICAgICAgICAgICAgICBtaWQxID0gbWlkMjsKICAgICAgICAgICAgICAgIG1pZDIgPSBhW2ldOwogICAgICAgICAgICAgICAgaSsrOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgbWlkMSA9IG1pZDI7CiAgICAgICAgICAgICAgICBtaWQyID0gYltqXTsKICAgICAgICAgICAgICAgIGorKzsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gKG1pZDEgKyBtaWQyKSAvIDI7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogQSBsb2dhcml0aG1pYy10aW1lIGFsZ29yaXRobSB0aGF0IHNvbHZlcyB0aGUgc2FtZSBwcm9ibGVtLgogICAgICogVGhlIGJhc2ljIGlkZWEgaXMgdG8gY29tcHV0ZSB0aGUgbWVkaWFucyBvZiBib3RoIG9mIHRoZQogICAgICogYXJyYXlzICh3ZWxsLCB0aGVzZSBhcmUgbm90IGV4YWN0bHkgIm1lZGlhbnMiLCBpbiBjYXNlIHRoZQogICAgICogYXJyYXkgbGVuZ3RoIGlzIGV2ZW4sIG1pZCA9IEFbbiAvIDJdLCBub3QgdGhlIGF2ZXJhZ2UgdmFsdWUpOgogICAgICogICAgIEEgPSBbYTEsIGEyLCAuLi4sIG1pZDEsIC4uLiwgYW5dIAogICAgICogICAgIEIgPSBbYjEsIGIyLCAuLi4sIG1pZDIsIC4uLiwgYm5dCiAgICAgKiBhbmQgYWZ0ZXIgdGhhdCB0aGVyZSBhcmUgdGhyZWUgY2FzZXMgdG8gY29uc2lkZXI6CiAgICAgKgogICAgICogIC0gbWlkMSA9PSBtaWQyLCB3aGljaCBtZWFucyAoZ2l2ZW4gbGVuKEEpID09IGxlbihCKSkgdGhhdAogICAgICogICAgaW4gZXZlcnkgYXJyYXkgdGhlcmUgYXJlIG4vMiBlbGVtZXRzIG9uIHRoZSBsZWZ0IHNpZGUKICAgICAqICAgIGZyb20gdGhlIG1pZCwgc28gaW4gdGhlIG1lcmdlZCBhcnJheSBtaWQxIGFuZCBtaWQyIHdvdWxkCiAgICAgKiAgICBiZSBvbiBuLzIgKyBuLzIgPSBuIGFuZCBuKzEgcG9zaXRpb25zICh0aHVzIG1pZDEgaXMgdGhlCiAgICAgKiAgICBtZWRpYW4gb2YgdGhlIG1lcmdlZCBhcnJheSkKICAgICAqCiAgICAgKiAgLSBtaWQxICZsdDsgbWlkMiBtZWFucyB0aGF0IHRoZSBncmVhdGVzdCBlbGVtZW50IG9mIHRoZSBsZWZ0CiAgICAgKiAgICBzaWRlIG9mIHRoZSBhcnJheSBBIChBX2xlZnQpIGlzIGF0IG1vc3QgYXMgbGFyZ2UgYXMgdGhlCiAgICAgKiAgICBncmVhdGVzdCBlbGVtZW50IG9mIEJfbGVmdC4gQW5kIHNpbWlsYXJseSB0aGUgc21hbGxlc3QKICAgICAqICAgIGVsZW1lbnQgb2YgQl9yaWdodCBpcyBhdCBsZWFzdCBhcyBsYXJnZSBhcyB0aGUgc21hbGxlc3QKICAgICAqICAgIGVsZW1lbnQgb2YgQV9yaWdodC4KICAgICAqCiAgICAgKiAgICBUaGlzIG1lYW5zIHRoYXQgdGhlIGxlZnQgc2lkZSBvZiB0aGUgaW1hZ2luYXJ5IG1lcmdlZCBhcnJheQogICAgICogICAgZm9yIHN1cmUgd291bGQgbm90IGVuZCB3aXRoIGFuIGVsZW1lbnQgZnJvbSBBX2xlZnQsIGFuZAogICAgICogICAgdGhlIHJpZ2h0IHNpZGUgd2lsbCBub3Qgc3RhcnQgd2l0aCBhbiB2YWx1ZSBmcm9tIEJfcmlnaHQuCiAgICAgKiAgICAoSXQgY2FuIGJlIGVhc2lseSBzZWVuIGZyb20gdGhlIGV4YW1wbGUgZG93biBiZWxvdywganVzdAogICAgICogICAgZm9sbG93IHRoZSBzdGVwcyBvZiB0aGUgbWVyZ2UgYWxnb3JpdGhtLikKICAgICAqCiAgICAgKiAgICBUaHVzIHRoZSBkZXNpcmVkIG1lZGlhbiBlbGVtZW50cyBhcmUgc29tZXdoZXJlIGluCiAgICAgKiAgICBBX3JpZ2h0IG9yIEJfbGVmdC4gV2hlbiBjb21wdXRpbmcgdGhlIG1lZGlhbiB3ZSBjYW4gZ2V0IHJpZAogICAgICogICAgb2YgdGhlIHNhbWUgYW1vdW50IG9mIGVsZW1lbnRzIG9uIHRoZSByaWdodCBhcyBvbiB0aGUgbGVmdCBzaWRlCiAgICAgKiAgICBhbmQgdGhlIHJlc3VsdCB3aWxsIG5vdCBjaGFuZ2UgaW4gY2FzZSB0aGUgZWxlbWVudHMgb24gdGhlIGxlZnQKICAgICAqICAgIGFyZSBzbWFsbGVyIHRoYW4gdGhlIG1lZGlhbiwgbWVhbndoaWxlIGVsZW1lbnRzIG9uIHRoZSByaWdodAogICAgICogICAgYXJlIGdyZWF0ZXIuIFNvIHdlIGNhbiBkbyBoZXJlOiBBX2xlZnQgYW5kIEJfcmlnaHQgY2FuIGJlCiAgICAgKiAgICB0aHJvd24gYXdheSBsZWF2aW5nIHVzIHdpdGgganVzdCBBX3JpZ2h0IGFuZCBCX2xlZnQgLQogICAgICogICAgbm93IHdlIGhhdmUgdGhlIHNhbWUgcHJvYmxlbSBidXQgb2YgaGFsZiBvZiB0aGUgc2l6ZS4KICAgICAqCiAgICAgKiAgICBFeGFtcGxlOgogICAgICogICAgYSA9IFsgMSwgMiwgMywgNCwgOCBdCiAgICAgKiAgICBiID0gWyAwLCAzLCA0LCA1LCA2IF0KICAgICAqICAgIE1lcmdlZDogWyAwLCAxKiwgMiosIDMsIDMqIHwgNCwgNCosIDUsIDYsIDgqIF0KICAgICAqICAgIChlbGVtZW50cyBmcm9tIHRoZSBmaXJzdCBhcnJheSBhcmUgbWFya2VkIHdpdGggYXN0ZXJpc2tzKQogICAgICoKICAgICAqICAtIG1pZDEgJmd0OyBtaWQyIGNhc2UgaXMgaGFuZGxlZCBzaW1pbGFybHkuICAqLyAKICAgIHN0YXRpYyBkb3VibGUgbWVkaWFuVHdvQXJyYXlzKGRvdWJsZVtdIGEsIGRvdWJsZVtdIGIpIHsKICAgICAgICBpZiAoYS5sZW5ndGggIT0gYi5sZW5ndGgpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IElsbGVnYWxBcmd1bWVudEV4Y2VwdGlvbihTdHJpbmcuZm9ybWF0KAogICAgICAgICAgICAgICAgIkV4cGVjdGVkOiBsZW4oYSkgPT0gbGVuKGIpLiIKICAgICAgICAgICAgICAgICsgIkdvdDogbGVuKGEpID0gJWQsIGxlbihiKSA9ICVkIiwKICAgICAgICAgICAgICAgIGEubGVuZ3RoLCBiLmxlbmd0aAogICAgICAgICAgICApKTsKICAgICAgICB9IAogICAgICAgIGZpbmFsIGludCBuID0gYS5sZW5ndGg7CiAgICAgICAgaW50IGxvMSA9IDAsIGhpMSA9IG47IC8vIGxlZnQgc3ViYXJyYXkKICAgICAgICBpbnQgbG8yID0gMCwgaGkyID0gbjsgLy8gcmlnaHQgc3ViYXJyYXkKCiAgICAgICAgd2hpbGUgKGhpMSAtIGxvMSA+IDIpIHsKICAgICAgICAgICAgZG91YmxlIG1pZDEgPSBhW2xvMSArIGhpMSAtIDEgPj4+IDFdOwogICAgICAgICAgICBkb3VibGUgbWlkMiA9IGJbbG8yICsgaGkyIC0gMSA+Pj4gMV07CgogICAgICAgICAgICBpZiAobWlkMSA+IG1pZDIpIHsKICAgICAgICAgICAgICAgIC8vIHN3YXAoYSwgYik7IHN3YXAobG8xLCBsbzIpOyBzd2FwKGhpMSwgaGkyKTsKICAgICAgICAgICAgICAgIGRvdWJsZVtdIGFycmF5U3dhcCA9IGE7IGEgPSBiOyBiID0gYXJyYXlTd2FwOwogICAgICAgICAgICAgICAgaW50IHN3YXAgPSBsbzE7IGxvMSA9IGxvMjsgbG8yID0gc3dhcDsKICAgICAgICAgICAgICAgIHN3YXAgPSBoaTE7IGhpMSA9IGhpMjsgaGkyID0gc3dhcDsKICAgICAgICAgICAgfSBlbHNlIGlmIChhW2xvMSArIGhpMSA+Pj4gMV0gPT0gYltsbzIgKyBoaTIgLSAxID4+PiAxXSkgewogICAgICAgICAgICAgICAgcmV0dXJuIGFbbG8xICsgaGkxID4+PiAxXTsKICAgICAgICAgICAgfSBlbHNlIGlmIChhW2xvMSArIGhpMSAtIDEgPj4+IDFdID09IGJbbG8yICsgaGkyID4+PiAxXSkgewogICAgICAgICAgICAgICAgcmV0dXJuIGFbbG8xICsgaGkxID4+PiAxXTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpbnQgY3V0TGVuZ3RoID0gaGkxIC0gbG8xIC0gMSA+Pj4gMTsKICAgICAgICAgICAgbG8xICs9IGN1dExlbmd0aDsKICAgICAgICAgICAgaGkyIC09IGN1dExlbmd0aDsKICAgICAgICB9CgogICAgICAgIGlmIChoaTEgLSBsbzEgPT0gMSkgewogICAgICAgICAgICByZXR1cm4gKGFbbG8xXSArIGJbbG8yXSkgLyAyOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIGFzc2VydCBoaTEgLSBsbzEgPT0gMjsKICAgICAgICAgICAgLy8gW2EwLCBhMV0gW2IwLCBiMV0gY2FzZQogICAgICAgICAgICAvLyBwb3NzaWJsZSBtZXJnZWQgYXJyYXlzOgogICAgICAgICAgICAvLyAgIGEwIDwgYjAKICAgICAgICAgICAgLy8gICBbYTAsIGExLCBiMCwgYjFdIG1pZCA9IGF2ZyhhMSwgYjApIC0tIGExIDwgYjAgPCBiMQogICAgICAgICAgICAvLyAgIFthMCwgYjAsIGExLCBiMV0gbWlkID0gYXZnKGExLCBiMCkgLS0gYTEgPCBiMQogICAgICAgICAgICAvLyAgIFthMCwgYjAsIGIxLCBhMV0gbWlkID0gYXZnKGIxLCBiMCkgLS0gYTEgPiBiMQogICAgICAgICAgICAvLyAgIAogICAgICAgICAgICAvLyAgIGEwID4gYjAKICAgICAgICAgICAgLy8gICBbYjAsIGEwLCBiMSwgYTFdIG1pZCA9IGF2ZyhhMCwgYjEpIC0tIGExID4gYjEKICAgICAgICAgICAgLy8gICBbYjAsIGEwLCBhMSwgYjFdIG1pZCA9IGF2ZyhhMCwgYTEpIC0tIGExIDwgYjEKICAgICAgICAgICAgLy8gICBbYjAsIGIxLCBhMCwgYTFdIG1pZCA9IGF2ZyhhMCwgYjEpIC0tIGExID4gYTAgPiBiMQogICAgICAgICAgICByZXR1cm4gKG1heChhW2xvMV0sIGJbbG8yXSkKICAgICAgICAgICAgICAgICAgICArIG1pbihhW2xvMSArIDFdLCBiW2xvMiArIDFdKSkgLyAyOwogICAgICAgIH0KICAgIH0KCiAgICAvKioKICAgICAqIEEgbGluZWFyIHNvbHV0aW9uIG9mIHRoZSBzYW1lIHByb2JsZW0gYnV0IG5vdyB3aXRoCiAgICAgKiBub3QgbmVjZXNzZXJpbHkgZXF1YWwtbGVuZ3RoIHNvcnRlZCBhcnJheXMuCiAgICAgKiBAcGFyYW0gYSBhIHNvcnRlZCBhcnJheQogICAgICogQHBhcmFtIGIgYSBzb3J0ZWQgYXJyYXkKICAgICAqLwogICAgc3RhdGljIGRvdWJsZSBtZWRpYW5Ud29EaWZmZXJlbnRTaXplQXJyYXlzTGluZWFyKGRvdWJsZVtdIGEsCiAgICAgICAgICAgIGRvdWJsZVtdIGIpIHsKICAgICAgICBhc3NlcnQgaXNTb3J0ZWQoYSkgJiYgaXNTb3J0ZWQoYik7CiAgICAgICAgCiAgICAgICAgLy8gaWYgbiA6PSBsZW4oYSkgKyBsZW4oYikgaXMgZXZlbiwgdGhlbiB0aGUgbWVkaWFuIG9mIHRoZQogICAgICAgIC8vIG1lcmdlZCBhcnJheSBlcXVhbHMgdG8gYXZnKG1yZ2RbbWlkIC0gMV0sIG1yZ2RbbWlkXSkKICAgICAgICAvLwogICAgICAgIC8vIG90aGVyd2lzZSB0aGUgbWVkaWFuIGlzIGp1c3QgbXJnZFttaWRdCiAgICAgICAgZmluYWwgaW50IG4gPSBhLmxlbmd0aCArIGIubGVuZ3RoOwogICAgICAgIGludCBtaWQgPSBuID4+PiAxOwogICAgICAgIGRvdWJsZSBtZWRpYW4xID0gRG91YmxlLk5hTiwgbWVkaWFuMiA9IERvdWJsZS5OYU47CiAgICAgICAgLy8gYSBhbmQgYiBpdGVyYXRvcnMgcmVzcGVjdGl2ZWx5CiAgICAgICAgaW50IGkgPSAwLCBqID0gMDsKCiAgICAgICAgZm9yIChpbnQgayA9IDA7IGsgPCBtaWQgKyAxOyBrKyspIHsKICAgICAgICAgICAgbWVkaWFuMSA9IG1lZGlhbjI7CiAgICAgICAgICAgIGlmIChqID09IGIubGVuZ3RoIHx8IGkgPCBhLmxlbmd0aCAmJiBhW2ldIDwgYltqXSkgewogICAgICAgICAgICAgICAgbWVkaWFuMiA9IGFbaV07CiAgICAgICAgICAgICAgICBpKys7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBtZWRpYW4yID0gYltqXTsKICAgICAgICAgICAgICAgIGorKzsKICAgICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgaWYgKG4gJSAyID09IDApIHsKICAgICAgICAgICAgcmV0dXJuIChtZWRpYW4xICsgbWVkaWFuMikgLyAyOwogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHJldHVybiBtZWRpYW4yOwogICAgICAgIH0KICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBDb21wdXRlcyB0aGUgbWVkaWFuIG9mIHR3byBzb3J0ZWQgbm90IG5lY2Vzc2FyaWx5IGVxdWFsCiAgICAgKiBsZW5ndGggYXJyYXlzLiBSdW5zIGluIGxvZ2FyaXRobWljIHRpbWUgYW5kIGRvZXMgbm90CiAgICAgKiByZXF1aXJlIGFueSBleHRyYSBzcGFjZS4KICAgICAqLwogICAgc3RhdGljIGRvdWJsZSBtZWRpYW5Ud29EaWZmZXJlbnRTaXplQXJyYXlzKGRvdWJsZVtdIGEsIGRvdWJsZVtdIGIpIHsKICAgICAgICBhc3NlcnQgaXNTb3J0ZWQoYSkgJiYgaXNTb3J0ZWQoYik7CgogICAgICAgIGludCBsbzEgPSAwLCBoaTEgPSBhLmxlbmd0aDsKICAgICAgICBpbnQgbG8yID0gMCwgaGkyID0gYi5sZW5ndGg7CgogICAgICAgIHdoaWxlIChoaTEgLSBsbzEgPiAyICYmIGhpMiAtIGxvMiA+IDIpIHsKICAgICAgICAgICAgZG91YmxlIG1lZGlhbjEgPSBhW2xvMSArIGhpMSAtIDEgPj4+IDFdOwogICAgICAgICAgICBkb3VibGUgbWVkaWFuMiA9IGJbbG8yICsgaGkyIC0gMSA+Pj4gMV07CgogICAgICAgICAgICBpZiAobWVkaWFuMSA+IG1lZGlhbjIpIHsKICAgICAgICAgICAgICAgIC8vIHN3YXAoYSwgYik7IHN3YXAobG8xLCBsbzIpOyBzd2FwKGhpMSwgaGkyKTsKICAgICAgICAgICAgICAgIGRvdWJsZVtdIGFycmF5U3dhcCA9IGE7IGEgPSBiOyBiID0gYXJyYXlTd2FwOwogICAgICAgICAgICAgICAgaW50IHN3YXAgPSBsbzE7IGxvMSA9IGxvMjsgbG8yID0gc3dhcDsKICAgICAgICAgICAgICAgIHN3YXAgPSBoaTE7IGhpMSA9IGhpMjsgaGkyID0gc3dhcDsKICAgICAgICAgICAgfSBlbHNlIGlmIChhW2xvMSArIGhpMSA+Pj4gMV0gPT0gYltsbzIgKyBoaTIgLSAxID4+PiAxXSkgewogICAgICAgICAgICAgICAgcmV0dXJuIGFbbG8xICsgaGkxID4+PiAxXTsKICAgICAgICAgICAgfSBlbHNlIGlmIChhW2xvMSArIGhpMSAtIDEgPj4+IDFdID09IGJbbG8yICsgaGkyID4+PiAxXSkgewogICAgICAgICAgICAgICAgcmV0dXJuIGFbbG8xICsgaGkxIC0gMSA+Pj4gMV07CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gLTEgdG8gY3V0IFthMCwgYTEsIGEyLCBhM10gdG8gW2ExLCBhMiwgYTNdCiAgICAgICAgICAgIC8vIG5vdCB0byBqdXN0IFthMiwgYTNdCiAgICAgICAgICAgIGludCBjdXRMZW5ndGggPSBtaW4oKGhpMSAtIGxvMSAtIDEpID4+PiAxLAogICAgICAgICAgICAgICAgICAgIChoaTIgLSBsbzIgLSAxKSA+Pj4gMSk7CiAgICAgICAgICAgIGxvMSArPSBjdXRMZW5ndGg7CiAgICAgICAgICAgIGhpMiAtPSBjdXRMZW5ndGg7CiAgICAgICAgfQogICAgICAgIHJldHVybiBtZWRpYW5CYXNlQ2FzZShhLCBsbzEsIGhpMSwgYiwgbG8yLCBoaTIpOwogICAgfQogICAgCiAgICAvKioKICAgICAqIEEgbWV0aG9kIGRlc2lnbmVkIHRvIGhhbmRsZSB0aGUgYmFzZSBjYXNlcyB3aGVuIGNhbGN1bGF0aW5nCiAgICAgKiB0aGUgbWVkaWFuIG9mIHR3byBzb3J0ZWQgYXJyYXlzLgogICAgICovCiAgICBwcml2YXRlIHN0YXRpYyBkb3VibGUgbWVkaWFuQmFzZUNhc2UoCiAgICAgICAgICAgIGRvdWJsZVtdIGEsIGludCBsbzEsIGludCBoaTEsCiAgICAgICAgICAgIGRvdWJsZVtdIGIsIGludCBsbzIsIGludCBoaTIpIHsKICAgICAgICBhc3NlcnQgaGkxIC0gbG8xIDw9IDIgfHwgaGkyIC0gbG8yIDw9IDI7CiAgICAgICAgYXNzZXJ0IGlzU29ydGVkKGEsIGxvMSwgaGkxKSAmJiBpc1NvcnRlZChiLCBsbzIsIGhpMik7CiAgICAgICAgYXNzZXJ0IHJhbmdlQ2hlY2soYSwgbG8xLCBoaTEpICYmIHJhbmdlQ2hlY2soYSwgbG8xLCBoaTEpOwogICAgICAgIAogICAgICAgIGlmIChoaTEgLSBsbzEgPiBoaTIgLSBsbzIpIHsKICAgICAgICAgICAgLy8gc3dhcChhLCBiKTsgc3dhcChsbzEsIGxvMik7IHN3YXAoaGkxLCBoaTIpOwogICAgICAgICAgICBkb3VibGVbXSBhcnJheVN3YXAgPSBhOyBhID0gYjsgYiA9IGFycmF5U3dhcDsKICAgICAgICAgICAgaW50IHN3YXAgPSBoaTE7IGhpMSA9IGhpMjsgaGkyID0gc3dhcDsKICAgICAgICAgICAgc3dhcCA9IGxvMTsgbG8xID0gbG8yOyBsbzIgPSBzd2FwOwogICAgICAgIH0KICAgICAgICAKICAgICAgICBpbnQgYUxlbmd0aCA9IGhpMSAtIGxvMTsKICAgICAgICBpbnQgYkxlbmd0aCA9IGhpMiAtIGxvMjsKCiAgICAgICAgaWYgKGFMZW5ndGggPT0gMCAmJiBiTGVuZ3RoID09IDApIHsKICAgICAgICAgICAgcmV0dXJuIERvdWJsZS5OYU47CiAgICAgICAgfQogICAgICAgIGlmIChhTGVuZ3RoID09IDIgJiYgYkxlbmd0aCA9PSAyKSB7CiAgICAgICAgICAgIHJldHVybiB0d29Ud29NZWRpYW4oYSwgbG8xLCBoaTEsIGIsIGxvMiwgaGkyKTsKICAgICAgICB9CiAgICAgICAgaWYgKGFMZW5ndGggPT0gMSAmJiBiTGVuZ3RoID09IDEpIHsKICAgICAgICAgICAgcmV0dXJuIChhW2xvMV0gKyBiW2xvMl0pIC8gMjsKICAgICAgICB9CiAgICAgICAgaWYgKGFMZW5ndGggPT0gMSAmJiBiTGVuZ3RoID09IDIpIHsKICAgICAgICAgICAgcmV0dXJuIG9uZVR3b01lZGlhbihhLCBsbzEsIGhpMSwgYiwgbG8yLCBoaTIpOwogICAgICAgIH0KICAgICAgICAKICAgICAgICBpbnQgbWlkID0gKGxvMiArIGhpMikgPj4+IDE7CiAgICAgICAgaWYgKGFMZW5ndGggPT0gMCkgewogICAgICAgICAgICBpZiAoYkxlbmd0aCAlIDIgPT0gMCkgewogICAgICAgICAgICAgICAgcmV0dXJuIChiW21pZCAtIDFdICsgYlttaWRdKSAvIDI7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICByZXR1cm4gYlttaWRdOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGlmIChhTGVuZ3RoID09IDEpIHsKICAgICAgICAgICAgLy8gWzEsIDMsIDUsIDddIC0+IChpbnNlcnQgMiwgNCwgNikKICAgICAgICAgICAgLy8gWzEsIDIqLCAzLCA1LCA3XSwgWzEsIDMsIDQqLCA1LCA3XSBvciBbMSwgMywgNSwgNiosIDddCiAgICAgICAgICAgIGlmIChiTGVuZ3RoICUgMiA9PSAwKSB7CiAgICAgICAgICAgICAgICBpZiAoYVtsbzFdIDwgYlttaWQgLSAxXSkgewogICAgICAgICAgICAgICAgICAgIHJldHVybiBiW21pZCAtIDFdOwogICAgICAgICAgICAgICAgfSBlbHNlIGlmIChiW21pZCAtIDFdIDwgYVtsbzFdICYmIGFbbG8xXSA8IGJbbWlkXSkgewogICAgICAgICAgICAgICAgICAgIHJldHVybiBhW2xvMV07CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIHJldHVybiBiW21pZF07CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIC8vIFsxLCAzLCA1XSAtPiAoaW5zZXJ0IDAsIDIsIDQsIDYpCiAgICAgICAgICAgIC8vIFswKiwgMSwgMywgNV0sIFsxLCAyKiwgMywgNV0sCiAgICAgICAgICAgIC8vIFsxLCAzLCA0KiwgNV0sIFsxLCAzLCA1LCA2Kl0KICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIGlmIChhW2xvMV0gPCBiW21pZCAtIDFdKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChiW21pZCAtIDFdICsgYlttaWRdKSAvIDI7CiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGJbbWlkIC0gMV0gPCBhW2xvMV0gJiYgYVtsbzFdIDwgYlttaWQgKyAxXSkgewogICAgICAgICAgICAgICAgICAgIHJldHVybiAoYlttaWRdICsgYVtsbzFdKSAvIDI7CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIHJldHVybiAoYlttaWRdICsgYlttaWQgKyAxXSkgLyAyOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGlmIChhTGVuZ3RoID09IDIpIHsKICAgICAgICAgICAgLy8gWzIsIDUsIDgsIDExXSAtPiAoaW5zZXJ0IFswLCAxXSwgWzMsIDRdLCBbNiwgN10uLi4pCiAgICAgICAgICAgIC8vIFswKiwgMSosIDIsIDUsIDgsIDExXSwgWzIsIDMqLCA0KiwgNSwgOCwgMTFdCiAgICAgICAgICAgIC8vIFsyLCA1LCA2KiwgNyosIDgsIDExXSwgWzIsIDUsIDgsIDkqLCAxMCosIDExXQogICAgICAgICAgICAvLyBbMiwgNSwgOCwgMTEsIDEyKiwgMTMqXQogICAgICAgICAgICBpZiAoYkxlbmd0aCAlIDIgPT0gMCkgewogICAgICAgICAgICAgICAgaWYgKGFbbG8xICsgMV0gPCBiW21pZCAtIDJdKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChiW21pZCAtIDJdICsgYlttaWQgLSAxXSkgLyAyOwogICAgICAgICAgICAgICAgfSBlbHNlIGlmIChiW21pZCArIDFdIDwgYVtsbzFdKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChiW21pZF0gKyBiW21pZCArIDFdKSAvIDI7CiAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgIHJldHVybiB0d29Ud29NZWRpYW4oYSwgbG8xLCBoaTEsIGIsIG1pZCAtIDEsIG1pZCArIDEpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAvLyBbMiwgNSwgOF0gLT4gKGluc2VydCBbMCwgMV0sIFszLCA0XSwgWzYsIDddLCBbOSwgMTBdKQogICAgICAgICAgICAvLyBbMCosIDEqLCAyLCA1LCA4XSwgWzIsIDMqLCA0KiwgNSwgOF0KICAgICAgICAgICAgLy8gWzIsIDUsIDYqLCA3KiwgOF0sIFsyLCA1LCA4LCA5KiwgMTAqXQogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgaWYgKGFbbG8xICsgMV0gPCBiW21pZCAtIDFdKSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGJbbWlkIC0gMV07CiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGJbbWlkICsgMV0gPCBhW2xvMV0pIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gYlttaWQgKyAxXTsKICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9uZVR3b01lZGlhbihiLCBtaWQsIG1pZCArIDEsIGEsIGxvMSwgaGkxKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gRG91YmxlLk5hTjsKICAgIH0KICAgIAogICAgLyoqCiAgICAgKiBSZXR1cm5zIHRoZSBrLXRoIGxhcmdlc3QgZWxlbWVudCBhbW9uZyB0d28gc29ydGVkIGFycmF5cwogICAgICogYSBhbmQgYi4gUnVucyBpbiBsaW5lYXIgdGltZS4KICAgICAqLwogICAgc3RhdGljIGRvdWJsZSBrdGhMYXJnZXN0TGluZWFyKGRvdWJsZVtdIGEsIGRvdWJsZVtdIGIsIGludCBrKSB7CiAgICAgICAgYXNzZXJ0IGlzU29ydGVkKGEpICYmIGlzU29ydGVkKGIpOwoKICAgICAgICBpZiAoayA8IDAgfHwgayA+PSBhLmxlbmd0aCArIGIubGVuZ3RoKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBJbmRleE91dE9mQm91bmRzRXhjZXB0aW9uKFN0cmluZy5mb3JtYXQoCiAgICAgICAgICAgICAgICAiR290OiBsZW4oYSkgPSAlZCwgbGVuKGIpID0gJWQsIGsgPSAlZCIsCiAgICAgICAgICAgICAgICBhLmxlbmd0aCwgYi5sZW5ndGgsIGsKICAgICAgICAgICAgKSk7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIGRvdWJsZSBsYXN0ID0gRG91YmxlLk5hTjsKICAgICAgICBpbnQgaW5kZXhBID0gMCwgaW5kZXhCID0gMDsKICAgICAgICBmb3IgKGludCBpID0gMDsgaSA8IGsgKyAxOyBpKyspIHsKICAgICAgICAgICAgaWYgKGluZGV4QiA9PSBiLmxlbmd0aAogICAgICAgICAgICAgICAgICAgIHx8IGluZGV4QSA8IGEubGVuZ3RoICYmIGFbaW5kZXhBXSA8IGJbaW5kZXhCXSkgewogICAgICAgICAgICAgICAgbGFzdCA9IGFbaW5kZXhBXTsKICAgICAgICAgICAgICAgIGluZGV4QSsrOwogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgbGFzdCA9IGJbaW5kZXhCXTsKICAgICAgICAgICAgICAgIGluZGV4QisrOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiBsYXN0OwogICAgfQogICAgCiAgICAvKioKICAgICAqIEZpbmRzIHRoZSBrLXRoIGxhcmdlc3QgZWxlbWVudCBhbW9uZyB0d28gc29ydGVkIGFycmF5cy4KICAgICAqIFJ1bnMgaW4gTyhsZ2spIHRpbWUuCiAgICAgKi8KICAgIHN0YXRpYyBkb3VibGUga3RoTGFyZ2VzdChkb3VibGVbXSBhLCBkb3VibGVbXSBiLCBpbnQgaykgewogICAgICAgIGFzc2VydCBpc1NvcnRlZChhKSAmJiBpc1NvcnRlZChiKTsKCiAgICAgICAgaWYgKGsgPCAwIHx8IGsgPj0gYS5sZW5ndGggKyBiLmxlbmd0aCkgewogICAgICAgICAgICB0aHJvdyBuZXcgSW5kZXhPdXRPZkJvdW5kc0V4Y2VwdGlvbihTdHJpbmcuZm9ybWF0KAogICAgICAgICAgICAgICAgIkdvdDogbGVuKGEpID0gJWQsIGxlbihiKSA9ICVkLCBrID0gJWQiLAogICAgICAgICAgICAgICAgYS5sZW5ndGgsIGIubGVuZ3RoLCBrCiAgICAgICAgICAgICkpOwogICAgICAgIH0KCiAgICAgICAgaW50IGxvMSA9IDAsIGhpMSA9IGEubGVuZ3RoOwogICAgICAgIGludCBsbzIgPSAwLCBoaTIgPSBiLmxlbmd0aDsKCiAgICAgICAgd2hpbGUgKGsgPj0gMCkgewogICAgICAgICAgICAvLyBpbiBjYXNlIG9uZSBvZiB0aGUgYXJyYXlzIGlzIGVtcHR5LCByZXR1cm4gdGhlIGstdGgKICAgICAgICAgICAgLy8gZWxlbWVudCBvZiB0aGUgbm9uLWVtcHR5IGFycmF5CiAgICAgICAgICAgIGlmIChsbzEgPT0gaGkxKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gYltsbzIgKyBrXTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAobG8yID09IGhpMikgewogICAgICAgICAgICAgICAgcmV0dXJuIGFbbG8xICsga107CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gKGF0IHRoaXMgcG9pbnQgZWFjaCBhcnJheSBjb250YWlucyBhdCBsZWFzdCAxIGVsZW1lbnQpCiAgICAgICAgICAgIGlmIChrID09IDApIHsKICAgICAgICAgICAgICAgIHJldHVybiBtaW4oYVtsbzFdLCBiW2xvMl0pOwogICAgICAgICAgICB9CiAgICAgICAgICAgIC8vIGtlZXAgdGhlIHJlZmVyZW5jZSB0byB0aGUgc21hbGxlciBhcnJheSBpbiB0aGUgdmFyaWFibGUgYGFgCiAgICAgICAgICAgIC8vIGZvciBzaW1wbGljaXR5CiAgICAgICAgICAgIGlmIChoaTEgLSBsbzEgPiBoaTIgLSBsbzIpIHsKICAgICAgICAgICAgICAgIC8vIHN3YXAoYSwgYik7IHN3YXAobG8xLCBsbzIpOyBzd2FwKGhpMSwgaGkyKTsKICAgICAgICAgICAgICAgIGRvdWJsZVtdIGFycmF5U3dhcCA9IGE7IGEgPSBiOyBiID0gYXJyYXlTd2FwOwogICAgICAgICAgICAgICAgaW50IHN3YXAgPSBsbzE7IGxvMSA9IGxvMjsgbG8yID0gc3dhcDsKICAgICAgICAgICAgICAgIHN3YXAgPSBoaTE7IGhpMSA9IGhpMjsgaGkyID0gc3dhcDsKICAgICAgICAgICAgfQogICAgICAgICAgICAvLyBpZiBvbmUgb2YgdGhlIGFycmF5cycgbGVuZ3RoIGlzIDw9IGsgKyAxIC8gMiwgaXQgbWlnaHQgYmUKICAgICAgICAgICAgLy8gdGhlIGNhc2UgdGhhdCBhbGwgdGhlIGVsZW1lbnRzIGZyb20gdGhpcyBhcnJheSBhcmUKICAgICAgICAgICAgLy8gbGVzcyB0aGFuIHRoZSBrLXRoIGxhcmdlc3QgZWxlbWVudCBvZiB0aGUgdHdvIGFycmF5cwogICAgICAgICAgICBpZiAoaGkxIC0gbG8xIDw9IChrICsgMSkgLyAyKSB7CiAgICAgICAgICAgICAgICBpZiAoYVtoaTEgLSAxXSA8IGJbbG8yICsgayAgLSAoaGkxIC0gbG8xKV0pIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gYltsbzIgKyBrICAtIChoaTEgLSBsbzEpXTsKICAgICAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgbG8yICs9IChrICsgMSkgLyAyOwogICAgICAgICAgICAgICAgICAgIGsgLT0gKGsgKyAxKSAvIDI7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBpZiAoYVtsbzEgKyBrIC8gMl0gPT0gYltsbzIgKyBrIC8gMl0pIHsKICAgICAgICAgICAgICAgICAgICByZXR1cm4gYVtsbzEgKyBrIC8gMl07CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBpZiAoYVtsbzEgKyBrIC8gMl0gPiBiW2xvMiArIGsgLyAyXSkgewogICAgICAgICAgICAgICAgICAgIC8vIHN3YXAoYSwgYik7IHN3YXAobG8xLCBsbzIpOyBzd2FwKGhpMSwgaGkyKTsKICAgICAgICAgICAgICAgICAgICBkb3VibGVbXSBhcnJheVN3YXAgPSBhOyBhID0gYjsgYiA9IGFycmF5U3dhcDsKICAgICAgICAgICAgICAgICAgICBpbnQgc3dhcCA9IGxvMTsgbG8xID0gbG8yOyBsbzIgPSBzd2FwOwogICAgICAgICAgICAgICAgICAgIHN3YXAgPSBoaTE7IGhpMSA9IGhpMjsgaGkyID0gc3dhcDsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGxvMSArPSAoayArIDEpIC8gMjsKICAgICAgICAgICAgICAgIGsgLT0gKGsgKyAxKSAvIDI7CiAgICAgICAgICAgIH0gICAgCiAgICAgICAgfQogICAgICAgIHJldHVybiBEb3VibGUuTmFOOwogICAgfQoKICAgIHByaXZhdGUgc3RhdGljIGRvdWJsZSBvbmVUd29NZWRpYW4oCiAgICAgICAgICAgIGRvdWJsZVtdIGEsIGludCBsbzEsIGludCBoaTEsCiAgICAgICAgICAgIGRvdWJsZVtdIGIsIGludCBsbzIsIGludCBoaTIpIHsKICAgICAgICBhc3NlcnQgaGkxIC0gbG8xID09IDEgJiYgaGkyIC0gbG8yID09IDI7CiAgICAgICAgLy8gcmV0dXJuIGEwICsgYjAgKyBiMSAtIG1pbihhMCwgYjApIC0gbWF4KGEwLCBiMSk7CiAgICAgICAgLy8gcmV0dXJuIG1heChhMCwgYjApICsgbWluKDAsIGIxIC0gYTApOwogICAgICAgIHJldHVybiBtYXgoYVtsbzFdLCBiW2xvMl0pICsgbWluKDAsIGJbbG8yICsgMV0gLSBhW2xvMV0pOwogICAgfQoKICAgIHByaXZhdGUgc3RhdGljIGRvdWJsZSB0d29Ud29NZWRpYW4oCiAgICAgICAgICAgIGRvdWJsZVtdIGEsIGludCBsbzEsIGludCBoaTEsCiAgICAgICAgICAgIGRvdWJsZVtdIGIsIGludCBsbzIsIGludCBoaTIpIHsKICAgICAgICBhc3NlcnQgaGkxIC0gbG8xID09IDIgJiYgaGkyIC0gbG8yID09IDI7CgogICAgICAgIHJldHVybiAobWF4KGFbbG8xXSwgYltsbzJdKSArIG1pbihhW2xvMSArIDFdLCBiW2xvMiArIDFdKSkgLyAyOwogICAgfQogICAgCiAgICAvKioKICAgICAqIENoZWNrcyBpZiB0aGUgYXJyYXkgb2YgZG91YmxlcyBpcyBzb3J0ZWQuCiAgICAgKiBVc2VkIHNvbGVseSBmb3IgYXNzZXJ0aW9ucyB0ZXN0cy4KICAgICAqLwogICAgcHJpdmF0ZSBzdGF0aWMgYm9vbGVhbiBpc1NvcnRlZChkb3VibGVbXSBhLCBpbnQgbG8sIGludCBoaSkgewogICAgICAgIGFzc2VydCByYW5nZUNoZWNrKGEsIGxvLCBoaSkKICAgICAgICAgICAgOiBTdHJpbmcuZm9ybWF0KCJsZW4oYSkgPSAlZCwgbG8gPSAlZCwgaGkgPSAlZCIsCiAgICAgICAgICAgICAgICBhLmxlbmd0aCwgbG8sIGhpKTsKCiAgICAgICAgZm9yIChpbnQgaSA9IGxvOyBpIDwgaGkgLSAxOyBpKyspIHsKICAgICAgICAgICAgaWYgKGFbaV0gPiBhW2kgKyAxXSkgewogICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiB0cnVlOwogICAgfQoKICAgIHByaXZhdGUgc3RhdGljIGJvb2xlYW4gaXNTb3J0ZWQoZG91YmxlW10gYSkgewogICAgICAgIHJldHVybiBpc1NvcnRlZChhLCAwLCBhLmxlbmd0aCk7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogQ2hlY2tzIGlmIHRoZSBzcGVjaWZpZWQgaW50ZXJ2YWwgYmVsb25ncyB0byB0aGUgYXJyYXkuCiAgICAgKiBSZXR1cm5zIGZhbHNlIGluIGNhc2UgaXQgZG9lcyBub3QsIHRoZSBpbnRlcnZhbCBpcyBkZWZpbmVkCiAgICAgKiBpbmNvcnJlY3RseSAoZW1wdHkgaW50ZXJ2YWxzIGFyZSBhY2NlcHRhYmxlKSBvciBhID09IG51bGwuCiAgICAgKgogICAgICogVXNlZCBzb2xlbHkgZm9yIGFzc2VydGlvbnMgdGVzdHMuCiAgICAgKi8KICAgIHByaXZhdGUgc3RhdGljIGJvb2xlYW4gcmFuZ2VDaGVjayhkb3VibGVbXSBhLCBpbnQgbG8sIGludCBoaSkgewogICAgICAgIGlmIChhID09IG51bGwpIHsKICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgIH0gZWxzZSBpZiAobG8gPCAwIHx8IGxvID49IGEubGVuZ3RoICYmIGxvICE9IDAKICAgICAgICAgICAgICAgIHx8IGhpIDwgMCB8fCBoaSA+IGEubGVuZ3RoKSB7CiAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICB9IGVsc2UgaWYgKGxvID4gaGkpIHsKICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgIH0KICAgICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KCiAgICBwdWJsaWMgc3RhdGljIHZvaWQgbWFpbihTdHJpbmdbXSBhcmdzKSB7CiAgICAgICAgZG91YmxlW10gYSA9IHsgMCwgMiwgNCwgNiwgOCB9OwogICAgICAgIGRvdWJsZVtdIGIgPSB7IDEsIDMsIDUsIDcsIDkgfTsKICAgICAgICBpbnQgayA9IDQ7CiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKG1lZGlhblR3b0FycmF5c0xpbmVhcihhLCBiKSk7CiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKG1lZGlhblR3b0FycmF5cyhhLCBiKSk7CiAgICAgICAgCiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKG1lZGlhblR3b0RpZmZlcmVudFNpemVBcnJheXNMaW5lYXIoYSwgYikpOwogICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbihtZWRpYW5Ud29EaWZmZXJlbnRTaXplQXJyYXlzKGEsIGIpKTsKICAgICAgICAKICAgICAgICBTeXN0ZW0ub3V0LnByaW50bG4oa3RoTGFyZ2VzdExpbmVhcihhLCBiLCBrKSk7CiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKGt0aExhcmdlc3QoYSwgYiwgaykpOwogICAgfQp9