/**
|
* @license
|
* Copyright 2022 Google LLC. All Rights Reserved.
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
* =============================================================================
|
*/
|
import { util } from '@tensorflow/tfjs-core';
|
function validateIndices(indices, indicesShape, numParams) {
|
indices.forEach((index, i) => {
|
if (index < 0 || index >= numParams) {
|
const locString = util.indexToLoc(i, indicesShape.length, util.computeStrides(indicesShape))
|
.join(',');
|
throw new Error(`indices[${locString}] = ${index} is not in [0, ${numParams})`);
|
}
|
});
|
}
|
function validateSplits(paramsNestedSplits, numParamsDenseValues) {
|
// Validate
|
for (let dim = 0; dim < paramsNestedSplits.length; ++dim) {
|
const splits = paramsNestedSplits[dim];
|
const lastSplit = (dim === paramsNestedSplits.length - 1) ?
|
numParamsDenseValues :
|
paramsNestedSplits[dim + 1].length;
|
if (splits.length === 0) {
|
throw new Error('Ragged splits may not be empty');
|
}
|
if (splits[0] < 0) {
|
throw new Error('Ragged splits must be non-negative');
|
}
|
if (splits[splits.length - 1] > lastSplit) {
|
throw new Error('Ragged splits must not point past values');
|
}
|
for (let i = 1; i < splits.length; ++i) {
|
if (splits[i - 1] > splits[i]) {
|
throw new Error('Ragged splits must be sorted in ascending order');
|
}
|
}
|
}
|
}
|
// Construct the `splits` output tensors, encoded using a nested vector.
|
// Also find the slices of values that need to be copied, and store them
|
// in `valueSlices`. The total number of values that will be copied (which
|
// we need for allocating the output values tensor) is stored in `numValues`.
|
function makeSplits(indices, indicesShape, paramsNestedSplits, numParamsDenseValues) {
|
const valueSlices = [];
|
let numValues = 0;
|
const numSplits = indicesShape.length - 1 + paramsNestedSplits.length;
|
const outSplits = new Array(numSplits).fill(null).map(() => [0]);
|
validateSplits(paramsNestedSplits, numParamsDenseValues);
|
// Add `splits` that come from all but the last dimension of the dense
|
// Tensor `indices`. In particular, for each dimension D, we add a
|
// splits tensor whose values are:
|
// range(reduceProd(splits.shape[:D]) + 1) * splits.shape[D+1]
|
// E.g., if indices.shape=[2, 3, 4] then we will add splits tensors:
|
// [0, 3, 6] # length=2+1, stride=3
|
// [0, 4, 8, 12, 16, 20, 24] # length=2*3+1, stride=4
|
let nrows = 1;
|
for (let dim = 0; dim < indicesShape.length - 1; ++dim) {
|
nrows *= indicesShape[dim];
|
const rowLength = indicesShape[dim + 1];
|
for (let i = 1; i < nrows + 1; ++i) {
|
outSplits[dim].push(i * rowLength);
|
}
|
}
|
// Add `splits` that come from `paramsNestedSplits`. Starting with the
|
// outermost ragged dimension (i.e., the first `splits` tensor), we work
|
// our way in, finding the range of values that should be copied. As we
|
// go, we update the output `splits` for each dimension with the appropriate
|
// values. In particular, the *lengths* of the slices from `param_splits`
|
// should be copied to generate corresponding slice lengths in the output
|
// splits. E.g., if we are copying a ragged row with length 4, then we
|
// should add a new split point to outSplits that is 4 greater than the
|
// previous split point in outSplits.
|
for (let i = 0; i < indices.length; ++i) {
|
let start = indices[i];
|
let limit = indices[i] + 1;
|
// Copy splits.
|
for (let dim = 0; dim < paramsNestedSplits.length; ++dim) {
|
const splits = paramsNestedSplits[dim];
|
const outDim = dim + indicesShape.length - 1;
|
if (outDim >= 0) {
|
const outSplitsOutDim = outSplits[outDim];
|
const delta = outSplitsOutDim[outSplitsOutDim.length - 1] - splits[start];
|
for (let j = start; j < limit; ++j) {
|
outSplits[outDim].push(splits[j + 1] + delta);
|
}
|
}
|
start = splits[start];
|
limit = splits[limit];
|
}
|
if (limit !== start) {
|
valueSlices.push([start, limit]);
|
numValues += limit - start;
|
}
|
}
|
return { outSplits, valueSlices, numValues };
|
}
|
function getSplits(outSplits) {
|
const splitsOut = [];
|
for (let i = 0; i < outSplits.length; ++i) {
|
const numSplits = outSplits[i].length;
|
const splits = util.getArrayFromDType('int32', numSplits);
|
splitsOut.push(splits);
|
outSplits[i].forEach((value, j) => splits[j] = value);
|
}
|
return splitsOut;
|
}
|
function computeFlatOuterDims(orig, numOutDims) {
|
const outDims = orig.slice(0, numOutDims);
|
while (outDims.length < numOutDims) {
|
outDims.push(1);
|
}
|
for (let inDim = numOutDims; inDim < orig.length; inDim++) {
|
outDims[numOutDims - 1] *= orig[inDim];
|
}
|
return outDims;
|
}
|
// For each slice in `(start, limit)` in `valueSlices`, append
|
// `paramsDenseValues[start,...,limit] to `values`. `valueSize` indicates
|
// the number of scalars contained in each value paramsDenseValues[i].
|
function writeValueSlices(paramsDenseValues, paramsDenseValuesShape, valueSlices, valueSize, values, valuesShape) {
|
const denseM = computeFlatOuterDims(paramsDenseValuesShape, 2)[1];
|
const valuesM = computeFlatOuterDims(valuesShape, 2)[1];
|
let outPos = 0;
|
for (const slice of valueSlices) {
|
for (let i = slice[0]; i < slice[1]; ++i) {
|
for (let j = 0; j < valueSize; ++j) {
|
values[outPos * valuesM + j] = paramsDenseValues[i * denseM + j];
|
}
|
++outPos;
|
}
|
}
|
}
|
function getValues(paramsDenseValues, paramsDenseValuesShape, paramsDenseValuesDType, valueSlices, numValues) {
|
const valuesShape = paramsDenseValuesShape.slice();
|
valuesShape[0] = numValues;
|
const valuesOut = util.getArrayFromDType(paramsDenseValuesDType, util.sizeFromShape(valuesShape));
|
const numElements = paramsDenseValues.length;
|
const valueSize = numElements === 0 ? 0 : (numElements / paramsDenseValuesShape[0]);
|
writeValueSlices(paramsDenseValues, paramsDenseValuesShape, valueSlices, valueSize, valuesOut, valuesShape);
|
return [valuesOut, valuesShape];
|
}
|
export function raggedGatherImpl(paramsNestedSplits, paramsNestedSplitsShapes, paramsDenseValues, paramsDenseValuesShape, paramsDenseValuesDType, indices, indicesShape, outputRaggedRank) {
|
if (paramsNestedSplits.length === 0) {
|
throw new Error('paramsNestedSplits must be non empty');
|
}
|
if (paramsNestedSplitsShapes[0].length === 0) {
|
throw new Error('Split tensors must not be scalars');
|
}
|
const numParams = paramsNestedSplitsShapes[0][0] - 1;
|
validateIndices(indices, indicesShape, numParams);
|
if (paramsDenseValuesShape.length === 0) {
|
throw new Error('params.rank must be nonzero');
|
}
|
const numParamsDenseValues = paramsDenseValuesShape[0];
|
// Calculate the `splits`, and store the value slices that we need to
|
// copy in `valueSlices`.
|
const { outSplits, valueSlices, numValues } = makeSplits(indices, indicesShape, paramsNestedSplits, numParamsDenseValues);
|
// Write the output tensors.
|
const outputNestedSplits = getSplits(outSplits);
|
const outputDenseValues = getValues(paramsDenseValues, paramsDenseValuesShape, paramsDenseValuesDType, valueSlices, numValues);
|
return [outputNestedSplits, outputDenseValues[0], outputDenseValues[1]];
|
}
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmFnZ2VkR2F0aGVyX2ltcGwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi90ZmpzLWJhY2tlbmQtY3B1L3NyYy9rZXJuZWxzL1JhZ2dlZEdhdGhlcl9pbXBsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUVILE9BQU8sRUFBdUIsSUFBSSxFQUFDLE1BQU0sdUJBQXVCLENBQUM7QUFFakUsU0FBUyxlQUFlLENBQ3BCLE9BQW1CLEVBQUUsWUFBc0IsRUFBRSxTQUFpQjtJQUNoRSxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsS0FBYSxFQUFFLENBQVMsRUFBRSxFQUFFO1FBQzNDLElBQUksS0FBSyxHQUFHLENBQUMsSUFBSSxLQUFLLElBQUksU0FBUyxFQUFFO1lBQ25DLE1BQU0sU0FBUyxHQUNYLElBQUksQ0FBQyxVQUFVLENBQ1AsQ0FBQyxFQUFFLFlBQVksQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLGNBQWMsQ0FBQyxZQUFZLENBQUMsQ0FBQztpQkFDN0QsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ25CLE1BQU0sSUFBSSxLQUFLLENBQ1gsV0FBVyxTQUFTLE9BQU8sS0FBSyxrQkFBa0IsU0FBUyxHQUFHLENBQUMsQ0FBQztTQUNyRTtJQUNILENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVELFNBQVMsY0FBYyxDQUNuQixrQkFBZ0MsRUFBRSxvQkFBNEI7SUFDaEUsV0FBVztJQUNYLEtBQUssSUFBSSxHQUFHLEdBQUcsQ0FBQyxFQUFFLEdBQUcsR0FBRyxrQkFBa0IsQ0FBQyxNQUFNLEVBQUUsRUFBRSxHQUFHLEVBQUU7UUFDeEQsTUFBTSxNQUFNLEdBQUcsa0JBQWtCLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDdkMsTUFBTSxTQUFTLEdBQUcsQ0FBQyxHQUFHLEtBQUssa0JBQWtCLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDdkQs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TUFBTSxrQkFBa0IsR0FBRyxTQUFTLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDaEQsTUFBTSxpQkFBaUIsR0FBRyxTQUFTLENBQy9CLGlCQUFpQixFQUFFLHNCQUFzQixFQUFFLHNCQUFzQixFQUNqRSxXQUFXLEVBQUUsU0FBUyxDQUFDLENBQUM7SUFFNUIsT0FBTyxDQUFDLGtCQUFrQixFQUFFLGlCQUFpQixDQUFDLENBQUMsQ0FBQyxFQUFFLGlCQUFpQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDMUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCAyMDIyIEdvb2dsZSBMTEMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKi9cblxuaW1wb3J0IHtEYXRhVHlwZSwgVHlwZWRBcnJheSwgdXRpbH0gZnJvbSAnQHRlbnNvcmZsb3cvdGZqcy1jb3JlJztcblxuZnVuY3Rpb24gdmFsaWRhdGVJbmRpY2VzKFxuICAgIGluZGljZXM6IFR5cGVkQXJyYXksIGluZGljZXNTaGFwZTogbnVtYmVyW10sIG51bVBhcmFtczogbnVtYmVyKSB7XG4gIGluZGljZXMuZm9yRWFjaCgoaW5kZXg6IG51bWJlciwgaTogbnVtYmVyKSA9PiB7XG4gICAgaWYgKGluZGV4IDwgMCB8fCBpbmRleCA+PSBudW1QYXJhbXMpIHtcbiAgICAgIGNvbnN0IGxvY1N0cmluZyA9XG4gICAgICAgICAgdXRpbC5pbmRleFRvTG9jKFxuICAgICAgICAgICAgICAgICAgaSwgaW5kaWNlc1NoYXBlLmxlbmd0aCwgdXRpbC5jb21wdXRlU3RyaWRlcyhpbmRpY2VzU2hhcGUpKVxuICAgICAgICAgICAgICAuam9pbignLCcpO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIGBpbmRpY2VzWyR7bG9jU3RyaW5nfV0gPSAke2luZGV4fSBpcyBub3QgaW4gWzAsICR7bnVtUGFyYW1zfSlgKTtcbiAgICB9XG4gIH0pO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZVNwbGl0cyhcbiAgICBwYXJhbXNOZXN0ZWRTcGxpdHM6IFR5cGVkQXJyYXlbXSwgbnVtUGFyYW1zRGVuc2VWYWx1ZXM6IG51bWJlcikge1xuICAvLyBWYWxpZGF0ZVxuICBmb3IgKGxldCBkaW0gPSAwOyBkaW0gPCBwYXJhbXNOZXN0ZWRTcGxpdHMubGVuZ3RoOyArK2RpbSkge1xuICAgIGNvbnN0IHNwbGl0cyA9IHBhcmFtc05lc3RlZFNwbGl0c1tkaW1dO1xuICAgIGNvbnN0IGxhc3RTcGxpdCA9IChkaW0gPT09IHBhcmFtc05lc3RlZFNwbGl0cy5sZW5ndGggLSAxKSA/XG4gICAgICAgIG51bVBhcmFtc0RlbnNlVmFsdWVzIDpcbiAgICAgICAgcGFyYW1zTmVzdGVkU3BsaXRzW2RpbSArIDFdLmxlbmd0aDtcbiAgICBpZiAoc3BsaXRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdSYWdnZWQgc3BsaXRzIG1heSBub3QgYmUgZW1wdHknKTtcbiAgICB9XG4gICAgaWYgKHNwbGl0c1swXSA8IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignUmFnZ2VkIHNwbGl0cyBtdXN0IGJlIG5vbi1uZWdhdGl2ZScpO1xuICAgIH1cbiAgICBpZiAoc3BsaXRzW3NwbGl0cy5sZW5ndGggLSAxXSA+IGxhc3RTcGxpdCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdSYWdnZWQgc3BsaXRzIG11c3Qgbm90IHBvaW50IHBhc3QgdmFsdWVzJyk7XG4gICAgfVxuICAgIGZvciAobGV0IGkgPSAxOyBpIDwgc3BsaXRzLmxlbmd0aDsgKytpKSB7XG4gICAgICBpZiAoc3BsaXRzW2kgLSAxXSA+IHNwbGl0c1tpXSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1JhZ2dlZCBzcGxpdHMgbXVzdCBiZSBzb3J0ZWQgaW4gYXNjZW5kaW5nIG9yZGVyJyk7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbi8vIENvbnN0cnVjdCB0aGUgYHNwbGl0c2Agb3V0cHV0IHRlbnNvcnMsIGVuY29kZWQgdXNpbmcgYSBuZXN0ZWQgdmVjdG9yLlxuLy8gQWxzbyBmaW5kIHRoZSBzbGljZXMgb2YgdmFsdWVzIHRoYXQgbmVlZCB0byBiZSBjb3BpZWQsIGFuZCBzdG9yZSB0aGVtXG4vLyBpbiBgdmFsdWVTbGljZXNgLiAgVGhlIHRvdGFsIG51bWJlciBvZiB2YWx1ZXMgdGhhdCB3aWxsIGJlIGNvcGllZCAod2hpY2hcbi8vIHdlIG5lZWQgZm9yIGFsbG9jYXRpbmcgdGhlIG91dHB1dCB2YWx1ZXMgdGVuc29yKSBpcyBzdG9yZWQgaW4gYG51bVZhbHVlc2AuXG5mdW5jdGlvbiBtYWtlU3BsaXRzKFxuICAgIGluZGljZXM6IFR5cGVkQXJyYXksIGluZGljZXNTaGFwZTogbnVtYmVyW10sXG4gICAgcGFyYW1zTmVzdGVkU3BsaXRzOiBUeXBlZEFycmF5W10sIG51bVBhcmFtc0RlbnNlVmFsdWVzOiBudW1iZXIpIHtcbiAgY29uc3QgdmFsdWVTbGljZXM6IEFycmF5PFtudW1iZXIsIG51bWJlcl0+ID0gW107XG4gIGxldCBudW1WYWx1ZXMgPSAwO1xuXG4gIGNvbnN0IG51bVNwbGl0cyA9IGluZGljZXNTaGFwZS5sZW5ndGggLSAxICsgcGFyYW1zTmVzdGVkU3BsaXRzLmxlbmd0aDtcbiAgY29uc3Qgb3V0U3BsaXRzID0gbmV3IEFycmF5KG51bVNwbGl0cykuZmlsbChudWxsKS5tYXAoKCkgPT4gWzBdKTtcblxuICB2YWxpZGF0ZVNwbGl0cyhwYXJhbXNOZXN0ZWRTcGxpdHMsIG51bVBhcmFtc0RlbnNlVmFsdWVzKTtcblxuICAvLyBBZGQgYHNwbGl0c2AgdGhhdCBjb21lIGZyb20gYWxsIGJ1dCB0aGUgbGFzdCBkaW1lbnNpb24gb2YgdGhlIGRlbnNlXG4gIC8vIFRlbnNvciBgaW5kaWNlc2AuICBJbiBwYXJ0aWN1bGFyLCBmb3IgZWFjaCBkaW1lbnNpb24gRCwgd2UgYWRkIGFcbiAgLy8gc3BsaXRzIHRlbnNvciB3aG9zZSB2YWx1ZXMgYXJlOlxuICAvLyAgIHJhbmdlKHJlZHVjZVByb2Qoc3BsaXRzLnNoYXBlWzpEXSkgKyAxKSAqIHNwbGl0cy5zaGFwZVtEKzFdXG4gIC8vIEUuZy4sIGlmIGluZGljZXMuc2hhcGU9WzIsIDMsIDRdIHRoZW4gd2Ugd2lsbCBhZGQgc3BsaXRzIHRlbnNvcnM6XG4gIC8vICAgWzAsIDMsIDZdICAgICAgICAgICAgICAgICAgICAjIGxlbmd0aD0yKzEsIHN0cmlkZT0zXG4gIC8vICAgWzAsIDQsIDgsIDEyLCAxNiwgMjAsIDI0XSAgICAjIGxlbmd0aD0yKjMrMSwgc3RyaWRlPTRcbiAgbGV0IG5yb3dzID0gMTtcbiAgZm9yIChsZXQgZGltID0gMDsgZGltIDwgaW5kaWNlc1NoYXBlLmxlbmd0aCAtIDE7ICsrZGltKSB7XG4gICAgbnJvd3MgKj0gaW5kaWNlc1NoYXBlW2RpbV07XG4gICAgY29uc3Qgcm93TGVuZ3RoID0gaW5kaWNlc1NoYXBlW2RpbSArIDFdO1xuICAgIGZvciAobGV0IGkgPSAxOyBpIDwgbnJvd3MgKyAxOyArK2kpIHtcbiAgICAgIG91dFNwbGl0c1tkaW1dLnB1c2goaSAqIHJvd0xlbmd0aCk7XG4gICAgfVxuICB9XG5cbiAgLy8gQWRkIGBzcGxpdHNgIHRoYXQgY29tZSBmcm9tIGBwYXJhbXNOZXN0ZWRTcGxpdHNgLiAgU3RhcnRpbmcgd2l0aCB0aGVcbiAgLy8gb3V0ZXJtb3N0IHJhZ2dlZCBkaW1lbnNpb24gKGkuZS4sIHRoZSBmaXJzdCBgc3BsaXRzYCB0ZW5zb3IpLCB3ZSB3b3JrXG4gIC8vIG91ciB3YXkgaW4sIGZpbmRpbmcgdGhlIHJhbmdlIG9mIHZhbHVlcyB0aGF0IHNob3VsZCBiZSBjb3BpZWQuICBBcyB3ZVxuICAvLyBnbywgd2UgdXBkYXRlIHRoZSBvdXRwdXQgYHNwbGl0c2AgZm9yIGVhY2ggZGltZW5zaW9uIHdpdGggdGhlIGFwcHJvcHJpYXRlXG4gIC8vIHZhbHVlcy4gIEluIHBhcnRpY3VsYXIsIHRoZSAqbGVuZ3Rocyogb2YgdGhlIHNsaWNlcyBmcm9tIGBwYXJhbV9zcGxpdHNgXG4gIC8vIHNob3VsZCBiZSBjb3BpZWQgdG8gZ2VuZXJhdGUgY29ycmVzcG9uZGluZyBzbGljZSBsZW5ndGhzIGluIHRoZSBvdXRwdXRcbiAgLy8gc3BsaXRzLiAgRS5nLiwgaWYgd2UgYXJlIGNvcHlpbmcgYSByYWdnZWQgcm93IHdpdGggbGVuZ3RoIDQsIHRoZW4gd2VcbiAgLy8gc2hvdWxkIGFkZCBhIG5ldyBzcGxpdCBwb2ludCB0byBvdXRTcGxpdHMgdGhhdCBpcyA0IGdyZWF0ZXIgdGhhbiB0aGVcbiAgLy8gcHJldmlvdXMgc3BsaXQgcG9pbnQgaW4gb3V0U3BsaXRzLlxuICBmb3IgKGxldCBpID0gMDsgaSA8IGluZGljZXMubGVuZ3RoOyArK2kpIHtcbiAgICBsZXQgc3RhcnQgPSBpbmRpY2VzW2ldO1xuICAgIGxldCBsaW1pdCA9IGluZGljZXNbaV0gKyAxO1xuXG4gICAgLy8gQ29weSBzcGxpdHMuXG4gICAgZm9yIChsZXQgZGltID0gMDsgZGltIDwgcGFyYW1zTmVzdGVkU3BsaXRzLmxlbmd0aDsgKytkaW0pIHtcbiAgICAgIGNvbnN0IHNwbGl0cyA9IHBhcmFtc05lc3RlZFNwbGl0c1tkaW1dO1xuICAgICAgY29uc3Qgb3V0RGltID0gZGltICsgaW5kaWNlc1NoYXBlLmxlbmd0aCAtIDE7XG4gICAgICBpZiAob3V0RGltID49IDApIHtcbiAgICAgICAgY29uc3Qgb3V0U3BsaXRzT3V0RGltID0gb3V0U3BsaXRzW291dERpbV07XG4gICAgICAgIGNvbnN0IGRlbHRhID1cbiAgICAgICAgICAgIG91dFNwbGl0c091dERpbVtvdXRTcGxpdHNPdXREaW0ubGVuZ3RoIC0gMV0gLSBzcGxpdHNbc3RhcnRdO1xuICAgICAgICBmb3IgKGxldCBqID0gc3RhcnQ7IGogPCBsaW1pdDsgKytqKSB7XG4gICAgICAgICAgb3V0U3BsaXRzW291dERpbV0ucHVzaChzcGxpdHNbaiArIDFdICsgZGVsdGEpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBzdGFydCA9IHNwbGl0c1tzdGFydF07XG4gICAgICBsaW1pdCA9IHNwbGl0c1tsaW1pdF07XG4gICAgfVxuICAgIGlmIChsaW1pdCAhPT0gc3RhcnQpIHtcbiAgICAgIHZhbHVlU2xpY2VzLnB1c2goW3N0YXJ0LCBsaW1pdF0pO1xuICAgICAgbnVtVmFsdWVzICs9IGxpbWl0IC0gc3RhcnQ7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHtvdXRTcGxpdHMsIHZhbHVlU2xpY2VzLCBudW1WYWx1ZXN9O1xufVxuXG5mdW5jdGlvbiBnZXRTcGxpdHMob3V0U3BsaXRzOiBudW1iZXJbXVtdKSB7XG4gIGNvbnN0IHNwbGl0c091dDogVHlwZWRBcnJheVtdID0gW107XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgb3V0U3BsaXRzLmxlbmd0aDsgKytpKSB7XG4gICAgY29uc3QgbnVtU3BsaXRzID0gb3V0U3BsaXRzW2ldLmxlbmd0aDtcbiAgICBjb25zdCBzcGxpdHMgPSB1dGlsLmdldEFycmF5RnJvbURUeXBlKCdpbnQzMicsIG51bVNwbGl0cykgYXMgVHlwZWRBcnJheTtcbiAgICBzcGxpdHNPdXQucHVzaChzcGxpdHMpO1xuXG4gICAgb3V0U3BsaXRzW2ldLmZvckVhY2goKHZhbHVlLCBqOiBudW1iZXIpID0+IHNwbGl0c1tqXSA9IHZhbHVlKTtcbiAgfVxuXG4gIHJldHVybiBzcGxpdHNPdXQ7XG59XG5cbmZ1bmN0aW9uIGNvbXB1dGVGbGF0T3V0ZXJEaW1zKG9yaWc6IG51bWJlcltdLCBudW1PdXREaW1zOiBudW1iZXIpIHtcbiAgY29uc3Qgb3V0RGltcyA9IG9yaWcuc2xpY2UoMCwgbnVtT3V0RGltcyk7XG4gIHdoaWxlIChvdXREaW1zLmxlbmd0aCA8IG51bU91dERpbXMpIHtcbiAgICBvdXREaW1zLnB1c2goMSk7XG4gIH1cblxuICBmb3IgKGxldCBpbkRpbSA9IG51bU91dERpbXM7IGluRGltIDwgb3JpZy5sZW5ndGg7IGluRGltKyspIHtcbiAgICBvdXREaW1zW251bU91dERpbXMgLSAxXSAqPSBvcmlnW2luRGltXTtcbiAgfVxuXG4gIHJldHVybiBvdXREaW1zO1xufVxuLy8gRm9yIGVhY2ggc2xpY2UgaW4gYChzdGFydCwgbGltaXQpYCBpbiBgdmFsdWVTbGljZXNgLCBhcHBlbmRcbi8vIGBwYXJhbXNEZW5zZVZhbHVlc1tzdGFydCwuLi4sbGltaXRdIHRvIGB2YWx1ZXNgLiAgYHZhbHVlU2l6ZWAgaW5kaWNhdGVzXG4vLyB0aGUgbnVtYmVyIG9mIHNjYWxhcnMgY29udGFpbmVkIGluIGVhY2ggdmFsdWUgcGFyYW1zRGVuc2VWYWx1ZXNbaV0uXG5mdW5jdGlvbiB3cml0ZVZhbHVlU2xpY2VzKFxuICAgIHBhcmFtc0RlbnNlVmFsdWVzOiBUeXBlZEFycmF5LCBwYXJhbXNEZW5zZVZhbHVlc1NoYXBlOiBudW1iZXJbXSxcbiAgICB2YWx1ZVNsaWNlczogQXJyYXk8W251bWJlciwgbnVtYmVyXT4sIHZhbHVlU2l6ZTogbnVtYmVyLCB2YWx1ZXM6IFR5cGVkQXJyYXksXG4gICAgdmFsdWVzU2hhcGU6IG51bWJlcltdKSB7XG4gIGNvbnN0IGRlbnNlTSA9IGNvbXB1dGVGbGF0T3V0ZXJEaW1zKHBhcmFtc0RlbnNlVmFsdWVzU2hhcGUsIDIpWzFdO1xuICBjb25zdCB2YWx1ZXNNID0gY29tcHV0ZUZsYXRPdXRlckRpbXModmFsdWVzU2hhcGUsIDIpWzFdO1xuXG4gIGxldCBvdXRQb3MgPSAwO1xuICBmb3IgKGNvbnN0IHNsaWNlIG9mIHZhbHVlU2xpY2VzKSB7XG4gICAgZm9yIChsZXQgaSA9IHNsaWNlWzBdOyBpIDwgc2xpY2VbMV07ICsraSkge1xuICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCB2YWx1ZVNpemU7ICsraikge1xuICAgICAgICB2YWx1ZXNbb3V0UG9zICogdmFsdWVzTSArIGpdID0gcGFyYW1zRGVuc2VWYWx1ZXNbaSAqIGRlbnNlTSArIGpdO1xuICAgICAgfVxuICAgICAgKytvdXRQb3M7XG4gICAgfVxuICB9XG59XG5cbmZ1bmN0aW9uIGdldFZhbHVlcyhcbiAgICBwYXJhbXNEZW5zZVZhbHVlczogVHlwZWRBcnJheSwgcGFyYW1zRGVuc2VWYWx1ZXNTaGFwZTogbnVtYmVyW10sXG4gICAgcGFyYW1zRGVuc2VWYWx1ZXNEVHlwZTogRGF0YVR5cGUsIHZhbHVlU2xpY2VzOiBBcnJheTxbbnVtYmVyLCBudW1iZXJdPixcbiAgICBudW1WYWx1ZXM6IG51bWJlcik6IFtUeXBlZEFycmF5LCBudW1iZXJbXV0ge1xuICBjb25zdCB2YWx1ZXNTaGFwZSA9IHBhcmFtc0RlbnNlVmFsdWVzU2hhcGUuc2xpY2UoKTtcbiAgdmFsdWVzU2hhcGVbMF0gPSBudW1WYWx1ZXM7XG5cbiAgY29uc3QgdmFsdWVzT3V0ID0gdXRpbC5nZXRBcnJheUZyb21EVHlwZShcbiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtc0RlbnNlVmFsdWVzRFR5cGUsXG4gICAgICAgICAgICAgICAgICAgICAgICB1dGlsLnNpemVGcm9tU2hhcGUodmFsdWVzU2hhcGUpKSBhcyBUeXBlZEFycmF5O1xuXG4gIGNvbnN0IG51bUVsZW1lbnRzID0gcGFyYW1zRGVuc2VWYWx1ZXMubGVuZ3RoO1xuICBjb25zdCB2YWx1ZVNpemUgPVxuICAgICAgbnVtRWxlbWVudHMgPT09IDAgPyAwIDogKG51bUVsZW1lbnRzIC8gcGFyYW1zRGVuc2VWYWx1ZXNTaGFwZVswXSk7XG4gIHdyaXRlVmFsdWVTbGljZXMoXG4gICAgICBwYXJhbXNEZW5zZVZhbHVlcywgcGFyYW1zRGVuc2VWYWx1ZXNTaGFwZSwgdmFsdWVTbGljZXMsIHZhbHVlU2l6ZSxcbiAgICAgIHZhbHVlc091dCwgdmFsdWVzU2hhcGUpO1xuXG4gIHJldHVybiBbdmFsdWVzT3V0LCB2YWx1ZXNTaGFwZV07XG59XG5leHBvcnQgZnVuY3Rpb24gcmFnZ2VkR2F0aGVySW1wbChcbiAgICBwYXJhbXNOZXN0ZWRTcGxpdHM6IFR5cGVkQXJyYXlbXSwgcGFyYW1zTmVzdGVkU3BsaXRzU2hhcGVzOiBudW1iZXJbXVtdLFxuICAgIHBhcmFtc0RlbnNlVmFsdWVzOiBUeXBlZEFycmF5LCBwYXJhbXNEZW5zZVZhbHVlc1NoYXBlOiBudW1iZXJbXSxcbiAgICBwYXJhbXNEZW5zZVZhbHVlc0RUeXBlOiBEYXRhVHlwZSwgaW5kaWNlczogVHlwZWRBcnJheSxcbiAgICBpbmRpY2VzU2hhcGU6IG51bWJlcltdLFxuICAgIG91dHB1dFJhZ2dlZFJhbms6IG51bWJlcik6IFtUeXBlZEFycmF5W10sIFR5cGVkQXJyYXksIG51bWJlcltdXSB7XG4gIGlmIChwYXJhbXNOZXN0ZWRTcGxpdHMubGVuZ3RoID09PSAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdwYXJhbXNOZXN0ZWRTcGxpdHMgbXVzdCBiZSBub24gZW1wdHknKTtcbiAgfVxuXG4gIGlmIChwYXJhbXNOZXN0ZWRTcGxpdHNTaGFwZXNbMF0ubGVuZ3RoID09PSAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdTcGxpdCB0ZW5zb3JzIG11c3Qgbm90IGJlIHNjYWxhcnMnKTtcbiAgfVxuICBjb25zdCBudW1QYXJhbXMgPSBwYXJhbXNOZXN0ZWRTcGxpdHNTaGFwZXNbMF1bMF0gLSAxO1xuICB2YWxpZGF0ZUluZGljZXMoaW5kaWNlcywgaW5kaWNlc1NoYXBlLCBudW1QYXJhbXMpO1xuXG4gIGlmIChwYXJhbXNEZW5zZVZhbHVlc1NoYXBlLmxlbmd0aCA9PT0gMCkge1xuICAgIHRocm93IG5ldyBFcnJvcigncGFyYW1zLnJhbmsgbXVzdCBiZSBub256ZXJvJyk7XG4gIH1cbiAgY29uc3QgbnVtUGFyYW1zRGVuc2VWYWx1ZXMgPSBwYXJhbXNEZW5zZVZhbHVlc1NoYXBlWzBdO1xuXG4gIC8vIENhbGN1bGF0ZSB0aGUgYHNwbGl0c2AsIGFuZCBzdG9yZSB0aGUgdmFsdWUgc2xpY2VzIHRoYXQgd2UgbmVlZCB0b1xuICAvLyBjb3B5IGluIGB2YWx1ZVNsaWNlc2AuXG4gIGNvbnN0IHtvdXRTcGxpdHMsIHZhbHVlU2xpY2VzLCBudW1WYWx1ZXN9ID0gbWFrZVNwbGl0cyhcbiAgICAgIGluZGljZXMsIGluZGljZXNTaGFwZSwgcGFyYW1zTmVzdGVkU3BsaXRzLCBudW1QYXJhbXNEZW5zZVZhbHVlcyk7XG5cbiAgLy8gV3JpdGUgdGhlIG91dHB1dCB0ZW5zb3JzLlxuICBjb25zdCBvdXRwdXROZXN0ZWRTcGxpdHMgPSBnZXRTcGxpdHMob3V0U3BsaXRzKTtcbiAgY29uc3Qgb3V0cHV0RGVuc2VWYWx1ZXMgPSBnZXRWYWx1ZXMoXG4gICAgICBwYXJhbXNEZW5zZVZhbHVlcywgcGFyYW1zRGVuc2VWYWx1ZXNTaGFwZSwgcGFyYW1zRGVuc2VWYWx1ZXNEVHlwZSxcbiAgICAgIHZhbHVlU2xpY2VzLCBudW1WYWx1ZXMpO1xuXG4gIHJldHVybiBbb3V0cHV0TmVzdGVkU3BsaXRzLCBvdXRwdXREZW5zZVZhbHVlc1swXSwgb3V0cHV0RGVuc2VWYWx1ZXNbMV1dO1xufVxuIl19
|