/* package whatever; // don't place package name! */
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone {
/**
* A class that is able to brute-force a solution for a Sudoku-like puzzle.
* <br>
* Due to the internal use of bit-shifting the largest sudoku puzzle this can solve is 25x25
* which should be more than enough. Sudoku-like puzzles are always square-number sized. 1x1, 4x4, 9x9, 16x16, 25x25, etc.
*
* @author rolfl
*
*/
private static class RecursiveBruteSolver {
// dimension - the width of the grid
private final int dimension;
// a simple bit-mask with 1 bit set for each possible value in each square.
// for a 4-size sudoku it will look like:
// 0b0001 0b0010 0b0100 0b1000
// for a 9-size sudoku like:
// 0b000000001 0b000000010 0b000000100 .....
private final int[] bitmask;
// if we flatten the grid, this is how big it is in 1 dimension
private final int flatsize;
// the array of flattened cell available digits
private final int[][] available;
// a complicated concept - the index into the flattened array of all
// squares that are in the same row/column/block, but also have a larger
// index in the flattened array.
private final int[][] followings;
// Some squares will have just one possible value, they do not need to be
// solved.
// this unknown array is the indices of the unsolved squares in the
// flattened array
private final int[] unknown;
// keep track of all recursive call counts
private long statistics = 0L;
/**
* Create a Brute-force solver that will determine all the solutions (if
* any) for a Sudoku grid (when you call the solve() method).
*
* @param dimension
* the side-size of the sudoku grid. The digits 2D array is
* expected to match the same dimensions.
* @param digits
* a 3D array containing the digits that are allowed at that
* position in the array. The actual digits available are
* expected to be 0-based. i.e. a regular 9-size Sudoku has the
* digits 1-9, this solver expects them to be represented as 0-8.
*/
public RecursiveBruteSolver(int dimension, int[][][] digits) {
this.dimension = dimension;
// if we flatten the array....
this.flatsize = dimension * dimension;
available = new int[flatsize][];
followings = new int[flatsize][];
// how many digits are there...and what will the bit-mask be for each digit.
bitmask = new int[dimension];
for (int i = 0; i < dimension; i++) {
bitmask[i] = 1 << i;
}
// keep track of the unknown cells.
// make a generous-size array, we will trim it later.
int[] tmpunknown = new int[flatsize];
int tmpunknowncnt = 0;
// flatten out the grid.
for (int r = 0; r < dimension; r++) {
for (int c = 0; c < dimension; c++) {
int flatid = r * dimension + c;
// gets an array of digits that can be put in each square.
// for example, if a Sudoku square can have 3,5 or 6 this will return
// [2,4,5]
available
[flatid
] = Arrays.
copyOf(digits
[r
][c
], digits
[r
][c
].
length); if (available[flatid].length > 1) {
tmpunknown[tmpunknowncnt++] = flatid;
}
}
}
// System.out.println("There are " + tmpunknowncnt + " unknown cells");
// Special note about `followings`
// A square in a Sudoku puzzle affects all other squares in the same row, column, and block.
// Only one square in the same row/block/column can have particular value.
// For this recursion we 'flatten' the grid, and process the grid in order.
// For each unsolved cell, we set the cell value, and then move on to the next unsolved cell
// but, we need to 'remove' our value from the possible values of other cells in the same row/column/block.
// Because of the way this solver progresses along the flattened array, we only need to remove it
// from cells that come **after** us in the flattened array (values before us already have a fixed value).
// So, buildFollowing() builds an array of indexes in the flattened array that are in the same row/column/block
// but also have a higher index in the flattened array.
for (int flat = 0; flat < available.length; flat++) {
if (available[flat] != null) {
followings[flat] = buildFollowing(flat / dimension, flat
% dimension);
}
}
// create the final copy of the unknown cells (cells which need to be solved).
unknown
= Arrays.
copyOf(tmpunknown, tmpunknowncnt
); }
public int[][][] solve() {
// following points to unknown subsequent values.....
final int[] combination = new int[flatsize];
// where to store the possible solutions we find
final List<int[][]> solutions = new ArrayList<>();
// this freedoms is an integer for each value.
// bits in the integer are set for each of the values the
// position can be. This is essentially a record of the state
// inside the recursive routine. For example, if setting some other
// cell in the same row/column/block to 5, and our 5-bit is set,
// then we will unset it here because we no longer have the freedom
// to be 5.
final int[] freedoms = new int[flatsize]; //Arrays.copyOf(resetmask, resetmask.length);
for (int flatid = 0; flatid < flatsize; flatid++) {
for (int b : available[flatid]) {
// set the degrees-of-freedom mask of this...
// what values can this cell take?
freedoms[flatid] |= bitmask[b];
}
}
// Do the actual recursion.
// combination contains pointers to which actual values are being used.
// freedom contans the possible states for all subsequent cells.
recurse(solutions, 0, combination, freedoms);
System.
out.
println("There were " + statistics
+ " recursive calls...");
// convert the list of Solutions back to an array
return solutions.toArray(new int[solutions.size()][][]);
}
/**
* Recursively solve the Sudoku puzzle.
* @param solutions where to store any found solutions.
* @param index The index in the 'unknown' array that points to the flat-based cell we need to solve.
* @param combination What the current combination of cell values is.
* @param freedoms The state of what potential values all cells can have.
*/
private void recurse(final List<int[][]> solutions, final int index,
final int[] combination, final int[] freedoms) {
statistics++;
if (index >= unknown.length) {
// solution!
solutions.add(buildSolution(combination));
return;
}
// The basic algorithm here is: for our unsolved square, we set it to each of it's possible values in turn.
// then, for each of the values we can be:
// 1. we also find all 'related' squares, and remove our value
// from the degrees-of-freedom for the related squares
// (If I am 'x' then they cannot be). See special not about 'followings'
// 3. we keep track of which other squares we actually change the freedoms for.
// 4. we recurse to the next unsolved square.
// 5. when the recursion returns, we restore the freedoms we previously 'revoked'
// 6. we move on to the next value we can be (back to 1).
// 7. when we have run out of possible values, we return.
final int flat = unknown[index];
for (int a = available[flat].length - 1; a >= 0; a--) {
final int attempt = available[flat][a];
if ((freedoms[flat] & bitmask[attempt]) == 0) {
// this option excluded by previous restrictions....
// the original unsolved puzzle says we can be 'attempt', but
// higher levels of recursion have removed 'attempt' from our
// degrees-of-freedom.
continue;
}
// ok, is used to track whether we are still creating a valid Sudoku.
boolean ok = true;
// progress is used to forward, and then backtrack which following cells
// have been impacted.
// start at -1 because we pre-increment the progress.
int progress = -1;
// act has 1 bit representing each follower we act on.
long act = 0;
while (++progress < followings[flat].length) {
if (freedoms[followings[flat][progress]] == bitmask[attempt]) {
// we intend to remove the attempt from this follower's freedom's
// but that will leave it with nothing, so this is not possible to do.
// ok is false, so we will start a back-up
ok = false;
break;
}
// we **can** remove the value from this follower's freedoms.
// indicate that this follower is being 'touched'.
// act will have 1 bit available for each follower we touch.
act <<= 1;
// record the pre-state of the follower's freedoms.
final int pre = freedoms[followings[flat][progress]];
// if the follower's freedoms contained the value we are revoking, then set the bit.
act |= (freedoms[followings[flat][progress]] &= ~bitmask[attempt]) == pre ? 0 : 1;
}
if (ok) {
// we have removed our digit from all followers, and the puzzle is still valid.
// indicate our combination digit....
combination[flat] = a;
// find the next unsolved.
recurse(solutions, index + 1, combination, freedoms);
}
while (--progress >= 0) {
// restore all previously revoked freedoms.
if ((act & 0x1) == 1) {
freedoms[followings[flat][progress]] |= bitmask[attempt]; // & resetmask[flat]);
}
act >>= 1;
}
}
}
/**
* buildFollowing creates an array of references to other cells in the same
* row/column/block that also have an index **after** us in the flattened array system.
*
* @param row our row index
* @param col our column index
* @return an array of flattened indices that are in the same row/column/block as us.
*/
private int[] buildFollowing(int row, int col) {
int[] folls = new int[dimension * 3]; // possible rows/columns/blocks - 3 sets of values.
final int innerbound
= (int)Math.
sqrt(dimension
); // 3 for size 9, 2 for size 4, 4 for size 16, etc. // cnt is used to count the valid following indices.
int cnt = 0;
// column-bound - last column in the same block as us.
int cb = ((1 + col / innerbound) * innerbound);
// row-bound - last row in the same block as us.
int rb = ((1 + row / innerbound) * innerbound);
// get all (unsolved) indices that follow us in the same row
for (int c = col + 1; c < dimension; c++) {
// rest of row.
if (available[row * dimension + c].length > 1) {
// only need to worry about unsolved followers.
folls[cnt++] = row * dimension + c;
}
}
// get all (unsolved) indices that follow us in the same column
for (int r = row + 1; r < dimension; r++) {
if (available[r * dimension + col].length > 1) {
// only need to worry about unsolved followers.
folls[cnt++] = r * dimension + col;
}
if (r < rb) {
// if we have not 'escaped' our block, we also find other cells in
// the same block, but not our row/column.
for (int c = col + 1; c < cb; c++) {
if (available[r * dimension + c].length > 1) {
// only need to worry about unsolved followers.
folls[cnt++] = r * dimension + c;
}
}
}
}
// return just the values that were needed as followers.
return Arrays.
copyOf(folls, cnt
); }
/**
* Convert the valid combination of values back to a simple int[] grid.
* @param combination the combination of unsolved values that is a valid puzzle.
* @return A Solution object representing the solution.
*/
private int[][] buildSolution(int[] combination) {
int[][] grid = new int[dimension][dimension];
for (int f = 0; f < combination.length; f++) {
grid[f / dimension][f % dimension] = available[f][combination[f]];
}
// double-check the validity of this solution (all sudoku basic rules are followed.
// throws exception if not.
// SudokuRules.isValid(grid);
// mechanism for printing out a grid.
// System.out.println("BruteForceRecursive found Solution:\n"
// + GridToText.displayAsString(grid));
return grid;
}
}
public static void main
(String[] args
) { int[][][] puzzle = new int[][][] {
{ { 1, 4, 5, },{ 2, 5, 6, },{ 1, 2, 4, 5, 6, },{ 7, },{ 3, },{ 2, 4, 5, 6, },{ 0, 1, 6, },{ 0, 1, 6, },{ 8, }, },
{ { 1, 3, 5, },{ 2, 3, 5, 6, 8, },{ 0, },{ 2, 5, 6, },{ 2, 5, 6, 8, },{ 2, 5, 6, 8, },{ 1, 6, 7, },{ 1, 6, 7, },{ 4, }, },
{ { 7, },{ 6, 8, },{ 4, 6, 8, },{ 4, 6, },{ 1, },{ 0, },{ 3, },{ 5, },{ 2, }, },
{ { 6, },{ 0, 2, 3, 5, },{ 7, },{ 0, 1, 2, 3, 4, 5, },{ 2, 4, 5, },{ 1, 2, 4, 5, },{ 1, 5, },{ 8, },{ 1, 3, 5, }, },
{ { 0, 1, 3, 5, },{ 0, 2, 3, 5, 8, },{ 1, 2, 5, 8, },{ 0, 1, 2, 3, 4, 5, 6, },{ 2, 4, 5, 6, 8, },{ 1, 2, 4, 5, 6, 7, 8, },{ 1, 5, 6, 7, },{ 1, 3, 4, 6, 7, },{ 1, 3, 5, 7, }, },
{ { 1, 3, 5, },{ 4, },{ 1, 5, 8, },{ 1, 3, 5, 6, },{ 5, 6, 8, },{ 1, 5, 6, 7, 8, },{ 2, },{ 1, 3, 6, 7, },{ 0, }, },
{ { 4, 5, },{ 1, },{ 3, },{ 8, },{ 0, },{ 2, 4, 5, },{ 5, 7, },{ 2, 7, },{ 6, }, },
{ { 8, },{ 0, 5, 6, 7, },{ 5, 6, },{ 1, 2, 5, 6, },{ 2, 5, 6, },{ 1, 2, 5, 6, },{ 4, },{ 0, 1, 2, 3, 7, },{ 1, 3, 5, 7, }, },
{ { 2, },{ 0, 5, 6, },{ 4, 5, 6, },{ 1, 4, 5, 6, },{ 7, },{ 3, },{ 0, 1, 5, 8, },{ 0, 1, },{ 1, 5, }, },
};
RecursiveBruteSolver solver = new RecursiveBruteSolver(9, puzzle);
for (int[][] sol : solver.solve()) {
System.
out.
println("Solution:"); System.
out.
println(displayAsString
(sol
)); }
}
private static final char[][] symbols = {
"╔═╤╦╗".toCharArray(),
"║ │║║".toCharArray(),
"╟─┼╫╢".toCharArray(),
"╠═╪╬╣".toCharArray(),
"╚═╧╩╝".toCharArray(),
};
private static final char[] DIGITCHARS = "123456789ABCFEDGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
public static final char getSudokuDigit(final int value) {
if (value < 0) {
return ' ';
}
return DIGITCHARS[value];
}
public static final String displayAsString
(int[][]data
) { return buildStringForGrid
(data.
length,
(int)Math.
sqrt(data.
length), data
); }
private static final String buildStringForGrid
(final int dimension,
final int blocksize,
final int[][]rows
) { final StringBuilder sb = new StringBuilder();
for (int r = 0; r < dimension; r++) {
if (r == 0) {
sb.append(printSymbolLine(dimension, blocksize, null, symbols[0]));
} else if (r % blocksize == 0) {
sb.append(printSymbolLine(dimension, blocksize, null, symbols[3]));
} else {
sb.append(printSymbolLine(dimension, blocksize, null, symbols[2]));
}
sb.append(printSymbolLine(dimension, blocksize, rows[r], symbols[1]));
}
sb.append(printSymbolLine(dimension, blocksize, null, symbols[4]));
return sb.toString();
}
private static String printSymbolLine
(int dimension,
int blocksize,
int[] values,
char[] symbols
) { StringBuilder sb = new StringBuilder();
sb.append(symbols[0]);
int vc = 0;
for (int b = 0; b < blocksize; b++) {
for (int c = 0; c < blocksize; c++) {
if (values == null) {
sb.append(symbols[1]).append(symbols[1]).append(symbols[1]).append(symbols[2]);
} else {
final int val = values[vc++];
char ch = getSudokuDigit(val);
sb.append(symbols[1]).append(ch).append(symbols[1]).append(symbols[2]);
}
}
sb.setCharAt(sb.length() - 1, symbols[3]);
}
sb.setCharAt(sb.length() - 1, symbols[4]);
sb.append("\n");
return sb.toString();
}
}
CgovKiBwYWNrYWdlIHdoYXRldmVyOyAvLyBkb24ndCBwbGFjZSBwYWNrYWdlIG5hbWUhICovCgppbXBvcnQgamF2YS51dGlsLkFycmF5TGlzdDsKaW1wb3J0IGphdmEudXRpbC5BcnJheXM7CmltcG9ydCBqYXZhLnV0aWwuTGlzdDsKCi8qIE5hbWUgb2YgdGhlIGNsYXNzIGhhcyB0byBiZSAiTWFpbiIgb25seSBpZiB0aGUgY2xhc3MgaXMgcHVibGljLiAqLwpjbGFzcyBJZGVvbmUgewogICAgCiAgICAvKioKICAgICAqIEEgY2xhc3MgdGhhdCBpcyBhYmxlIHRvIGJydXRlLWZvcmNlIGEgc29sdXRpb24gZm9yIGEgU3Vkb2t1LWxpa2UgcHV6emxlLgogICAgICogPGJyPgogICAgICogRHVlIHRvIHRoZSBpbnRlcm5hbCB1c2Ugb2YgYml0LXNoaWZ0aW5nIHRoZSBsYXJnZXN0IHN1ZG9rdSBwdXp6bGUgdGhpcyBjYW4gc29sdmUgaXMgMjV4MjUKICAgICAqIHdoaWNoIHNob3VsZCBiZSBtb3JlIHRoYW4gZW5vdWdoLiBTdWRva3UtbGlrZSBwdXp6bGVzIGFyZSBhbHdheXMgc3F1YXJlLW51bWJlciBzaXplZC4gMXgxLCA0eDQsIDl4OSwgMTZ4MTYsIDI1eDI1LCBldGMuCiAgICAgKiAKICAgICAqIEBhdXRob3Igcm9sZmwKICAgICAqCiAgICAgKi8KICAgIHByaXZhdGUgc3RhdGljIGNsYXNzIFJlY3Vyc2l2ZUJydXRlU29sdmVyIHsKICAgIAogICAgICAgIC8vIGRpbWVuc2lvbiAtIHRoZSB3aWR0aCBvZiB0aGUgZ3JpZAogICAgICAgIHByaXZhdGUgZmluYWwgaW50IGRpbWVuc2lvbjsKICAgICAgICAvLyBhIHNpbXBsZSBiaXQtbWFzayB3aXRoIDEgYml0IHNldCBmb3IgZWFjaCBwb3NzaWJsZSB2YWx1ZSBpbiBlYWNoIHNxdWFyZS4KICAgICAgICAvLyBmb3IgYSA0LXNpemUgc3Vkb2t1IGl0IHdpbGwgbG9vayBsaWtlOgogICAgICAgIC8vIDBiMDAwMSAwYjAwMTAgMGIwMTAwIDBiMTAwMAogICAgICAgIC8vIGZvciBhIDktc2l6ZSBzdWRva3UgbGlrZToKICAgICAgICAvLyAwYjAwMDAwMDAwMSAwYjAwMDAwMDAxMCAwYjAwMDAwMDEwMCAuLi4uLgogICAgICAgIHByaXZhdGUgZmluYWwgaW50W10gYml0bWFzazsKICAgICAgICAvLyBpZiB3ZSBmbGF0dGVuIHRoZSBncmlkLCB0aGlzIGlzIGhvdyBiaWcgaXQgaXMgaW4gMSBkaW1lbnNpb24KICAgICAgICBwcml2YXRlIGZpbmFsIGludCBmbGF0c2l6ZTsKICAgICAgICAvLyB0aGUgYXJyYXkgb2YgZmxhdHRlbmVkIGNlbGwgYXZhaWxhYmxlIGRpZ2l0cwogICAgICAgIHByaXZhdGUgZmluYWwgaW50W11bXSBhdmFpbGFibGU7CiAgICAgICAgLy8gYSBjb21wbGljYXRlZCBjb25jZXB0IC0gdGhlIGluZGV4IGludG8gdGhlIGZsYXR0ZW5lZCBhcnJheSBvZiBhbGwKICAgICAgICAvLyBzcXVhcmVzIHRoYXQgYXJlIGluIHRoZSBzYW1lIHJvdy9jb2x1bW4vYmxvY2ssIGJ1dCBhbHNvIGhhdmUgYSBsYXJnZXIKICAgICAgICAvLyBpbmRleCBpbiB0aGUgZmxhdHRlbmVkIGFycmF5LgogICAgICAgIHByaXZhdGUgZmluYWwgaW50W11bXSBmb2xsb3dpbmdzOwogICAgICAgIC8vIFNvbWUgc3F1YXJlcyB3aWxsIGhhdmUganVzdCBvbmUgcG9zc2libGUgdmFsdWUsIHRoZXkgZG8gbm90IG5lZWQgdG8gYmUKICAgICAgICAvLyBzb2x2ZWQuCiAgICAgICAgLy8gdGhpcyB1bmtub3duIGFycmF5IGlzIHRoZSBpbmRpY2VzIG9mIHRoZSB1bnNvbHZlZCBzcXVhcmVzIGluIHRoZQogICAgICAgIC8vIGZsYXR0ZW5lZCBhcnJheQogICAgICAgIHByaXZhdGUgZmluYWwgaW50W10gdW5rbm93bjsKICAgICAgICAKICAgICAgICAvLyBrZWVwIHRyYWNrIG9mIGFsbCByZWN1cnNpdmUgY2FsbCBjb3VudHMKICAgICAgICBwcml2YXRlIGxvbmcgc3RhdGlzdGljcyA9IDBMOwogICAgCiAgICAgICAgLyoqCiAgICAgICAgICogQ3JlYXRlIGEgQnJ1dGUtZm9yY2Ugc29sdmVyIHRoYXQgd2lsbCBkZXRlcm1pbmUgYWxsIHRoZSBzb2x1dGlvbnMgKGlmCiAgICAgICAgICogYW55KSBmb3IgYSBTdWRva3UgZ3JpZCAod2hlbiB5b3UgY2FsbCB0aGUgc29sdmUoKSBtZXRob2QpLgogICAgICAgICAqIAogICAgICAgICAqIEBwYXJhbSBkaW1lbnNpb24KICAgICAgICAgKiAgICAgICAgICAgIHRoZSBzaWRlLXNpemUgb2YgdGhlIHN1ZG9rdSBncmlkLiBUaGUgZGlnaXRzIDJEIGFycmF5IGlzCiAgICAgICAgICogICAgICAgICAgICBleHBlY3RlZCB0byBtYXRjaCB0aGUgc2FtZSBkaW1lbnNpb25zLgogICAgICAgICAqIEBwYXJhbSBkaWdpdHMKICAgICAgICAgKiAgICAgICAgICAgIGEgM0QgYXJyYXkgY29udGFpbmluZyB0aGUgZGlnaXRzIHRoYXQgYXJlIGFsbG93ZWQgYXQgdGhhdAogICAgICAgICAqICAgICAgICAgICAgcG9zaXRpb24gaW4gdGhlIGFycmF5LiBUaGUgYWN0dWFsIGRpZ2l0cyBhdmFpbGFibGUgYXJlCiAgICAgICAgICogICAgICAgICAgICBleHBlY3RlZCB0byBiZSAwLWJhc2VkLiBpLmUuIGEgcmVndWxhciA5LXNpemUgU3Vkb2t1IGhhcyB0aGUKICAgICAgICAgKiAgICAgICAgICAgIGRpZ2l0cyAxLTksIHRoaXMgc29sdmVyIGV4cGVjdHMgdGhlbSB0byBiZSByZXByZXNlbnRlZCBhcyAwLTguCiAgICAgICAgICovCiAgICAgICAgcHVibGljIFJlY3Vyc2l2ZUJydXRlU29sdmVyKGludCBkaW1lbnNpb24sIGludFtdW11bXSBkaWdpdHMpIHsKICAgICAgICAgICAgdGhpcy5kaW1lbnNpb24gPSBkaW1lbnNpb247CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBpZiB3ZSBmbGF0dGVuIHRoZSBhcnJheS4uLi4KICAgICAgICAgICAgdGhpcy5mbGF0c2l6ZSA9IGRpbWVuc2lvbiAqIGRpbWVuc2lvbjsKICAgICAgICAgICAgYXZhaWxhYmxlID0gbmV3IGludFtmbGF0c2l6ZV1bXTsKICAgICAgICAgICAgZm9sbG93aW5ncyA9IG5ldyBpbnRbZmxhdHNpemVdW107CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBob3cgbWFueSBkaWdpdHMgYXJlIHRoZXJlLi4uYW5kIHdoYXQgd2lsbCB0aGUgYml0LW1hc2sgYmUgZm9yIGVhY2ggZGlnaXQuCiAgICAgICAgICAgIGJpdG1hc2sgPSBuZXcgaW50W2RpbWVuc2lvbl07CiAgICAgICAgICAgIGZvciAoaW50IGkgPSAwOyBpIDwgZGltZW5zaW9uOyBpKyspIHsKICAgICAgICAgICAgICAgIGJpdG1hc2tbaV0gPSAxIDw8IGk7CiAgICAgICAgICAgIH0KICAgIAogICAgICAgICAgICAvLyBrZWVwIHRyYWNrIG9mIHRoZSB1bmtub3duIGNlbGxzLgogICAgICAgICAgICAvLyBtYWtlIGEgZ2VuZXJvdXMtc2l6ZSBhcnJheSwgd2Ugd2lsbCB0cmltIGl0IGxhdGVyLgogICAgICAgICAgICBpbnRbXSB0bXB1bmtub3duID0gbmV3IGludFtmbGF0c2l6ZV07CiAgICAgICAgICAgIGludCB0bXB1bmtub3duY250ID0gMDsKICAgIAogICAgICAgICAgICAvLyBmbGF0dGVuIG91dCB0aGUgZ3JpZC4KICAgICAgICAgICAgZm9yIChpbnQgciA9IDA7IHIgPCBkaW1lbnNpb247IHIrKykgewogICAgICAgICAgICAgICAgZm9yIChpbnQgYyA9IDA7IGMgPCBkaW1lbnNpb247IGMrKykgewogICAgICAgICAgICAgICAgICAgIGludCBmbGF0aWQgPSByICogZGltZW5zaW9uICsgYzsKICAgICAgICAgICAgICAgICAgICAvLyBnZXRzIGFuIGFycmF5IG9mIGRpZ2l0cyB0aGF0IGNhbiBiZSBwdXQgaW4gZWFjaCBzcXVhcmUuCiAgICAgICAgICAgICAgICAgICAgLy8gZm9yIGV4YW1wbGUsIGlmIGEgU3Vkb2t1IHNxdWFyZSBjYW4gaGF2ZSAzLDUgb3IgNiB0aGlzIHdpbGwgcmV0dXJuCiAgICAgICAgICAgICAgICAgICAgLy8gICAgWzIsNCw1XQogICAgICAgICAgICAgICAgICAgIGF2YWlsYWJsZVtmbGF0aWRdID0gQXJyYXlzLmNvcHlPZihkaWdpdHNbcl1bY10sIGRpZ2l0c1tyXVtjXS5sZW5ndGgpOwogICAgICAgICAgICAgICAgICAgIGlmIChhdmFpbGFibGVbZmxhdGlkXS5sZW5ndGggPiAxKSB7CiAgICAgICAgICAgICAgICAgICAgICAgIHRtcHVua25vd25bdG1wdW5rbm93bmNudCsrXSA9IGZsYXRpZDsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgIAogICAgLy8gICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigiVGhlcmUgYXJlICIgKyB0bXB1bmtub3duY250ICsgIiB1bmtub3duIGNlbGxzIik7CiAgICAKICAgICAgICAgICAgLy8gU3BlY2lhbCBub3RlIGFib3V0IGBmb2xsb3dpbmdzYAogICAgICAgICAgICAvLyBBIHNxdWFyZSBpbiBhIFN1ZG9rdSBwdXp6bGUgYWZmZWN0cyBhbGwgb3RoZXIgc3F1YXJlcyBpbiB0aGUgc2FtZSByb3csIGNvbHVtbiwgYW5kIGJsb2NrLgogICAgICAgICAgICAvLyBPbmx5IG9uZSBzcXVhcmUgaW4gdGhlIHNhbWUgcm93L2Jsb2NrL2NvbHVtbiBjYW4gaGF2ZSBwYXJ0aWN1bGFyIHZhbHVlLgogICAgICAgICAgICAvLyBGb3IgdGhpcyByZWN1cnNpb24gd2UgJ2ZsYXR0ZW4nIHRoZSBncmlkLCBhbmQgcHJvY2VzcyB0aGUgZ3JpZCBpbiBvcmRlci4KICAgICAgICAgICAgLy8gRm9yIGVhY2ggdW5zb2x2ZWQgY2VsbCwgd2Ugc2V0IHRoZSBjZWxsIHZhbHVlLCBhbmQgdGhlbiBtb3ZlIG9uIHRvIHRoZSBuZXh0IHVuc29sdmVkIGNlbGwKICAgICAgICAgICAgLy8gYnV0LCB3ZSBuZWVkIHRvICdyZW1vdmUnIG91ciB2YWx1ZSBmcm9tIHRoZSBwb3NzaWJsZSB2YWx1ZXMgb2Ygb3RoZXIgY2VsbHMgaW4gdGhlIHNhbWUgcm93L2NvbHVtbi9ibG9jay4KICAgICAgICAgICAgLy8gQmVjYXVzZSBvZiB0aGUgd2F5IHRoaXMgc29sdmVyIHByb2dyZXNzZXMgYWxvbmcgdGhlIGZsYXR0ZW5lZCBhcnJheSwgd2Ugb25seSBuZWVkIHRvIHJlbW92ZSBpdAogICAgICAgICAgICAvLyBmcm9tIGNlbGxzIHRoYXQgY29tZSAqKmFmdGVyKiogdXMgaW4gdGhlIGZsYXR0ZW5lZCBhcnJheSAodmFsdWVzIGJlZm9yZSB1cyBhbHJlYWR5IGhhdmUgYSBmaXhlZCB2YWx1ZSkuCiAgICAgICAgICAgIC8vIFNvLCBidWlsZEZvbGxvd2luZygpIGJ1aWxkcyBhbiBhcnJheSBvZiBpbmRleGVzIGluIHRoZSBmbGF0dGVuZWQgYXJyYXkgdGhhdCBhcmUgaW4gdGhlIHNhbWUgcm93L2NvbHVtbi9ibG9jawogICAgICAgICAgICAvLyBidXQgYWxzbyBoYXZlIGEgaGlnaGVyIGluZGV4IGluIHRoZSBmbGF0dGVuZWQgYXJyYXkuCiAgICAgICAgICAgIGZvciAoaW50IGZsYXQgPSAwOyBmbGF0IDwgYXZhaWxhYmxlLmxlbmd0aDsgZmxhdCsrKSB7CiAgICAgICAgICAgICAgICBpZiAoYXZhaWxhYmxlW2ZsYXRdICE9IG51bGwpIHsKICAgICAgICAgICAgICAgICAgICBmb2xsb3dpbmdzW2ZsYXRdID0gYnVpbGRGb2xsb3dpbmcoZmxhdCAvIGRpbWVuc2lvbiwgZmxhdAogICAgICAgICAgICAgICAgICAgICAgICAgICAgJSBkaW1lbnNpb24pOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAKICAgICAgICAgICAgLy8gY3JlYXRlIHRoZSBmaW5hbCBjb3B5IG9mIHRoZSB1bmtub3duIGNlbGxzIChjZWxscyB3aGljaCBuZWVkIHRvIGJlIHNvbHZlZCkuCiAgICAgICAgICAgIHVua25vd24gPSBBcnJheXMuY29weU9mKHRtcHVua25vd24sIHRtcHVua25vd25jbnQpOwogICAgICAgIH0KICAgIAogICAgICAgIHB1YmxpYyBpbnRbXVtdW10gc29sdmUoKSB7CiAgICAKICAgICAgICAgICAgLy8gZm9sbG93aW5nIHBvaW50cyB0byB1bmtub3duIHN1YnNlcXVlbnQgdmFsdWVzLi4uLi4KICAgICAgICAgICAgZmluYWwgaW50W10gY29tYmluYXRpb24gPSBuZXcgaW50W2ZsYXRzaXplXTsKICAgICAgICAgICAgLy8gd2hlcmUgdG8gc3RvcmUgdGhlIHBvc3NpYmxlIHNvbHV0aW9ucyB3ZSBmaW5kCiAgICAgICAgICAgIGZpbmFsIExpc3Q8aW50W11bXT4gc29sdXRpb25zID0gbmV3IEFycmF5TGlzdDw+KCk7CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyB0aGlzIGZyZWVkb21zIGlzIGFuIGludGVnZXIgZm9yIGVhY2ggdmFsdWUuCiAgICAgICAgICAgIC8vIGJpdHMgaW4gdGhlIGludGVnZXIgYXJlIHNldCBmb3IgZWFjaCBvZiB0aGUgdmFsdWVzIHRoZQogICAgICAgICAgICAvLyBwb3NpdGlvbiBjYW4gYmUuIFRoaXMgaXMgZXNzZW50aWFsbHkgYSByZWNvcmQgb2YgdGhlIHN0YXRlCiAgICAgICAgICAgIC8vIGluc2lkZSB0aGUgcmVjdXJzaXZlIHJvdXRpbmUuIEZvciBleGFtcGxlLCBpZiBzZXR0aW5nIHNvbWUgb3RoZXIKICAgICAgICAgICAgLy8gY2VsbCBpbiB0aGUgc2FtZSByb3cvY29sdW1uL2Jsb2NrIHRvIDUsIGFuZCBvdXIgNS1iaXQgaXMgc2V0LAogICAgICAgICAgICAvLyB0aGVuIHdlIHdpbGwgdW5zZXQgaXQgaGVyZSBiZWNhdXNlIHdlIG5vIGxvbmdlciBoYXZlIHRoZSBmcmVlZG9tCiAgICAgICAgICAgIC8vIHRvIGJlIDUuCiAgICAgICAgICAgIGZpbmFsIGludFtdIGZyZWVkb21zID0gbmV3IGludFtmbGF0c2l6ZV07IC8vQXJyYXlzLmNvcHlPZihyZXNldG1hc2ssIHJlc2V0bWFzay5sZW5ndGgpOwogICAgICAgICAgICBmb3IgKGludCBmbGF0aWQgPSAwOyBmbGF0aWQgPCBmbGF0c2l6ZTsgZmxhdGlkKyspIHsKICAgICAgICAgICAgICAgIGZvciAoaW50IGIgOiBhdmFpbGFibGVbZmxhdGlkXSkgewogICAgICAgICAgICAgICAgICAgIC8vIHNldCB0aGUgZGVncmVlcy1vZi1mcmVlZG9tIG1hc2sgb2YgdGhpcy4uLgogICAgICAgICAgICAgICAgICAgIC8vIHdoYXQgdmFsdWVzIGNhbiB0aGlzIGNlbGwgdGFrZT8KICAgICAgICAgICAgICAgICAgICBmcmVlZG9tc1tmbGF0aWRdIHw9IGJpdG1hc2tbYl07CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgIAogICAgICAgICAgICAvLyBEbyB0aGUgYWN0dWFsIHJlY3Vyc2lvbi4KICAgICAgICAgICAgLy8gY29tYmluYXRpb24gY29udGFpbnMgcG9pbnRlcnMgdG8gd2hpY2ggYWN0dWFsIHZhbHVlcyBhcmUgYmVpbmcgdXNlZC4KICAgICAgICAgICAgLy8gZnJlZWRvbSBjb250YW5zIHRoZSBwb3NzaWJsZSBzdGF0ZXMgZm9yIGFsbCBzdWJzZXF1ZW50IGNlbGxzLgogICAgICAgICAgICByZWN1cnNlKHNvbHV0aW9ucywgMCwgY29tYmluYXRpb24sIGZyZWVkb21zKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigiVGhlcmUgd2VyZSAiICsgc3RhdGlzdGljcyArICIgcmVjdXJzaXZlIGNhbGxzLi4uIik7CiAgICAKICAgICAgICAgICAgLy8gY29udmVydCB0aGUgbGlzdCBvZiBTb2x1dGlvbnMgYmFjayB0byBhbiBhcnJheQogICAgICAgICAgICByZXR1cm4gc29sdXRpb25zLnRvQXJyYXkobmV3IGludFtzb2x1dGlvbnMuc2l6ZSgpXVtdW10pOwogICAgICAgIH0KICAgIAogICAgICAgIC8qKgogICAgICAgICAqIFJlY3Vyc2l2ZWx5IHNvbHZlIHRoZSBTdWRva3UgcHV6emxlLgogICAgICAgICAqIEBwYXJhbSBzb2x1dGlvbnMgd2hlcmUgdG8gc3RvcmUgYW55IGZvdW5kIHNvbHV0aW9ucy4KICAgICAgICAgKiBAcGFyYW0gaW5kZXggVGhlIGluZGV4IGluIHRoZSAndW5rbm93bicgYXJyYXkgdGhhdCBwb2ludHMgdG8gdGhlIGZsYXQtYmFzZWQgY2VsbCB3ZSBuZWVkIHRvIHNvbHZlLgogICAgICAgICAqIEBwYXJhbSBjb21iaW5hdGlvbiBXaGF0IHRoZSBjdXJyZW50IGNvbWJpbmF0aW9uIG9mIGNlbGwgdmFsdWVzIGlzLgogICAgICAgICAqIEBwYXJhbSBmcmVlZG9tcyBUaGUgc3RhdGUgb2Ygd2hhdCBwb3RlbnRpYWwgdmFsdWVzIGFsbCBjZWxscyBjYW4gaGF2ZS4KICAgICAgICAgKi8KICAgICAgICBwcml2YXRlIHZvaWQgcmVjdXJzZShmaW5hbCBMaXN0PGludFtdW10+IHNvbHV0aW9ucywgZmluYWwgaW50IGluZGV4LAogICAgICAgICAgICAgICAgZmluYWwgaW50W10gY29tYmluYXRpb24sIGZpbmFsIGludFtdIGZyZWVkb21zKSB7CiAgICAgICAgICAgIHN0YXRpc3RpY3MrKzsKICAgICAgICAgICAgaWYgKGluZGV4ID49IHVua25vd24ubGVuZ3RoKSB7CiAgICAgICAgICAgICAgICAvLyBzb2x1dGlvbiEKICAgICAgICAgICAgICAgIHNvbHV0aW9ucy5hZGQoYnVpbGRTb2x1dGlvbihjb21iaW5hdGlvbikpOwogICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICB9CiAgICAgICAgICAgIAogICAgICAgICAgICAvLyBUaGUgYmFzaWMgYWxnb3JpdGhtIGhlcmUgaXM6IGZvciBvdXIgdW5zb2x2ZWQgc3F1YXJlLCB3ZSBzZXQgaXQgdG8gZWFjaCBvZiBpdCdzIHBvc3NpYmxlIHZhbHVlcyBpbiB0dXJuLgogICAgICAgICAgICAvLyB0aGVuLCBmb3IgZWFjaCBvZiB0aGUgdmFsdWVzIHdlIGNhbiBiZToKICAgICAgICAgICAgLy8gMS4gd2UgYWxzbyBmaW5kIGFsbCAncmVsYXRlZCcgc3F1YXJlcywgYW5kIHJlbW92ZSBvdXIgdmFsdWUKICAgICAgICAgICAgLy8gICAgICBmcm9tIHRoZSBkZWdyZWVzLW9mLWZyZWVkb20gZm9yIHRoZSByZWxhdGVkIHNxdWFyZXMKICAgICAgICAgICAgLy8gICAgICAoSWYgSSBhbSAneCcgdGhlbiB0aGV5IGNhbm5vdCBiZSkuIFNlZSBzcGVjaWFsIG5vdCBhYm91dCAnZm9sbG93aW5ncycKICAgICAgICAgICAgLy8gMy4gd2Uga2VlcCB0cmFjayBvZiB3aGljaCBvdGhlciBzcXVhcmVzIHdlIGFjdHVhbGx5IGNoYW5nZSB0aGUgZnJlZWRvbXMgZm9yLgogICAgICAgICAgICAvLyA0LiB3ZSByZWN1cnNlIHRvIHRoZSBuZXh0IHVuc29sdmVkIHNxdWFyZS4KICAgICAgICAgICAgLy8gNS4gd2hlbiB0aGUgcmVjdXJzaW9uIHJldHVybnMsIHdlIHJlc3RvcmUgdGhlIGZyZWVkb21zIHdlIHByZXZpb3VzbHkgJ3Jldm9rZWQnCiAgICAgICAgICAgIC8vIDYuIHdlIG1vdmUgb24gdG8gdGhlIG5leHQgdmFsdWUgd2UgY2FuIGJlIChiYWNrIHRvIDEpLgogICAgICAgICAgICAvLyA3LiB3aGVuIHdlIGhhdmUgcnVuIG91dCBvZiBwb3NzaWJsZSB2YWx1ZXMsIHdlIHJldHVybi4KICAgICAgICAgICAgZmluYWwgaW50IGZsYXQgPSB1bmtub3duW2luZGV4XTsKICAgICAgICAgICAgZm9yIChpbnQgYSA9IGF2YWlsYWJsZVtmbGF0XS5sZW5ndGggLSAxOyBhID49IDA7IGEtLSkgewogICAgICAgICAgICAgICAgZmluYWwgaW50IGF0dGVtcHQgPSBhdmFpbGFibGVbZmxhdF1bYV07CiAgICAgICAgICAgICAgICBpZiAoKGZyZWVkb21zW2ZsYXRdICYgYml0bWFza1thdHRlbXB0XSkgPT0gMCkgewogICAgICAgICAgICAgICAgICAgIC8vIHRoaXMgb3B0aW9uIGV4Y2x1ZGVkIGJ5IHByZXZpb3VzIHJlc3RyaWN0aW9ucy4uLi4KICAgICAgICAgICAgICAgICAgICAvLyB0aGUgb3JpZ2luYWwgdW5zb2x2ZWQgcHV6emxlIHNheXMgd2UgY2FuIGJlICdhdHRlbXB0JywgYnV0CiAgICAgICAgICAgICAgICAgICAgLy8gaGlnaGVyIGxldmVscyBvZiByZWN1cnNpb24gaGF2ZSByZW1vdmVkICdhdHRlbXB0JyBmcm9tIG91cgogICAgICAgICAgICAgICAgICAgIC8vIGRlZ3JlZXMtb2YtZnJlZWRvbS4KICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIC8vIG9rLCBpcyB1c2VkIHRvIHRyYWNrIHdoZXRoZXIgd2UgYXJlIHN0aWxsIGNyZWF0aW5nIGEgdmFsaWQgU3Vkb2t1LgogICAgICAgICAgICAgICAgYm9vbGVhbiBvayA9IHRydWU7CiAgICAgICAgICAgICAgICAvLyBwcm9ncmVzcyBpcyB1c2VkIHRvIGZvcndhcmQsIGFuZCB0aGVuIGJhY2t0cmFjayB3aGljaCBmb2xsb3dpbmcgY2VsbHMKICAgICAgICAgICAgICAgIC8vIGhhdmUgYmVlbiBpbXBhY3RlZC4KICAgICAgICAgICAgICAgIC8vIHN0YXJ0IGF0IC0xIGJlY2F1c2Ugd2UgcHJlLWluY3JlbWVudCB0aGUgcHJvZ3Jlc3MuCiAgICAgICAgICAgICAgICBpbnQgcHJvZ3Jlc3MgPSAtMTsKICAgICAgICAgICAgICAgIC8vIGFjdCBoYXMgMSBiaXQgcmVwcmVzZW50aW5nIGVhY2ggZm9sbG93ZXIgd2UgYWN0IG9uLgogICAgICAgICAgICAgICAgbG9uZyBhY3QgPSAwOwogICAgICAgICAgICAgICAgd2hpbGUgKCsrcHJvZ3Jlc3MgPCBmb2xsb3dpbmdzW2ZsYXRdLmxlbmd0aCkgewogICAgICAgICAgICAgICAgICAgIGlmIChmcmVlZG9tc1tmb2xsb3dpbmdzW2ZsYXRdW3Byb2dyZXNzXV0gPT0gYml0bWFza1thdHRlbXB0XSkgewogICAgICAgICAgICAgICAgICAgICAgICAvLyB3ZSBpbnRlbmQgdG8gcmVtb3ZlIHRoZSBhdHRlbXB0IGZyb20gdGhpcyBmb2xsb3dlcidzIGZyZWVkb20ncwogICAgICAgICAgICAgICAgICAgICAgICAvLyBidXQgdGhhdCB3aWxsIGxlYXZlIGl0IHdpdGggbm90aGluZywgc28gdGhpcyBpcyBub3QgcG9zc2libGUgdG8gZG8uCiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG9rIGlzIGZhbHNlLCBzbyB3ZSB3aWxsIHN0YXJ0IGEgYmFjay11cAogICAgICAgICAgICAgICAgICAgICAgICBvayA9IGZhbHNlOwogICAgICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgLy8gd2UgKipjYW4qKiByZW1vdmUgdGhlIHZhbHVlIGZyb20gdGhpcyBmb2xsb3dlcidzIGZyZWVkb21zLgogICAgICAgICAgICAgICAgICAgIC8vIGluZGljYXRlIHRoYXQgdGhpcyBmb2xsb3dlciBpcyBiZWluZyAndG91Y2hlZCcuCiAgICAgICAgICAgICAgICAgICAgLy8gYWN0IHdpbGwgaGF2ZSAxIGJpdCBhdmFpbGFibGUgZm9yIGVhY2ggZm9sbG93ZXIgd2UgdG91Y2guCiAgICAgICAgICAgICAgICAgICAgYWN0IDw8PSAxOwogICAgICAgICAgICAgICAgICAgIC8vIHJlY29yZCB0aGUgcHJlLXN0YXRlIG9mIHRoZSBmb2xsb3dlcidzIGZyZWVkb21zLgogICAgICAgICAgICAgICAgICAgIGZpbmFsIGludCBwcmUgPSBmcmVlZG9tc1tmb2xsb3dpbmdzW2ZsYXRdW3Byb2dyZXNzXV07CiAgICAgICAgICAgICAgICAgICAgLy8gaWYgdGhlIGZvbGxvd2VyJ3MgZnJlZWRvbXMgY29udGFpbmVkIHRoZSB2YWx1ZSB3ZSBhcmUgcmV2b2tpbmcsIHRoZW4gc2V0IHRoZSBiaXQuCiAgICAgICAgICAgICAgICAgICAgYWN0IHw9IChmcmVlZG9tc1tmb2xsb3dpbmdzW2ZsYXRdW3Byb2dyZXNzXV0gJj0gfmJpdG1hc2tbYXR0ZW1wdF0pID09IHByZSA/IDAgOiAxOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgaWYgKG9rKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gd2UgaGF2ZSByZW1vdmVkIG91ciBkaWdpdCBmcm9tIGFsbCBmb2xsb3dlcnMsIGFuZCB0aGUgcHV6emxlIGlzIHN0aWxsIHZhbGlkLgogICAgICAgICAgICAgICAgICAgIC8vIGluZGljYXRlIG91ciBjb21iaW5hdGlvbiBkaWdpdC4uLi4KICAgICAgICAgICAgICAgICAgICBjb21iaW5hdGlvbltmbGF0XSA9IGE7CiAgICAgICAgICAgICAgICAgICAgLy8gZmluZCB0aGUgbmV4dCB1bnNvbHZlZC4KICAgICAgICAgICAgICAgICAgICByZWN1cnNlKHNvbHV0aW9ucywgaW5kZXggKyAxLCBjb21iaW5hdGlvbiwgZnJlZWRvbXMpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgd2hpbGUgKC0tcHJvZ3Jlc3MgPj0gMCkgewogICAgICAgICAgICAgICAgICAgIC8vIHJlc3RvcmUgYWxsIHByZXZpb3VzbHkgcmV2b2tlZCBmcmVlZG9tcy4KICAgICAgICAgICAgICAgICAgICBpZiAoKGFjdCAmIDB4MSkgPT0gMSkgewogICAgICAgICAgICAgICAgICAgICAgICBmcmVlZG9tc1tmb2xsb3dpbmdzW2ZsYXRdW3Byb2dyZXNzXV0gfD0gYml0bWFza1thdHRlbXB0XTsgLy8gJiByZXNldG1hc2tbZmxhdF0pOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICBhY3QgPj49IDE7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgIAogICAgICAgIH0KICAgIAogICAgICAgIC8qKgogICAgICAgICAqIGJ1aWxkRm9sbG93aW5nIGNyZWF0ZXMgYW4gYXJyYXkgb2YgcmVmZXJlbmNlcyB0byBvdGhlciBjZWxscyBpbiB0aGUgc2FtZQogICAgICAgICAqIHJvdy9jb2x1bW4vYmxvY2sgdGhhdCBhbHNvIGhhdmUgYW4gaW5kZXggKiphZnRlcioqIHVzIGluIHRoZSBmbGF0dGVuZWQgYXJyYXkgc3lzdGVtLiAKICAgICAgICAgKgogICAgICAgICAqIEBwYXJhbSByb3cgb3VyIHJvdyBpbmRleAogICAgICAgICAqIEBwYXJhbSBjb2wgb3VyIGNvbHVtbiBpbmRleAogICAgICAgICAqIEByZXR1cm4gYW4gYXJyYXkgb2YgZmxhdHRlbmVkIGluZGljZXMgdGhhdCBhcmUgaW4gdGhlIHNhbWUgcm93L2NvbHVtbi9ibG9jayBhcyB1cy4KICAgICAgICAgKi8KICAgICAgICBwcml2YXRlIGludFtdIGJ1aWxkRm9sbG93aW5nKGludCByb3csIGludCBjb2wpIHsKICAgICAgICAgICAgaW50W10gZm9sbHMgPSBuZXcgaW50W2RpbWVuc2lvbiAqIDNdOyAvLyBwb3NzaWJsZSByb3dzL2NvbHVtbnMvYmxvY2tzIC0gMyBzZXRzIG9mIHZhbHVlcy4KICAgICAgICAgICAgZmluYWwgaW50IGlubmVyYm91bmQgPSAoaW50KU1hdGguc3FydChkaW1lbnNpb24pOyAvLyAzIGZvciBzaXplIDksIDIgZm9yIHNpemUgNCwgNCBmb3Igc2l6ZSAxNiwgZXRjLgogICAgICAgICAgICAvLyBjbnQgaXMgdXNlZCB0byBjb3VudCB0aGUgdmFsaWQgZm9sbG93aW5nIGluZGljZXMuCiAgICAgICAgICAgIGludCBjbnQgPSAwOwogICAgICAgICAgICAvLyBjb2x1bW4tYm91bmQgLSBsYXN0IGNvbHVtbiBpbiB0aGUgc2FtZSBibG9jayBhcyB1cy4KICAgICAgICAgICAgaW50IGNiID0gKCgxICsgY29sIC8gaW5uZXJib3VuZCkgKiBpbm5lcmJvdW5kKTsKICAgICAgICAgICAgLy8gcm93LWJvdW5kIC0gbGFzdCByb3cgaW4gdGhlIHNhbWUgYmxvY2sgYXMgdXMuCiAgICAgICAgICAgIGludCByYiA9ICgoMSArIHJvdyAvIGlubmVyYm91bmQpICogaW5uZXJib3VuZCk7CiAgICAgICAgICAgIC8vIGdldCBhbGwgKHVuc29sdmVkKSBpbmRpY2VzIHRoYXQgZm9sbG93IHVzIGluIHRoZSBzYW1lIHJvdwogICAgICAgICAgICBmb3IgKGludCBjID0gY29sICsgMTsgYyA8IGRpbWVuc2lvbjsgYysrKSB7CiAgICAgICAgICAgICAgICAvLyByZXN0IG9mIHJvdy4KICAgICAgICAgICAgICAgIGlmIChhdmFpbGFibGVbcm93ICogZGltZW5zaW9uICsgY10ubGVuZ3RoID4gMSkgewogICAgICAgICAgICAgICAgICAgIC8vIG9ubHkgbmVlZCB0byB3b3JyeSBhYm91dCB1bnNvbHZlZCBmb2xsb3dlcnMuCiAgICAgICAgICAgICAgICAgICAgZm9sbHNbY250KytdID0gcm93ICogZGltZW5zaW9uICsgYzsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICAvLyBnZXQgYWxsICh1bnNvbHZlZCkgaW5kaWNlcyB0aGF0IGZvbGxvdyB1cyBpbiB0aGUgc2FtZSBjb2x1bW4KICAgICAgICAgICAgZm9yIChpbnQgciA9IHJvdyArIDE7IHIgPCBkaW1lbnNpb247IHIrKykgewogICAgICAgICAgICAgICAgaWYgKGF2YWlsYWJsZVtyICogZGltZW5zaW9uICsgY29sXS5sZW5ndGggPiAxKSB7CiAgICAgICAgICAgICAgICAgICAgLy8gb25seSBuZWVkIHRvIHdvcnJ5IGFib3V0IHVuc29sdmVkIGZvbGxvd2Vycy4KICAgICAgICAgICAgICAgICAgICBmb2xsc1tjbnQrK10gPSByICogZGltZW5zaW9uICsgY29sOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgaWYgKHIgPCByYikgewogICAgICAgICAgICAgICAgICAgIC8vIGlmIHdlIGhhdmUgbm90ICdlc2NhcGVkJyBvdXIgYmxvY2ssIHdlIGFsc28gZmluZCBvdGhlciBjZWxscyBpbgogICAgICAgICAgICAgICAgICAgIC8vIHRoZSBzYW1lIGJsb2NrLCBidXQgbm90IG91ciByb3cvY29sdW1uLgogICAgICAgICAgICAgICAgICAgIGZvciAoaW50IGMgPSBjb2wgKyAxOyBjIDwgY2I7IGMrKykgewogICAgICAgICAgICAgICAgICAgICAgICBpZiAoYXZhaWxhYmxlW3IgKiBkaW1lbnNpb24gKyBjXS5sZW5ndGggPiAxKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBvbmx5IG5lZWQgdG8gd29ycnkgYWJvdXQgdW5zb2x2ZWQgZm9sbG93ZXJzLgogICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9sbHNbY250KytdID0gciAqIGRpbWVuc2lvbiArIGM7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gcmV0dXJuIGp1c3QgdGhlIHZhbHVlcyB0aGF0IHdlcmUgbmVlZGVkIGFzIGZvbGxvd2Vycy4KICAgICAgICAgICAgcmV0dXJuIEFycmF5cy5jb3B5T2YoZm9sbHMsIGNudCk7CiAgICAgICAgfQogICAgCiAgICAgICAgLyoqCiAgICAgICAgICogQ29udmVydCB0aGUgdmFsaWQgY29tYmluYXRpb24gb2YgdmFsdWVzIGJhY2sgdG8gYSBzaW1wbGUgaW50W10gZ3JpZC4KICAgICAgICAgKiBAcGFyYW0gY29tYmluYXRpb24gdGhlIGNvbWJpbmF0aW9uIG9mIHVuc29sdmVkIHZhbHVlcyB0aGF0IGlzIGEgdmFsaWQgcHV6emxlLgogICAgICAgICAqIEByZXR1cm4gQSBTb2x1dGlvbiBvYmplY3QgcmVwcmVzZW50aW5nIHRoZSBzb2x1dGlvbi4KICAgICAgICAgKi8KICAgICAgICBwcml2YXRlIGludFtdW10gYnVpbGRTb2x1dGlvbihpbnRbXSBjb21iaW5hdGlvbikgewogICAgICAgICAgICBpbnRbXVtdIGdyaWQgPSBuZXcgaW50W2RpbWVuc2lvbl1bZGltZW5zaW9uXTsKICAgICAgICAgICAgZm9yIChpbnQgZiA9IDA7IGYgPCBjb21iaW5hdGlvbi5sZW5ndGg7IGYrKykgewogICAgICAgICAgICAgICAgZ3JpZFtmIC8gZGltZW5zaW9uXVtmICUgZGltZW5zaW9uXSA9IGF2YWlsYWJsZVtmXVtjb21iaW5hdGlvbltmXV07CiAgICAgICAgICAgIH0KICAgICAgICAgICAgLy8gZG91YmxlLWNoZWNrIHRoZSB2YWxpZGl0eSBvZiB0aGlzIHNvbHV0aW9uIChhbGwgc3Vkb2t1IGJhc2ljIHJ1bGVzIGFyZSBmb2xsb3dlZC4KICAgICAgICAgICAgLy8gdGhyb3dzIGV4Y2VwdGlvbiBpZiBub3QuCiAgICAvLyAgICAgICAgU3Vkb2t1UnVsZXMuaXNWYWxpZChncmlkKTsKICAgICAgICAgICAgLy8gbWVjaGFuaXNtIGZvciBwcmludGluZyBvdXQgYSBncmlkLgogICAgLy8gICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigiQnJ1dGVGb3JjZVJlY3Vyc2l2ZSBmb3VuZCBTb2x1dGlvbjpcbiIKICAgIC8vICAgICAgICAgICAgICAgICsgR3JpZFRvVGV4dC5kaXNwbGF5QXNTdHJpbmcoZ3JpZCkpOwogICAgICAgICAgICByZXR1cm4gZ3JpZDsKICAgICAgICB9CiAgICAKICAgIH0KICAgIAogICAgcHVibGljIHN0YXRpYyB2b2lkIG1haW4oU3RyaW5nW10gYXJncykgewogICAgICAgIGludFtdW11bXSBwdXp6bGUgPSBuZXcgaW50W11bXVtdIHsKICAgICAgICAgICAgICAgIHsgeyAxLCA0LCA1LCB9LHsgMiwgNSwgNiwgfSx7IDEsIDIsIDQsIDUsIDYsIH0seyA3LCB9LHsgMywgfSx7IDIsIDQsIDUsIDYsIH0seyAwLCAxLCA2LCB9LHsgMCwgMSwgNiwgfSx7IDgsIH0sICB9LAogICAgICAgICAgICAgICAgeyB7IDEsIDMsIDUsIH0seyAyLCAzLCA1LCA2LCA4LCB9LHsgMCwgfSx7IDIsIDUsIDYsIH0seyAyLCA1LCA2LCA4LCB9LHsgMiwgNSwgNiwgOCwgfSx7IDEsIDYsIDcsIH0seyAxLCA2LCA3LCB9LHsgNCwgfSwgIH0sCiAgICAgICAgICAgICAgICB7IHsgNywgfSx7IDYsIDgsIH0seyA0LCA2LCA4LCB9LHsgNCwgNiwgfSx7IDEsIH0seyAwLCB9LHsgMywgfSx7IDUsIH0seyAyLCB9LCAgfSwKICAgICAgICAgICAgICAgIHsgeyA2LCB9LHsgMCwgMiwgMywgNSwgfSx7IDcsIH0seyAwLCAxLCAyLCAzLCA0LCA1LCB9LHsgMiwgNCwgNSwgfSx7IDEsIDIsIDQsIDUsIH0seyAxLCA1LCB9LHsgOCwgfSx7IDEsIDMsIDUsIH0sICB9LAogICAgICAgICAgICAgICAgeyB7IDAsIDEsIDMsIDUsIH0seyAwLCAyLCAzLCA1LCA4LCB9LHsgMSwgMiwgNSwgOCwgfSx7IDAsIDEsIDIsIDMsIDQsIDUsIDYsIH0seyAyLCA0LCA1LCA2LCA4LCB9LHsgMSwgMiwgNCwgNSwgNiwgNywgOCwgfSx7IDEsIDUsIDYsIDcsIH0seyAxLCAzLCA0LCA2LCA3LCB9LHsgMSwgMywgNSwgNywgfSwgIH0sCiAgICAgICAgICAgICAgICB7IHsgMSwgMywgNSwgfSx7IDQsIH0seyAxLCA1LCA4LCB9LHsgMSwgMywgNSwgNiwgfSx7IDUsIDYsIDgsIH0seyAxLCA1LCA2LCA3LCA4LCB9LHsgMiwgfSx7IDEsIDMsIDYsIDcsIH0seyAwLCB9LCAgfSwKICAgICAgICAgICAgICAgIHsgeyA0LCA1LCB9LHsgMSwgfSx7IDMsIH0seyA4LCB9LHsgMCwgfSx7IDIsIDQsIDUsIH0seyA1LCA3LCB9LHsgMiwgNywgfSx7IDYsIH0sICB9LAogICAgICAgICAgICAgICAgeyB7IDgsIH0seyAwLCA1LCA2LCA3LCB9LHsgNSwgNiwgfSx7IDEsIDIsIDUsIDYsIH0seyAyLCA1LCA2LCB9LHsgMSwgMiwgNSwgNiwgfSx7IDQsIH0seyAwLCAxLCAyLCAzLCA3LCB9LHsgMSwgMywgNSwgNywgfSwgIH0sCiAgICAgICAgICAgICAgICB7IHsgMiwgfSx7IDAsIDUsIDYsIH0seyA0LCA1LCA2LCB9LHsgMSwgNCwgNSwgNiwgfSx7IDcsIH0seyAzLCB9LHsgMCwgMSwgNSwgOCwgfSx7IDAsIDEsIH0seyAxLCA1LCB9LCAgfSwKICAgICAgICB9OwoKICAgICAgICBSZWN1cnNpdmVCcnV0ZVNvbHZlciBzb2x2ZXIgPSBuZXcgUmVjdXJzaXZlQnJ1dGVTb2x2ZXIoOSwgcHV6emxlKTsKICAgICAgICBmb3IgKGludFtdW10gc29sIDogc29sdmVyLnNvbHZlKCkpIHsKICAgICAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCJTb2x1dGlvbjoiKTsKICAgICAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKGRpc3BsYXlBc1N0cmluZyhzb2wpKTsKICAgICAgICB9CiAgICB9CgogICAgcHJpdmF0ZSBzdGF0aWMgZmluYWwgY2hhcltdW10gc3ltYm9scyA9IHsKICAgICAgICAi4pWU4pWQ4pWk4pWm4pWXIi50b0NoYXJBcnJheSgpLAogICAgICAgICLilZEg4pSC4pWR4pWRIi50b0NoYXJBcnJheSgpLAogICAgICAgICLilZ/ilIDilLzilavilaIiLnRvQ2hhckFycmF5KCksCiAgICAgICAgIuKVoOKVkOKVquKVrOKVoyIudG9DaGFyQXJyYXkoKSwKICAgICAgICAi4pWa4pWQ4pWn4pWp4pWdIi50b0NoYXJBcnJheSgpLAogICAgfTsKICAgIAogICAgcHJpdmF0ZSBzdGF0aWMgZmluYWwgY2hhcltdIERJR0lUQ0hBUlMgPSAiMTIzNDU2Nzg5QUJDRkVER0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5eiIudG9DaGFyQXJyYXkoKTsKICAgIAogICAgcHVibGljIHN0YXRpYyBmaW5hbCBjaGFyIGdldFN1ZG9rdURpZ2l0KGZpbmFsIGludCB2YWx1ZSkgewogICAgICAgIGlmICh2YWx1ZSA8IDApIHsKICAgICAgICAgICAgcmV0dXJuICcgJzsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIERJR0lUQ0hBUlNbdmFsdWVdOwogICAgfQogICAgCiAgICBwdWJsaWMgc3RhdGljIGZpbmFsIFN0cmluZyBkaXNwbGF5QXNTdHJpbmcoaW50W11bXWRhdGEpIHsKICAgICAgICByZXR1cm4gYnVpbGRTdHJpbmdGb3JHcmlkKGRhdGEubGVuZ3RoLCAoaW50KU1hdGguc3FydChkYXRhLmxlbmd0aCksIGRhdGEpOwogICAgfQogICAgCiAgICBwcml2YXRlIHN0YXRpYyBmaW5hbCBTdHJpbmcgYnVpbGRTdHJpbmdGb3JHcmlkKGZpbmFsIGludCBkaW1lbnNpb24sIGZpbmFsIGludCBibG9ja3NpemUsIGZpbmFsIGludFtdW11yb3dzKSB7CiAgICAgICAgZmluYWwgU3RyaW5nQnVpbGRlciBzYiA9IG5ldyBTdHJpbmdCdWlsZGVyKCk7CiAgICAgICAgZm9yIChpbnQgciA9IDA7IHIgPCBkaW1lbnNpb247IHIrKykgewogICAgICAgICAgICBpZiAociA9PSAwKSB7CiAgICAgICAgICAgICAgICBzYi5hcHBlbmQocHJpbnRTeW1ib2xMaW5lKGRpbWVuc2lvbiwgYmxvY2tzaXplLCBudWxsLCBzeW1ib2xzWzBdKSk7CiAgICAgICAgICAgIH0gZWxzZSBpZiAociAlIGJsb2Nrc2l6ZSA9PSAwKSB7CiAgICAgICAgICAgICAgICBzYi5hcHBlbmQocHJpbnRTeW1ib2xMaW5lKGRpbWVuc2lvbiwgYmxvY2tzaXplLCBudWxsLCBzeW1ib2xzWzNdKSk7CiAgICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgICAgICBzYi5hcHBlbmQocHJpbnRTeW1ib2xMaW5lKGRpbWVuc2lvbiwgYmxvY2tzaXplLCBudWxsLCBzeW1ib2xzWzJdKSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgc2IuYXBwZW5kKHByaW50U3ltYm9sTGluZShkaW1lbnNpb24sIGJsb2Nrc2l6ZSwgcm93c1tyXSwgc3ltYm9sc1sxXSkpOwogICAgICAgIH0KICAgICAgICBzYi5hcHBlbmQocHJpbnRTeW1ib2xMaW5lKGRpbWVuc2lvbiwgYmxvY2tzaXplLCBudWxsLCBzeW1ib2xzWzRdKSk7CiAgICAgICAgcmV0dXJuIHNiLnRvU3RyaW5nKCk7CiAgICB9CiAgICAKICAgIHByaXZhdGUgc3RhdGljIFN0cmluZyBwcmludFN5bWJvbExpbmUoaW50IGRpbWVuc2lvbiwgaW50IGJsb2Nrc2l6ZSwgaW50W10gdmFsdWVzLCBjaGFyW10gc3ltYm9scykgewogICAgICAgIFN0cmluZ0J1aWxkZXIgc2IgPSBuZXcgU3RyaW5nQnVpbGRlcigpOwogICAgICAgIHNiLmFwcGVuZChzeW1ib2xzWzBdKTsKICAgICAgICBpbnQgdmMgPSAwOwogICAgICAgIGZvciAoaW50IGIgPSAwOyBiIDwgYmxvY2tzaXplOyBiKyspIHsKICAgICAgICAgICAgZm9yIChpbnQgYyA9IDA7IGMgPCBibG9ja3NpemU7IGMrKykgewogICAgICAgICAgICAgICAgaWYgKHZhbHVlcyA9PSBudWxsKSB7CiAgICAgICAgICAgICAgICAgICAgc2IuYXBwZW5kKHN5bWJvbHNbMV0pLmFwcGVuZChzeW1ib2xzWzFdKS5hcHBlbmQoc3ltYm9sc1sxXSkuYXBwZW5kKHN5bWJvbHNbMl0pOwogICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICBmaW5hbCBpbnQgdmFsID0gdmFsdWVzW3ZjKytdOwogICAgICAgICAgICAgICAgICAgIGNoYXIgY2ggPSBnZXRTdWRva3VEaWdpdCh2YWwpOwogICAgICAgICAgICAgICAgICAgIHNiLmFwcGVuZChzeW1ib2xzWzFdKS5hcHBlbmQoY2gpLmFwcGVuZChzeW1ib2xzWzFdKS5hcHBlbmQoc3ltYm9sc1syXSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgc2Iuc2V0Q2hhckF0KHNiLmxlbmd0aCgpIC0gMSwgc3ltYm9sc1szXSk7CiAgICAgICAgfQogICAgICAgIHNiLnNldENoYXJBdChzYi5sZW5ndGgoKSAtIDEsIHN5bWJvbHNbNF0pOwogICAgICAgIHNiLmFwcGVuZCgiXG4iKTsKICAgICAgICByZXR1cm4gc2IudG9TdHJpbmcoKTsKICAgIH0KfQo=