kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
309 lines (297 loc) • 44.3 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.assignAccessor = assignAccessor;
exports.convertStructToFixedSizeList = convertStructToFixedSizeList;
exports.expandArrayToCoords = expandArrayToCoords;
exports.extractAccessorsFromProps = extractAccessorsFromProps;
exports.findGeometryColumnIndex = findGeometryColumnIndex;
exports.getGeometryVector = getGeometryVector;
exports.getListNestingLevels = getListNestingLevels;
exports.getMultiLineStringResolvedOffsets = getMultiLineStringResolvedOffsets;
exports.getMultiPolygonResolvedOffsets = getMultiPolygonResolvedOffsets;
exports.getPolygonResolvedOffsets = getPolygonResolvedOffsets;
exports.invertOffsets = invertOffsets;
exports.isColumnReference = isColumnReference;
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _typed = require("@deck.gl/core/typed");
var arrow = _interopRequireWildcard(require("apache-arrow"));
var ga = _interopRequireWildcard(require("@geoarrow/geoarrow-js"));
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; }
// SPDX-License-Identifier: MIT
// Copyright contributors to the kepler.gl project
// deck.gl-community
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
function findGeometryColumnIndex(schema, extensionName, geometryColumnName) {
var index = schema.fields.findIndex(function (field) {
return field.name === geometryColumnName || field.metadata.get('ARROW:extension:name') === extensionName;
});
return index !== -1 ? index : null;
}
/**
* Returns `true` if the input is a reference to a column in the table
*/
function isColumnReference(input) {
return typeof input === 'string';
}
function isDataInterleavedCoords(data) {
// TODO: also check 2 or 3d? Float64?
return data.type instanceof arrow.FixedSizeList;
}
function isDataSeparatedCoords(data) {
// TODO: also check child names? Float64?
return data.type instanceof arrow.Struct;
}
/**
* Convert geoarrow Struct coordinates to FixedSizeList coords
*
* The GeoArrow spec allows for either separated or interleaved coords, but at
* this time deck.gl only supports interleaved.
*/
// TODO: this hasn't been tested yet
function convertStructToFixedSizeList(coords) {
if (isDataInterleavedCoords(coords)) {
return coords;
} else if (isDataSeparatedCoords(coords)) {
// TODO: support 3d
var interleavedCoords = new Float64Array(coords.length * 2);
var _coords$children = (0, _slicedToArray2["default"])(coords.children, 2),
xChild = _coords$children[0],
yChild = _coords$children[1];
for (var i = 0; i < coords.length; i++) {
interleavedCoords[i * 2] = xChild.values[i];
interleavedCoords[i * 2 + 1] = yChild.values[i];
}
var childDataType = new arrow.Float64();
var dataType = new arrow.FixedSizeList(2, new arrow.Field('coords', childDataType));
var interleavedCoordsData = arrow.makeData({
type: childDataType,
length: interleavedCoords.length
});
var data = arrow.makeData({
type: dataType,
length: coords.length,
nullCount: coords.nullCount,
nullBitmap: coords.nullBitmap,
child: interleavedCoordsData
});
return data;
}
(0, _typed.assert)(false);
}
/**
* A wrapper around a user-provided accessor function
*
* For layers like Scatterplot, Path, and Polygon, we automatically handle
* "exploding" the table when multi-geometry input are provided. This means that
* the upstream `index` value passed to the user will be the correct row index
* _only_ for non-exploded data.
*
* With this function, we simplify the user usage by automatically converting
* back from "exploded" index back to the original row index.
*/
function wrapAccessorFunction(objectInfo, userAccessorFunction, batchOffset) {
var index = objectInfo.index,
data = objectInfo.data;
var newIndex = index + batchOffset;
if (data.invertedGeomOffsets !== undefined) {
newIndex = data.invertedGeomOffsets[index];
}
var newObjectData = {
data: data.data,
length: data.length,
attributes: data.attributes
};
var newObjectInfo = {
index: newIndex,
data: newObjectData,
target: objectInfo.target
};
return userAccessorFunction(newObjectInfo);
}
/**
* Resolve accessor and assign to props object
*
* This is useful as a helper function because a scalar prop is set at the top
* level while a vectorized prop is set inside data.attributes
*
*/
function assignAccessor(args) {
var props = args.props,
propName = args.propName,
propInput = args.propInput,
chunkIdx = args.chunkIdx,
geomCoordOffsets = args.geomCoordOffsets,
_args$batchOffset = args.batchOffset,
batchOffset = _args$batchOffset === void 0 ? 0 : _args$batchOffset;
if (propInput === undefined) {
return;
}
if (propInput instanceof arrow.Vector) {
var columnData = propInput.data[chunkIdx];
if (arrow.DataType.isFixedSizeList(columnData)) {
(0, _typed.assert)(columnData.children.length === 1);
var values = columnData.children[0].values;
if (geomCoordOffsets) {
values = expandArrayToCoords(values, columnData.type.listSize, geomCoordOffsets);
}
props.data.attributes[propName] = {
value: values,
size: columnData.type.listSize,
// Set to `true` to signify that colors are already 0-255, and deck/luma
// does not need to rescale
// https://github.com/visgl/deck.gl/blob/401d624c0529faaa62125714c376b3ba3b8f379f/docs/api-reference/core/attribute-manager.md?plain=1#L66
normalized: true
};
} else if (arrow.DataType.isFloat(columnData)) {
var _values = columnData.values;
if (geomCoordOffsets) {
_values = expandArrayToCoords(_values, 1, geomCoordOffsets);
}
props.data.attributes[propName] = {
value: _values,
size: 1
};
}
} else if (typeof propInput === 'function') {
props[propName] = function (object, objectInfo) {
// Special case that doesn't have the same parameters
if (propName === 'getPolygonOffset') {
return propInput(object, objectInfo);
}
return wrapAccessorFunction(objectInfo, propInput, batchOffset);
};
} else {
props[propName] = propInput;
}
}
/**
* Expand an array from "one element per geometry" to "one element per coordinate"
*
* @param input: the input array to expand
* @param size : the number of nested elements in the input array per geometry. So for example, for RGB data this would be 3, for RGBA this would be 4. For radius, this would be 1.
* @param geomOffsets : an offsets array mapping from the geometry to the coordinate indexes. So in the case of a LineStringArray, this is retrieved directly from the GeoArrow storage. In the case of a PolygonArray, this comes from the resolved indexes that need to be given to the SolidPolygonLayer anyways.
* @param numPositions : end position in geomOffsets, as geomOffsets can potentially contain preallocated zeroes in the end of the buffer.
*
* @return {TypedArray} values expanded to be per-coordinate
*/
function expandArrayToCoords(input, size, geomOffsets, numPositions) {
var lastIndex = numPositions || geomOffsets.length - 1;
var numCoords = geomOffsets[lastIndex];
// @ts-expect-error
var outputArray = new input.constructor(numCoords * size);
// geomIdx is an index into the geomOffsets array
// geomIdx is also the geometry/table index
for (var geomIdx = 0; geomIdx < lastIndex; geomIdx++) {
// geomOffsets maps from the geometry index to the coord index
// So here we get the range of coords that this geometry covers
var lastCoordIdx = geomOffsets[geomIdx];
var nextCoordIdx = geomOffsets[geomIdx + 1];
// Iterate over this range of coord indices
for (var coordIdx = lastCoordIdx; coordIdx < nextCoordIdx; coordIdx++) {
// Iterate over size
for (var i = 0; i < size; i++) {
// Copy from the geometry index in `input` to the coord index in
// `output`
outputArray[coordIdx * size + i] = input[geomIdx * size + i];
}
}
}
return outputArray;
}
/**
* Get a geometry vector with the specified extension type name from the table.
*/
function getGeometryVector(table, geoarrowTypeName) {
var geometryColumnIdx = findGeometryColumnIndex(table.schema, geoarrowTypeName);
if (geometryColumnIdx === null) {
return null;
// throw new Error(`No column found with extension type ${geoarrowTypeName}`);
}
return table.getChildAt(geometryColumnIdx);
}
function getListNestingLevels(data) {
var nestingLevels = 0;
if (arrow.DataType.isList(data.type)) {
nestingLevels += 1;
data = data.children[0];
}
return nestingLevels;
}
function getMultiLineStringResolvedOffsets(data) {
var geomOffsets = data.valueOffsets;
var lineStringData = ga.child.getMultiLineStringChild(data);
var ringOffsets = lineStringData.valueOffsets;
var resolvedRingOffsets = new Int32Array(geomOffsets.length);
for (var i = 0; i < resolvedRingOffsets.length; ++i) {
// Perform the lookup into the ringIndices array using the geomOffsets
// array
resolvedRingOffsets[i] = ringOffsets[geomOffsets[i]];
}
return resolvedRingOffsets;
}
function getPolygonResolvedOffsets(data) {
var geomOffsets = data.valueOffsets;
var ringData = ga.child.getPolygonChild(data);
var ringOffsets = ringData.valueOffsets;
var resolvedRingOffsets = new Int32Array(geomOffsets.length);
for (var i = 0; i < resolvedRingOffsets.length; ++i) {
// Perform the lookup into the ringIndices array using the geomOffsets
// array
resolvedRingOffsets[i] = ringOffsets[geomOffsets[i]];
}
return resolvedRingOffsets;
}
function getMultiPolygonResolvedOffsets(data) {
var polygonData = ga.child.getMultiPolygonChild(data);
var ringData = ga.child.getPolygonChild(polygonData);
var geomOffsets = data.valueOffsets;
var polygonOffsets = polygonData.valueOffsets;
var ringOffsets = ringData.valueOffsets;
var resolvedRingOffsets = new Int32Array(geomOffsets.length);
for (var i = 0; i < resolvedRingOffsets.length; ++i) {
resolvedRingOffsets[i] = ringOffsets[polygonOffsets[geomOffsets[i]]];
}
return resolvedRingOffsets;
}
/**
* Invert offsets so that lookup can go in the opposite direction
*/
function invertOffsets(offsets) {
var largestOffset = offsets[offsets.length - 1];
var arrayConstructor = offsets.length < Math.pow(2, 8) ? Uint8Array : offsets.length < Math.pow(2, 16) ? Uint16Array : Uint32Array;
var invertedOffsets = new arrayConstructor(largestOffset);
for (var arrayIdx = 0; arrayIdx < offsets.length - 1; arrayIdx++) {
var thisOffset = offsets[arrayIdx];
var nextOffset = offsets[arrayIdx + 1];
for (var offset = thisOffset; offset < nextOffset; offset++) {
invertedOffsets[offset] = arrayIdx;
}
}
return invertedOffsets;
}
// TODO: better typing
function extractAccessorsFromProps(props, excludeKeys) {
var accessors = {};
var otherProps = {};
for (var _i = 0, _Object$entries = Object.entries(props); _i < _Object$entries.length; _i++) {
var _Object$entries$_i = (0, _slicedToArray2["default"])(_Object$entries[_i], 2),
key = _Object$entries$_i[0],
value = _Object$entries$_i[1];
if (excludeKeys.includes(key)) {
continue;
}
if (key.startsWith('get')) {
accessors[key] = value;
} else {
otherProps[key] = value;
}
}
return [accessors, otherProps];
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfdHlwZWQiLCJyZXF1aXJlIiwiYXJyb3ciLCJfaW50ZXJvcFJlcXVpcmVXaWxkY2FyZCIsImdhIiwiX2dldFJlcXVpcmVXaWxkY2FyZENhY2hlIiwiZSIsIldlYWtNYXAiLCJyIiwidCIsIl9fZXNNb2R1bGUiLCJfdHlwZW9mIiwiaGFzIiwiZ2V0IiwibiIsIl9fcHJvdG9fXyIsImEiLCJPYmplY3QiLCJkZWZpbmVQcm9wZXJ0eSIsImdldE93blByb3BlcnR5RGVzY3JpcHRvciIsInUiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJpIiwic2V0IiwiZmluZEdlb21ldHJ5Q29sdW1uSW5kZXgiLCJzY2hlbWEiLCJleHRlbnNpb25OYW1lIiwiZ2VvbWV0cnlDb2x1bW5OYW1lIiwiaW5kZXgiLCJmaWVsZHMiLCJmaW5kSW5kZXgiLCJmaWVsZCIsIm5hbWUiLCJtZXRhZGF0YSIsImlzQ29sdW1uUmVmZXJlbmNlIiwiaW5wdXQiLCJpc0RhdGFJbnRlcmxlYXZlZENvb3JkcyIsImRhdGEiLCJ0eXBlIiwiRml4ZWRTaXplTGlzdCIsImlzRGF0YVNlcGFyYXRlZENvb3JkcyIsIlN0cnVjdCIsImNvbnZlcnRTdHJ1Y3RUb0ZpeGVkU2l6ZUxpc3QiLCJjb29yZHMiLCJpbnRlcmxlYXZlZENvb3JkcyIsIkZsb2F0NjRBcnJheSIsImxlbmd0aCIsIl9jb29yZHMkY2hpbGRyZW4iLCJfc2xpY2VkVG9BcnJheTIiLCJjaGlsZHJlbiIsInhDaGlsZCIsInlDaGlsZCIsInZhbHVlcyIsImNoaWxkRGF0YVR5cGUiLCJGbG9hdDY0IiwiZGF0YVR5cGUiLCJGaWVsZCIsImludGVybGVhdmVkQ29vcmRzRGF0YSIsIm1ha2VEYXRhIiwibnVsbENvdW50IiwibnVsbEJpdG1hcCIsImNoaWxkIiwiYXNzZXJ0Iiwid3JhcEFjY2Vzc29yRnVuY3Rpb24iLCJvYmplY3RJbmZvIiwidXNlckFjY2Vzc29yRnVuY3Rpb24iLCJiYXRjaE9mZnNldCIsIm5ld0luZGV4IiwiaW52ZXJ0ZWRHZW9tT2Zmc2V0cyIsInVuZGVmaW5lZCIsIm5ld09iamVjdERhdGEiLCJhdHRyaWJ1dGVzIiwibmV3T2JqZWN0SW5mbyIsInRhcmdldCIsImFzc2lnbkFjY2Vzc29yIiwiYXJncyIsInByb3BzIiwicHJvcE5hbWUiLCJwcm9wSW5wdXQiLCJjaHVua0lkeCIsImdlb21Db29yZE9mZnNldHMiLCJfYXJncyRiYXRjaE9mZnNldCIsIlZlY3RvciIsImNvbHVtbkRhdGEiLCJEYXRhVHlwZSIsImlzRml4ZWRTaXplTGlzdCIsImV4cGFuZEFycmF5VG9Db29yZHMiLCJsaXN0U2l6ZSIsInZhbHVlIiwic2l6ZSIsIm5vcm1hbGl6ZWQiLCJpc0Zsb2F0Iiwib2JqZWN0IiwiZ2VvbU9mZnNldHMiLCJudW1Qb3NpdGlvbnMiLCJsYXN0SW5kZXgiLCJudW1Db29yZHMiLCJvdXRwdXRBcnJheSIsImNvbnN0cnVjdG9yIiwiZ2VvbUlkeCIsImxhc3RDb29yZElkeCIsIm5leHRDb29yZElkeCIsImNvb3JkSWR4IiwiZ2V0R2VvbWV0cnlWZWN0b3IiLCJ0YWJsZSIsImdlb2Fycm93VHlwZU5hbWUiLCJnZW9tZXRyeUNvbHVtbklkeCIsImdldENoaWxkQXQiLCJnZXRMaXN0TmVzdGluZ0xldmVscyIsIm5lc3RpbmdMZXZlbHMiLCJpc0xpc3QiLCJnZXRNdWx0aUxpbmVTdHJpbmdSZXNvbHZlZE9mZnNldHMiLCJ2YWx1ZU9mZnNldHMiLCJsaW5lU3RyaW5nRGF0YSIsImdldE11bHRpTGluZVN0cmluZ0NoaWxkIiwicmluZ09mZnNldHMiLCJyZXNvbHZlZFJpbmdPZmZzZXRzIiwiSW50MzJBcnJheSIsImdldFBvbHlnb25SZXNvbHZlZE9mZnNldHMiLCJyaW5nRGF0YSIsImdldFBvbHlnb25DaGlsZCIsImdldE11bHRpUG9seWdvblJlc29sdmVkT2Zmc2V0cyIsInBvbHlnb25EYXRhIiwiZ2V0TXVsdGlQb2x5Z29uQ2hpbGQiLCJwb2x5Z29uT2Zmc2V0cyIsImludmVydE9mZnNldHMiLCJvZmZzZXRzIiwibGFyZ2VzdE9mZnNldCIsImFycmF5Q29uc3RydWN0b3IiLCJNYXRoIiwicG93IiwiVWludDhBcnJheSIsIlVpbnQxNkFycmF5IiwiVWludDMyQXJyYXkiLCJpbnZlcnRlZE9mZnNldHMiLCJhcnJheUlkeCIsInRoaXNPZmZzZXQiLCJuZXh0T2Zmc2V0Iiwib2Zmc2V0IiwiZXh0cmFjdEFjY2Vzc29yc0Zyb21Qcm9wcyIsImV4Y2x1ZGVLZXlzIiwiYWNjZXNzb3JzIiwib3RoZXJQcm9wcyIsIl9pIiwiX09iamVjdCRlbnRyaWVzIiwiZW50cmllcyIsIl9PYmplY3QkZW50cmllcyRfaSIsImtleSIsImluY2x1ZGVzIiwic3RhcnRzV2l0aCJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy91dGlscy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogTUlUXG4vLyBDb3B5cmlnaHQgY29udHJpYnV0b3JzIHRvIHRoZSBrZXBsZXIuZ2wgcHJvamVjdFxuXG4vLyBkZWNrLmdsLWNvbW11bml0eVxuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVFxuLy8gQ29weXJpZ2h0IChjKSB2aXMuZ2wgY29udHJpYnV0b3JzXG5cbmltcG9ydCB7YXNzZXJ0fSBmcm9tICdAZGVjay5nbC9jb3JlL3R5cGVkJztcbmltcG9ydCAqIGFzIGFycm93IGZyb20gJ2FwYWNoZS1hcnJvdyc7XG5pbXBvcnQgKiBhcyBnYSBmcm9tICdAZ2VvYXJyb3cvZ2VvYXJyb3ctanMnO1xuaW1wb3J0IHtBY2Nlc3NvckNvbnRleHQsIEFjY2Vzc29yRnVuY3Rpb24sIF9JbnRlcm5hbEFjY2Vzc29yQ29udGV4dH0gZnJvbSAnLi4vdHlwZXMnO1xuXG5leHBvcnQgdHlwZSBUeXBlZEFycmF5ID1cbiAgfCBVaW50OEFycmF5XG4gIHwgVWludDhDbGFtcGVkQXJyYXlcbiAgfCBVaW50MTZBcnJheVxuICB8IFVpbnQzMkFycmF5XG4gIHwgSW50OEFycmF5XG4gIHwgSW50MTZBcnJheVxuICB8IEludDMyQXJyYXlcbiAgfCBGbG9hdDMyQXJyYXlcbiAgfCBGbG9hdDY0QXJyYXk7XG5cbmV4cG9ydCBmdW5jdGlvbiBmaW5kR2VvbWV0cnlDb2x1bW5JbmRleChcbiAgc2NoZW1hOiBhcnJvdy5TY2hlbWEsXG4gIGV4dGVuc2lvbk5hbWU6IHN0cmluZyxcbiAgZ2VvbWV0cnlDb2x1bW5OYW1lPzogc3RyaW5nIHwgbnVsbFxuKTogbnVtYmVyIHwgbnVsbCB7XG4gIGNvbnN0IGluZGV4ID0gc2NoZW1hLmZpZWxkcy5maW5kSW5kZXgoXG4gICAgZmllbGQgPT5cbiAgICAgIGZpZWxkLm5hbWUgPT09IGdlb21ldHJ5Q29sdW1uTmFtZSB8fFxuICAgICAgZmllbGQubWV0YWRhdGEuZ2V0KCdBUlJPVzpleHRlbnNpb246bmFtZScpID09PSBleHRlbnNpb25OYW1lXG4gICk7XG4gIHJldHVybiBpbmRleCAhPT0gLTEgPyBpbmRleCA6IG51bGw7XG59XG5cbi8qKlxuICogUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIGlucHV0IGlzIGEgcmVmZXJlbmNlIHRvIGEgY29sdW1uIGluIHRoZSB0YWJsZVxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNDb2x1bW5SZWZlcmVuY2UoaW5wdXQ6IGFueSk6IGlucHV0IGlzIHN0cmluZyB7XG4gIHJldHVybiB0eXBlb2YgaW5wdXQgPT09ICdzdHJpbmcnO1xufVxuXG5mdW5jdGlvbiBpc0RhdGFJbnRlcmxlYXZlZENvb3JkcyhcbiAgZGF0YTogYXJyb3cuRGF0YVxuKTogZGF0YSBpcyBhcnJvdy5EYXRhPGFycm93LkZpeGVkU2l6ZUxpc3Q8YXJyb3cuRmxvYXQ2ND4+IHtcbiAgLy8gVE9ETzogYWxzbyBjaGVjayAyIG9yIDNkPyBGbG9hdDY0P1xuICByZXR1cm4gZGF0YS50eXBlIGluc3RhbmNlb2YgYXJyb3cuRml4ZWRTaXplTGlzdDtcbn1cblxuZnVuY3Rpb24gaXNEYXRhU2VwYXJhdGVkQ29vcmRzKFxuICBkYXRhOiBhcnJvdy5EYXRhXG4pOiBkYXRhIGlzIGFycm93LkRhdGE8YXJyb3cuU3RydWN0PHt4OiBhcnJvdy5GbG9hdDY0OyB5OiBhcnJvdy5GbG9hdDY0fT4+IHtcbiAgLy8gVE9ETzogYWxzbyBjaGVjayBjaGlsZCBuYW1lcz8gRmxvYXQ2ND9cbiAgcmV0dXJuIGRhdGEudHlwZSBpbnN0YW5jZW9mIGFycm93LlN0cnVjdDtcbn1cblxuLyoqXG4gKiBDb252ZXJ0IGdlb2Fycm93IFN0cnVjdCBjb29yZGluYXRlcyB0byBGaXhlZFNpemVMaXN0IGNvb3Jkc1xuICpcbiAqIFRoZSBHZW9BcnJvdyBzcGVjIGFsbG93cyBmb3IgZWl0aGVyIHNlcGFyYXRlZCBvciBpbnRlcmxlYXZlZCBjb29yZHMsIGJ1dCBhdFxuICogdGhpcyB0aW1lIGRlY2suZ2wgb25seSBzdXBwb3J0cyBpbnRlcmxlYXZlZC5cbiAqL1xuLy8gVE9ETzogdGhpcyBoYXNuJ3QgYmVlbiB0ZXN0ZWQgeWV0XG5leHBvcnQgZnVuY3Rpb24gY29udmVydFN0cnVjdFRvRml4ZWRTaXplTGlzdChcbiAgY29vcmRzOlxuICAgIHwgYXJyb3cuRGF0YTxhcnJvdy5GaXhlZFNpemVMaXN0PGFycm93LkZsb2F0NjQ+PlxuICAgIHwgYXJyb3cuRGF0YTxhcnJvdy5TdHJ1Y3Q8e3g6IGFycm93LkZsb2F0NjQ7IHk6IGFycm93LkZsb2F0NjR9Pj5cbik6IGFycm93LkRhdGE8YXJyb3cuRml4ZWRTaXplTGlzdDxhcnJvdy5GbG9hdDY0Pj4ge1xuICBpZiAoaXNEYXRhSW50ZXJsZWF2ZWRDb29yZHMoY29vcmRzKSkge1xuICAgIHJldHVybiBjb29yZHM7XG4gIH0gZWxzZSBpZiAoaXNEYXRhU2VwYXJhdGVkQ29vcmRzKGNvb3JkcykpIHtcbiAgICAvLyBUT0RPOiBzdXBwb3J0IDNkXG4gICAgY29uc3QgaW50ZXJsZWF2ZWRDb29yZHMgPSBuZXcgRmxvYXQ2NEFycmF5KGNvb3Jkcy5sZW5ndGggKiAyKTtcbiAgICBjb25zdCBbeENoaWxkLCB5Q2hpbGRdID0gY29vcmRzLmNoaWxkcmVuO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY29vcmRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpbnRlcmxlYXZlZENvb3Jkc1tpICogMl0gPSB4Q2hpbGQudmFsdWVzW2ldO1xuICAgICAgaW50ZXJsZWF2ZWRDb29yZHNbaSAqIDIgKyAxXSA9IHlDaGlsZC52YWx1ZXNbaV07XG4gICAgfVxuXG4gICAgY29uc3QgY2hpbGREYXRhVHlwZSA9IG5ldyBhcnJvdy5GbG9hdDY0KCk7XG4gICAgY29uc3QgZGF0YVR5cGUgPSBuZXcgYXJyb3cuRml4ZWRTaXplTGlzdCgyLCBuZXcgYXJyb3cuRmllbGQoJ2Nvb3JkcycsIGNoaWxkRGF0YVR5cGUpKTtcblxuICAgIGNvbnN0IGludGVybGVhdmVkQ29vcmRzRGF0YSA9IGFycm93Lm1ha2VEYXRhKHtcbiAgICAgIHR5cGU6IGNoaWxkRGF0YVR5cGUsXG4gICAgICBsZW5ndGg6IGludGVybGVhdmVkQ29vcmRzLmxlbmd0aFxuICAgIH0pO1xuXG4gICAgY29uc3QgZGF0YSA9IGFycm93Lm1ha2VEYXRhKHtcbiAgICAgIHR5cGU6IGRhdGFUeXBlLFxuICAgICAgbGVuZ3RoOiBjb29yZHMubGVuZ3RoLFxuICAgICAgbnVsbENvdW50OiBjb29yZHMubnVsbENvdW50LFxuICAgICAgbnVsbEJpdG1hcDogY29vcmRzLm51bGxCaXRtYXAsXG4gICAgICBjaGlsZDogaW50ZXJsZWF2ZWRDb29yZHNEYXRhXG4gICAgfSk7XG4gICAgcmV0dXJuIGRhdGE7XG4gIH1cblxuICBhc3NlcnQoZmFsc2UpO1xufVxuXG50eXBlIEFzc2lnbkFjY2Vzc29yUHJvcHMgPSB7XG4gIC8qKiBUaGUgb2JqZWN0IG9uIHdoaWNoIHRvIGFzc2lnbiB0aGUgcmVzb2x2ZWQgYWNjZXNvciAqL1xuICBwcm9wczogUmVjb3JkPHN0cmluZywgYW55PjtcbiAgLyoqIFRoZSBuYW1lIG9mIHRoZSBwcm9wIHRvIHNldCAqL1xuICBwcm9wTmFtZTogc3RyaW5nO1xuICAvKiogVGhlIHVzZXItc3VwcGxpZWQgaW5wdXQgdG8gdGhlIGxheWVyLiBNdXN0IGVpdGhlciBiZSBhIHNjYWxhciB2YWx1ZSBvciBhIHJlZmVyZW5jZSB0byBhIGNvbHVtbiBpbiB0aGUgdGFibGUuICovXG4gIHByb3BJbnB1dDogYW55O1xuICAvKiogTnVtZXJpYyBpbmRleCBpbiB0aGUgdGFibGUgKi9cbiAgY2h1bmtJZHg6IG51bWJlcjtcbiAgLyoqIGEgbWFwIGZyb20gdGhlIGdlb21ldHJ5IGluZGV4IHRvIHRoZSBjb29yZCBvZmZzZXRzIGZvciB0aGF0IGdlb21ldHJ5LiAqL1xuICBnZW9tQ29vcmRPZmZzZXRzPzogSW50MzJBcnJheSB8IG51bGw7XG4gIC8qKiBBYnNvbHV0ZSBvZmZzZXQgb2YgdGhlIGJhdGNoIGluIHRoZSB0YWJsZS92ZWN0b3IuIEFkZGVkIHRvIHRoZSBzYW1wbGluZyBpbmRleC4gKi9cbiAgYmF0Y2hPZmZzZXQ/OiBudW1iZXI7XG59O1xuXG4vKipcbiAqIEEgd3JhcHBlciBhcm91bmQgYSB1c2VyLXByb3ZpZGVkIGFjY2Vzc29yIGZ1bmN0aW9uXG4gKlxuICogRm9yIGxheWVycyBsaWtlIFNjYXR0ZXJwbG90LCBQYXRoLCBhbmQgUG9seWdvbiwgd2UgYXV0b21hdGljYWxseSBoYW5kbGVcbiAqIFwiZXhwbG9kaW5nXCIgdGhlIHRhYmxlIHdoZW4gbXVsdGktZ2VvbWV0cnkgaW5wdXQgYXJlIHByb3ZpZGVkLiBUaGlzIG1lYW5zIHRoYXRcbiAqIHRoZSB1cHN0cmVhbSBgaW5kZXhgIHZhbHVlIHBhc3NlZCB0byB0aGUgdXNlciB3aWxsIGJlIHRoZSBjb3JyZWN0IHJvdyBpbmRleFxuICogX29ubHlfIGZvciBub24tZXhwbG9kZWQgZGF0YS5cbiAqXG4gKiBXaXRoIHRoaXMgZnVuY3Rpb24sIHdlIHNpbXBsaWZ5IHRoZSB1c2VyIHVzYWdlIGJ5IGF1dG9tYXRpY2FsbHkgY29udmVydGluZ1xuICogYmFjayBmcm9tIFwiZXhwbG9kZWRcIiBpbmRleCBiYWNrIHRvIHRoZSBvcmlnaW5hbCByb3cgaW5kZXguXG4gKi9cbmZ1bmN0aW9uIHdyYXBBY2Nlc3NvckZ1bmN0aW9uPEluLCBPdXQ+KFxuICBvYmplY3RJbmZvOiBfSW50ZXJuYWxBY2Nlc3NvckNvbnRleHQ8SW4+LFxuICB1c2VyQWNjZXNzb3JGdW5jdGlvbjogQWNjZXNzb3JGdW5jdGlvbjxJbiwgT3V0PixcbiAgYmF0Y2hPZmZzZXQ6IG51bWJlclxuKTogT3V0IHtcbiAgY29uc3Qge2luZGV4LCBkYXRhfSA9IG9iamVjdEluZm87XG4gIGxldCBuZXdJbmRleCA9IGluZGV4ICsgYmF0Y2hPZmZzZXQ7XG4gIGlmIChkYXRhLmludmVydGVkR2VvbU9mZnNldHMgIT09IHVuZGVmaW5lZCkge1xuICAgIG5ld0luZGV4ID0gZGF0YS5pbnZlcnRlZEdlb21PZmZzZXRzW2luZGV4XTtcbiAgfVxuICBjb25zdCBuZXdPYmplY3REYXRhID0ge1xuICAgIGRhdGE6IGRhdGEuZGF0YSxcbiAgICBsZW5ndGg6IGRhdGEubGVuZ3RoLFxuICAgIGF0dHJpYnV0ZXM6IGRhdGEuYXR0cmlidXRlc1xuICB9O1xuICBjb25zdCBuZXdPYmplY3RJbmZvID0ge1xuICAgIGluZGV4OiBuZXdJbmRleCxcbiAgICBkYXRhOiBuZXdPYmplY3REYXRhLFxuICAgIHRhcmdldDogb2JqZWN0SW5mby50YXJnZXRcbiAgfTtcbiAgcmV0dXJuIHVzZXJBY2Nlc3NvckZ1bmN0aW9uKG5ld09iamVjdEluZm8pO1xufVxuXG4vKipcbiAqIFJlc29sdmUgYWNjZXNzb3IgYW5kIGFzc2lnbiB0byBwcm9wcyBvYmplY3RcbiAqXG4gKiBUaGlzIGlzIHVzZWZ1bCBhcyBhIGhlbHBlciBmdW5jdGlvbiBiZWNhdXNlIGEgc2NhbGFyIHByb3AgaXMgc2V0IGF0IHRoZSB0b3BcbiAqIGxldmVsIHdoaWxlIGEgdmVjdG9yaXplZCBwcm9wIGlzIHNldCBpbnNpZGUgZGF0YS5hdHRyaWJ1dGVzXG4gKlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXNzaWduQWNjZXNzb3IoYXJnczogQXNzaWduQWNjZXNzb3JQcm9wcykge1xuICBjb25zdCB7cHJvcHMsIHByb3BOYW1lLCBwcm9wSW5wdXQsIGNodW5rSWR4LCBnZW9tQ29vcmRPZmZzZXRzLCBiYXRjaE9mZnNldCA9IDB9ID0gYXJncztcblxuICBpZiAocHJvcElucHV0ID09PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBpZiAocHJvcElucHV0IGluc3RhbmNlb2YgYXJyb3cuVmVjdG9yKSB7XG4gICAgY29uc3QgY29sdW1uRGF0YSA9IHByb3BJbnB1dC5kYXRhW2NodW5rSWR4XTtcblxuICAgIGlmIChhcnJvdy5EYXRhVHlwZS5pc0ZpeGVkU2l6ZUxpc3QoY29sdW1uRGF0YSkpIHtcbiAgICAgIGFzc2VydChjb2x1bW5EYXRhLmNoaWxkcmVuLmxlbmd0aCA9PT0gMSk7XG4gICAgICBsZXQgdmFsdWVzID0gY29sdW1uRGF0YS5jaGlsZHJlblswXS52YWx1ZXM7XG5cbiAgICAgIGlmIChnZW9tQ29vcmRPZmZzZXRzKSB7XG4gICAgICAgIHZhbHVlcyA9IGV4cGFuZEFycmF5VG9Db29yZHModmFsdWVzLCBjb2x1bW5EYXRhLnR5cGUubGlzdFNpemUsIGdlb21Db29yZE9mZnNldHMpO1xuICAgICAgfVxuXG4gICAgICBwcm9wcy5kYXRhLmF0dHJpYnV0ZXNbcHJvcE5hbWVdID0ge1xuICAgICAgICB2YWx1ZTogdmFsdWVzLFxuICAgICAgICBzaXplOiBjb2x1bW5EYXRhLnR5cGUubGlzdFNpemUsXG4gICAgICAgIC8vIFNldCB0byBgdHJ1ZWAgdG8gc2lnbmlmeSB0aGF0IGNvbG9ycyBhcmUgYWxyZWFkeSAwLTI1NSwgYW5kIGRlY2svbHVtYVxuICAgICAgICAvLyBkb2VzIG5vdCBuZWVkIHRvIHJlc2NhbGVcbiAgICAgICAgLy8gaHR0cHM6Ly9naXRodWIuY29tL3Zpc2dsL2RlY2suZ2wvYmxvYi80MDFkNjI0YzA1MjlmYWFhNjIxMjU3MTRjMzc2YjNiYTNiOGYzNzlmL2RvY3MvYXBpLXJlZmVyZW5jZS9jb3JlL2F0dHJpYnV0ZS1tYW5hZ2VyLm1kP3BsYWluPTEjTDY2XG4gICAgICAgIG5vcm1hbGl6ZWQ6IHRydWVcbiAgICAgIH07XG4gICAgfSBlbHNlIGlmIChhcnJvdy5EYXRhVHlwZS5pc0Zsb2F0KGNvbHVtbkRhdGEpKSB7XG4gICAgICBsZXQgdmFsdWVzID0gY29sdW1uRGF0YS52YWx1ZXM7XG5cbiAgICAgIGlmIChnZW9tQ29vcmRPZmZzZXRzKSB7XG4gICAgICAgIHZhbHVlcyA9IGV4cGFuZEFycmF5VG9Db29yZHModmFsdWVzLCAxLCBnZW9tQ29vcmRPZmZzZXRzKTtcbiAgICAgIH1cblxuICAgICAgcHJvcHMuZGF0YS5hdHRyaWJ1dGVzW3Byb3BOYW1lXSA9IHtcbiAgICAgICAgdmFsdWU6IHZhbHVlcyxcbiAgICAgICAgc2l6ZTogMVxuICAgICAgfTtcbiAgICB9XG4gIH0gZWxzZSBpZiAodHlwZW9mIHByb3BJbnB1dCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgIHByb3BzW3Byb3BOYW1lXSA9IDxJbj4ob2JqZWN0OiBhbnksIG9iamVjdEluZm86IEFjY2Vzc29yQ29udGV4dDxJbj4pID0+IHtcbiAgICAgIC8vIFNwZWNpYWwgY2FzZSB0aGF0IGRvZXNuJ3QgaGF2ZSB0aGUgc2FtZSBwYXJhbWV0ZXJzXG4gICAgICBpZiAocHJvcE5hbWUgPT09ICdnZXRQb2x5Z29uT2Zmc2V0Jykge1xuICAgICAgICByZXR1cm4gcHJvcElucHV0KG9iamVjdCwgb2JqZWN0SW5mbyk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB3cmFwQWNjZXNzb3JGdW5jdGlvbihvYmplY3RJbmZvLCBwcm9wSW5wdXQsIGJhdGNoT2Zmc2V0KTtcbiAgICB9O1xuICB9IGVsc2Uge1xuICAgIHByb3BzW3Byb3BOYW1lXSA9IHByb3BJbnB1dDtcbiAgfVxufVxuXG4vKipcbiAqIEV4cGFuZCBhbiBhcnJheSBmcm9tIFwib25lIGVsZW1lbnQgcGVyIGdlb21ldHJ5XCIgdG8gXCJvbmUgZWxlbWVudCBwZXIgY29vcmRpbmF0ZVwiXG4gKlxuICogQHBhcmFtIGlucHV0OiB0aGUgaW5wdXQgYXJyYXkgdG8gZXhwYW5kXG4gKiBAcGFyYW0gc2l6ZSA6IHRoZSBudW1iZXIgb2YgbmVzdGVkIGVsZW1lbnRzIGluIHRoZSBpbnB1dCBhcnJheSBwZXIgZ2VvbWV0cnkuIFNvIGZvciBleGFtcGxlLCBmb3IgUkdCIGRhdGEgdGhpcyB3b3VsZCBiZSAzLCBmb3IgUkdCQSB0aGlzIHdvdWxkIGJlIDQuIEZvciByYWRpdXMsIHRoaXMgd291bGQgYmUgMS5cbiAqIEBwYXJhbSBnZW9tT2Zmc2V0cyA6IGFuIG9mZnNldHMgYXJyYXkgbWFwcGluZyBmcm9tIHRoZSBnZW9tZXRyeSB0byB0aGUgY29vcmRpbmF0ZSBpbmRleGVzLiBTbyBpbiB0aGUgY2FzZSBvZiBhIExpbmVTdHJpbmdBcnJheSwgdGhpcyBpcyByZXRyaWV2ZWQgZGlyZWN0bHkgZnJvbSB0aGUgR2VvQXJyb3cgc3RvcmFnZS4gSW4gdGhlIGNhc2Ugb2YgYSBQb2x5Z29uQXJyYXksIHRoaXMgY29tZXMgZnJvbSB0aGUgcmVzb2x2ZWQgaW5kZXhlcyB0aGF0IG5lZWQgdG8gYmUgZ2l2ZW4gdG8gdGhlIFNvbGlkUG9seWdvbkxheWVyIGFueXdheXMuXG4gKiBAcGFyYW0gbnVtUG9zaXRpb25zIDogZW5kIHBvc2l0aW9uIGluIGdlb21PZmZzZXRzLCBhcyBnZW9tT2Zmc2V0cyBjYW4gcG90ZW50aWFsbHkgY29udGFpbiBwcmVhbGxvY2F0ZWQgemVyb2VzIGluIHRoZSBlbmQgb2YgdGhlIGJ1ZmZlci5cbiAqXG4gKiBAcmV0dXJuICB7VHlwZWRBcnJheX0gdmFsdWVzIGV4cGFuZGVkIHRvIGJlIHBlci1jb29yZGluYXRlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBleHBhbmRBcnJheVRvQ29vcmRzPFQgZXh0ZW5kcyBUeXBlZEFycmF5PihcbiAgaW5wdXQ6IFQsXG4gIHNpemU6IG51bWJlcixcbiAgZ2VvbU9mZnNldHM6IEludDMyQXJyYXksXG4gIG51bVBvc2l0aW9ucz86IG51bWJlclxuKTogVCB7XG4gIGNvbnN0IGxhc3RJbmRleCA9IG51bVBvc2l0aW9ucyB8fCBnZW9tT2Zmc2V0cy5sZW5ndGggLSAxO1xuICBjb25zdCBudW1Db29yZHMgPSBnZW9tT2Zmc2V0c1tsYXN0SW5kZXhdO1xuICAvLyBAdHMtZXhwZWN0LWVycm9yXG4gIGNvbnN0IG91dHB1dEFycmF5OiBUID0gbmV3IGlucHV0LmNvbnN0cnVjdG9yKG51bUNvb3JkcyAqIHNpemUpO1xuXG4gIC8vIGdlb21JZHggaXMgYW4gaW5kZXggaW50byB0aGUgZ2VvbU9mZnNldHMgYXJyYXlcbiAgLy8gZ2VvbUlkeCBpcyBhbHNvIHRoZSBnZW9tZXRyeS90YWJsZSBpbmRleFxuICBmb3IgKGxldCBnZW9tSWR4ID0gMDsgZ2VvbUlkeCA8IGxhc3RJbmRleDsgZ2VvbUlkeCsrKSB7XG4gICAgLy8gZ2VvbU9mZnNldHMgbWFwcyBmcm9tIHRoZSBnZW9tZXRyeSBpbmRleCB0byB0aGUgY29vcmQgaW5kZXhcbiAgICAvLyBTbyBoZXJlIHdlIGdldCB0aGUgcmFuZ2Ugb2YgY29vcmRzIHRoYXQgdGhpcyBnZW9tZXRyeSBjb3ZlcnNcbiAgICBjb25zdCBsYXN0Q29vcmRJZHggPSBnZW9tT2Zmc2V0c1tnZW9tSWR4XTtcbiAgICBjb25zdCBuZXh0Q29vcmRJZHggPSBnZW9tT2Zmc2V0c1tnZW9tSWR4ICsgMV07XG5cbiAgICAvLyBJdGVyYXRlIG92ZXIgdGhpcyByYW5nZSBvZiBjb29yZCBpbmRpY2VzXG4gICAgZm9yIChsZXQgY29vcmRJZHggPSBsYXN0Q29vcmRJZHg7IGNvb3JkSWR4IDwgbmV4dENvb3JkSWR4OyBjb29yZElkeCsrKSB7XG4gICAgICAvLyBJdGVyYXRlIG92ZXIgc2l6ZVxuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzaXplOyBpKyspIHtcbiAgICAgICAgLy8gQ29weSBmcm9tIHRoZSBnZW9tZXRyeSBpbmRleCBpbiBgaW5wdXRgIHRvIHRoZSBjb29yZCBpbmRleCBpblxuICAgICAgICAvLyBgb3V0cHV0YFxuICAgICAgICBvdXRwdXRBcnJheVtjb29yZElkeCAqIHNpemUgKyBpXSA9IGlucHV0W2dlb21JZHggKiBzaXplICsgaV07XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIG91dHB1dEFycmF5O1xufVxuXG4vKipcbiAqIEdldCBhIGdlb21ldHJ5IHZlY3RvciB3aXRoIHRoZSBzcGVjaWZpZWQgZXh0ZW5zaW9uIHR5cGUgbmFtZSBmcm9tIHRoZSB0YWJsZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEdlb21ldHJ5VmVjdG9yKFxuICB0YWJsZTogYXJyb3cuVGFibGUsXG4gIGdlb2Fycm93VHlwZU5hbWU6IHN0cmluZ1xuKTogYXJyb3cuVmVjdG9yIHwgbnVsbCB7XG4gIGNvbnN0IGdlb21ldHJ5Q29sdW1uSWR4ID0gZmluZEdlb21ldHJ5Q29sdW1uSW5kZXgodGFibGUuc2NoZW1hLCBnZW9hcnJvd1R5cGVOYW1lKTtcblxuICBpZiAoZ2VvbWV0cnlDb2x1bW5JZHggPT09IG51bGwpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgICAvLyB0aHJvdyBuZXcgRXJyb3IoYE5vIGNvbHVtbiBmb3VuZCB3aXRoIGV4dGVuc2lvbiB0eXBlICR7Z2VvYXJyb3dUeXBlTmFtZX1gKTtcbiAgfVxuXG4gIHJldHVybiB0YWJsZS5nZXRDaGlsZEF0KGdlb21ldHJ5Q29sdW1uSWR4KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldExpc3ROZXN0aW5nTGV2ZWxzKGRhdGE6IGFycm93LkRhdGEpOiBudW1iZXIge1xuICBsZXQgbmVzdGluZ0xldmVscyA9IDA7XG4gIGlmIChhcnJvdy5EYXRhVHlwZS5pc0xpc3QoZGF0YS50eXBlKSkge1xuICAgIG5lc3RpbmdMZXZlbHMgKz0gMTtcbiAgICBkYXRhID0gZGF0YS5jaGlsZHJlblswXTtcbiAgfVxuICByZXR1cm4gbmVzdGluZ0xldmVscztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldE11bHRpTGluZVN0cmluZ1Jlc29sdmVkT2Zmc2V0cyhkYXRhOiBnYS5kYXRhLk11bHRpTGluZVN0cmluZ0RhdGEpOiBJbnQzMkFycmF5IHtcbiAgY29uc3QgZ2VvbU9mZnNldHMgPSBkYXRhLnZhbHVlT2Zmc2V0cztcbiAgY29uc3QgbGluZVN0cmluZ0RhdGEgPSBnYS5jaGlsZC5nZXRNdWx0aUxpbmVTdHJpbmdDaGlsZChkYXRhKTtcbiAgY29uc3QgcmluZ09mZnNldHMgPSBsaW5lU3RyaW5nRGF0YS52YWx1ZU9mZnNldHM7XG5cbiAgY29uc3QgcmVzb2x2ZWRSaW5nT2Zmc2V0cyA9IG5ldyBJbnQzMkFycmF5KGdlb21PZmZzZXRzLmxlbmd0aCk7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgcmVzb2x2ZWRSaW5nT2Zmc2V0cy5sZW5ndGg7ICsraSkge1xuICAgIC8vIFBlcmZvcm0gdGhlIGxvb2t1cCBpbnRvIHRoZSByaW5nSW5kaWNlcyBhcnJheSB1c2luZyB0aGUgZ2VvbU9mZnNldHNcbiAgICAvLyBhcnJheVxuICAgIHJlc29sdmVkUmluZ09mZnNldHNbaV0gPSByaW5nT2Zmc2V0c1tnZW9tT2Zmc2V0c1tpXV07XG4gIH1cblxuICByZXR1cm4gcmVzb2x2ZWRSaW5nT2Zmc2V0cztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvbHlnb25SZXNvbHZlZE9mZnNldHMoZGF0YTogZ2EuZGF0YS5Qb2x5Z29uRGF0YSk6IEludDMyQXJyYXkge1xuICBjb25zdCBnZW9tT2Zmc2V0cyA9IGRhdGEudmFsdWVPZmZzZXRzO1xuICBjb25zdCByaW5nRGF0YSA9IGdhLmNoaWxkLmdldFBvbHlnb25DaGlsZChkYXRhKTtcbiAgY29uc3QgcmluZ09mZnNldHMgPSByaW5nRGF0YS52YWx1ZU9mZnNldHM7XG5cbiAgY29uc3QgcmVzb2x2ZWRSaW5nT2Zmc2V0cyA9IG5ldyBJbnQzMkFycmF5KGdlb21PZmZzZXRzLmxlbmd0aCk7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgcmVzb2x2ZWRSaW5nT2Zmc2V0cy5sZW5ndGg7ICsraSkge1xuICAgIC8vIFBlcmZvcm0gdGhlIGxvb2t1cCBpbnRvIHRoZSByaW5nSW5kaWNlcyBhcnJheSB1c2luZyB0aGUgZ2VvbU9mZnNldHNcbiAgICAvLyBhcnJheVxuICAgIHJlc29sdmVkUmluZ09mZnNldHNbaV0gPSByaW5nT2Zmc2V0c1tnZW9tT2Zmc2V0c1tpXV07XG4gIH1cblxuICByZXR1cm4gcmVzb2x2ZWRSaW5nT2Zmc2V0cztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldE11bHRpUG9seWdvblJlc29sdmVkT2Zmc2V0cyhkYXRhOiBnYS5kYXRhLk11bHRpUG9seWdvbkRhdGEpOiBJbnQzMkFycmF5IHtcbiAgY29uc3QgcG9seWdvbkRhdGEgPSBnYS5jaGlsZC5nZXRNdWx0aVBvbHlnb25DaGlsZChkYXRhKTtcbiAgY29uc3QgcmluZ0RhdGEgPSBnYS5jaGlsZC5nZXRQb2x5Z29uQ2hpbGQocG9seWdvbkRhdGEpO1xuXG4gIGNvbnN0IGdlb21PZmZzZXRzID0gZGF0YS52YWx1ZU9mZnNldHM7XG4gIGNvbnN0IHBvbHlnb25PZmZzZXRzID0gcG9seWdvbkRhdGEudmFsdWVPZmZzZXRzO1xuICBjb25zdCByaW5nT2Zmc2V0cyA9IHJpbmdEYXRhLnZhbHVlT2Zmc2V0cztcblxuICBjb25zdCByZXNvbHZlZFJpbmdPZmZzZXRzID0gbmV3IEludDMyQXJyYXkoZ2VvbU9mZnNldHMubGVuZ3RoKTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCByZXNvbHZlZFJpbmdPZmZzZXRzLmxlbmd0aDsgKytpKSB7XG4gICAgcmVzb2x2ZWRSaW5nT2Zmc2V0c1tpXSA9IHJpbmdPZmZzZXRzW3BvbHlnb25PZmZzZXRzW2dlb21PZmZzZXRzW2ldXV07XG4gIH1cblxuICByZXR1cm4gcmVzb2x2ZWRSaW5nT2Zmc2V0cztcbn1cblxuLyoqXG4gKiBJbnZlcnQgb2Zmc2V0cyBzbyB0aGF0IGxvb2t1cCBjYW4gZ28gaW4gdGhlIG9wcG9zaXRlIGRpcmVjdGlvblxuICovXG5leHBvcnQgZnVuY3Rpb24gaW52ZXJ0T2Zmc2V0cyhvZmZzZXRzOiBJbnQzMkFycmF5KTogVWludDhBcnJheSB8IFVpbnQxNkFycmF5IHwgVWludDMyQXJyYXkge1xuICBjb25zdCBsYXJnZXN0T2Zmc2V0ID0gb2Zmc2V0c1tvZmZzZXRzLmxlbmd0aCAtIDFdO1xuXG4gIGNvbnN0IGFycmF5Q29uc3RydWN0b3IgPVxuICAgIG9mZnNldHMubGVuZ3RoIDwgTWF0aC5wb3coMiwgOClcbiAgICAgID8gVWludDhBcnJheVxuICAgICAgOiBvZmZzZXRzLmxlbmd0aCA8IE1hdGgucG93KDIsIDE2KVxuICAgICAgPyBVaW50MTZBcnJheVxuICAgICAgOiBVaW50MzJBcnJheTtcblxuICBjb25zdCBpbnZlcnRlZE9mZnNldHMgPSBuZXcgYXJyYXlDb25zdHJ1Y3RvcihsYXJnZXN0T2Zmc2V0KTtcbiAgZm9yIChsZXQgYXJyYXlJZHggPSAwOyBhcnJheUlkeCA8IG9mZnNldHMubGVuZ3RoIC0gMTsgYXJyYXlJZHgrKykge1xuICAgIGNvbnN0IHRoaXNPZmZzZXQgPSBvZmZzZXRzW2FycmF5SWR4XTtcbiAgICBjb25zdCBuZXh0T2Zmc2V0ID0gb2Zmc2V0c1thcnJheUlkeCArIDFdO1xuICAgIGZvciAobGV0IG9mZnNldCA9IHRoaXNPZmZzZXQ7IG9mZnNldCA8IG5leHRPZmZzZXQ7IG9mZnNldCsrKSB7XG4gICAgICBpbnZlcnRlZE9mZnNldHNbb2Zmc2V0XSA9IGFycmF5SWR4O1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBpbnZlcnRlZE9mZnNldHM7XG59XG5cbi8vIFRPRE86IGJldHRlciB0eXBpbmdcbmV4cG9ydCBmdW5jdGlvbiBleHRyYWN0QWNjZXNzb3JzRnJvbVByb3BzKFxuICBwcm9wczogUmVjb3JkPHN0cmluZywgYW55PixcbiAgZXhjbHVkZUtleXM6IHN0cmluZ1tdXG4pOiBbUmVjb3JkPHN0cmluZywgYW55PiwgUmVjb3JkPHN0cmluZywgYW55Pl0ge1xuICBjb25zdCBhY2Nlc3NvcnM6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcbiAgY29uc3Qgb3RoZXJQcm9wczogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhwcm9wcykpIHtcbiAgICBpZiAoZXhjbHVkZUtleXMuaW5jbHVkZXMoa2V5KSkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgaWYgKGtleS5zdGFydHNXaXRoKCdnZXQnKSkge1xuICAgICAgYWNjZXNzb3JzW2tleV0gPSB2YWx1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgb3RoZXJQcm9wc1trZXldID0gdmFsdWU7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIFthY2Nlc3NvcnMsIG90aGVyUHJvcHNdO1xufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQU9BLElBQUFBLE1BQUEsR0FBQUMsT0FBQTtBQUNBLElBQUFDLEtBQUEsR0FBQUMsdUJBQUEsQ0FBQUYsT0FBQTtBQUNBLElBQUFHLEVBQUEsR0FBQUQsdUJBQUEsQ0FBQUYsT0FBQTtBQUE0QyxTQUFBSSx5QkFBQUMsQ0FBQSw2QkFBQUMsT0FBQSxtQkFBQUMsQ0FBQSxPQUFBRCxPQUFBLElBQUFFLENBQUEsT0FBQUYsT0FBQSxZQUFBRix3QkFBQSxZQUFBQSx5QkFBQUMsQ0FBQSxXQUFBQSxDQUFBLEdBQUFHLENBQUEsR0FBQUQsQ0FBQSxLQUFBRixDQUFBO0FBQUEsU0FBQUgsd0JBQUFHLENBQUEsRUFBQUUsQ0FBQSxTQUFBQSxDQUFBLElBQUFGLENBQUEsSUFBQUEsQ0FBQSxDQUFBSSxVQUFBLFNBQUFKLENBQUEsZUFBQUEsQ0FBQSxnQkFBQUssT0FBQSxDQUFBTCxDQUFBLDBCQUFBQSxDQUFBLHNCQUFBQSxDQUFBLFFBQUFHLENBQUEsR0FBQUosd0JBQUEsQ0FBQUcsQ0FBQSxPQUFBQyxDQUFBLElBQUFBLENBQUEsQ0FBQUcsR0FBQSxDQUFBTixDQUFBLFVBQUFHLENBQUEsQ0FBQUksR0FBQSxDQUFBUCxDQUFBLE9BQUFRLENBQUEsS0FBQUMsU0FBQSxVQUFBQyxDQUFBLEdBQUFDLE1BQUEsQ0FBQUMsY0FBQSxJQUFBRCxNQUFBLENBQUFFLHdCQUFBLFdBQUFDLENBQUEsSUFBQWQsQ0FBQSxvQkFBQWMsQ0FBQSxPQUFBQyxjQUFBLENBQUFDLElBQUEsQ0FBQWhC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