kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
462 lines (431 loc) • 56.8 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.addCustomPaletteColor = addCustomPaletteColor;
exports.addNewQuantativeColorBreakAtIndex = addNewQuantativeColorBreakAtIndex;
exports.colorMaybeToHex = colorMaybeToHex;
exports.colorMaybeToRGB = colorMaybeToRGB;
exports.colorRangeBackwardCompatibility = colorRangeBackwardCompatibility;
exports.createLinearGradient = createLinearGradient;
exports.hasColorMap = hasColorMap;
exports.hexToRgb = hexToRgb;
exports.initializeCustomPalette = initializeCustomPalette;
exports.interpolateHex = interpolateHex;
exports.isHexColor = isHexColor;
exports.isQuaPalette = isQuaPalette;
exports.isRgbColor = isRgbColor;
exports.normalizeColor = normalizeColor;
exports.paletteIsColorBlindSafe = paletteIsColorBlindSafe;
exports.paletteIsSteps = paletteIsSteps;
exports.paletteIsType = paletteIsType;
exports.removeCustomPaletteColor = removeCustomPaletteColor;
exports.reverseColorRange = reverseColorRange;
exports.rgbToHex = rgbToHex;
exports.sortCustomPaletteColor = sortCustomPaletteColor;
exports.updateColorRangeByMatchingPalette = updateColorRangeByMatchingPalette;
exports.updateColorRangeBySelectedPalette = updateColorRangeBySelectedPalette;
exports.updateCustomColorRangeByColorUI = updateCustomColorRangeByColorUI;
exports.updateCustomPaletteColor = updateCustomPaletteColor;
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _constants = require("@kepler.gl/constants");
var _commonUtils = require("@kepler.gl/common-utils");
var _d3Color = require("d3-color");
var _d3Interpolate = require("d3-interpolate");
var _utils = require("./utils");
var _console = _interopRequireDefault(require("global/console"));
var _excluded = ["colors"];
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } // SPDX-License-Identifier: MIT
// Copyright contributors to the kepler.gl project
/**
* get r g b from hex code
*
* @param hex
* @returns array of r g bs
*/
function hexToRgb(hex) {
var result = isHexColor(hex);
if (!result) {
return [0, 0, 0];
}
var r = parseInt(result[1], 16);
var g = parseInt(result[2], 16);
var b = parseInt(result[3], 16);
return [r, g, b];
}
function isHexColor(hex) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result;
}
function PadNum(c) {
var hex = c.toString(16);
return hex.length === 1 ? "0".concat(hex) : hex;
}
/**
* get hex from r g b
*
* @param rgb
* @returns hex string
*/
function rgbToHex(_ref) {
var _ref2 = (0, _slicedToArray2["default"])(_ref, 3),
r = _ref2[0],
g = _ref2[1],
b = _ref2[2];
return "#".concat([r, g, b].map(function (n) {
return PadNum(n);
}).join('')).toUpperCase();
}
/**
* Whether color range has custom color map
*/
function hasColorMap(colorRange) {
return Array.isArray(colorRange.colorMap) && Boolean(colorRange.colorMap.length);
}
/**
* given a list of rgb arrays it will generate a linear gradient css rule
* @param direction
* @param colors
* @return
*/
function createLinearGradient(direction, colors) {
var step = parseFloat((100.0 / colors.length).toFixed(2));
var bands = colors.map(function (rgb, index) {
return "rgba(".concat(rgb.join(','), ", 1) ").concat(step * index, "%, rgba(").concat(rgb.join(','), ", 1) ").concat(step * (index + 1), "%");
});
return "linear-gradient(to ".concat(direction, ", ").concat(bands.join(','), ")");
}
/**
* Convert color to RGB
*/
function colorMaybeToRGB(color) {
if (isRgbColor(color)) {
return color;
}
if (typeof color === 'string') {
var rgbObj = (0, _d3Color.rgb)(color);
if (Number.isFinite(rgbObj === null || rgbObj === void 0 ? void 0 : rgbObj.r) && Number.isFinite(rgbObj === null || rgbObj === void 0 ? void 0 : rgbObj.g) && Number.isFinite(rgbObj === null || rgbObj === void 0 ? void 0 : rgbObj.b)) {
return [rgbObj.r, rgbObj.g, rgbObj.b];
}
}
return null;
}
/**
* Whether color is rgb
* @returns
*/
function isRgbColor(color) {
return Boolean(color && Array.isArray(color) && color.length === 3 && color.every(function (n) {
return Number.isFinite(n) && n <= 255 && n >= 0;
}));
}
/**
* Take color values in 0-255 range and map to [0, 1]
*/
function normalizeColor(color) {
return color.map(function (component) {
return component / 255.0;
});
}
/**
* Convert color to Hex
*/
function colorMaybeToHex(color) {
var rgbColor = colorMaybeToRGB(color);
if (rgbColor) return rgbToHex(rgbColor);
return '#000000';
}
/**
* Convert color to Hex
*/
function interpolateHex(hex1, hex2) {
return (0, _d3Color.rgb)((0, _d3Interpolate.interpolate)(hex1, hex2)(0.5)).hex().toUpperCase();
}
function addNewCategoricalStepAtIndex(colorMap, index, newColor) {
if (!Array.isArray(colorMap) || !colorMap.length) {
return colorMap;
}
var newColorMap = colorMap.map(function (_ref3) {
var _ref4 = (0, _slicedToArray2["default"])(_ref3, 2),
val = _ref4[0],
c = _ref4[1];
return [Array.isArray(val) ? (0, _toConsumableArray2["default"])(val) : val, c];
});
newColorMap = (0, _utils.arrayInsert)(newColorMap, index + 1, [null, newColor]);
return newColorMap;
}
function addNewQuantativeColorBreakAtIndex(colorMap, index, newColors) {
if (!Array.isArray(colorMap) || !colorMap.length) {
return colorMap;
}
if (colorMap.length < 2) {
// less then 2, add 1 at end
// however shouldn't allow delete when there are 2
return newColors.map(function (c, i) {
return i === 0 ? colorMap[i] : [null, c];
});
}
// breaks should be 1 less than colors
var breaks = colorMap.map(function (cm) {
return cm[0];
}).slice(0, colorMap.length - 1);
// insert new break
var newValue = index >= breaks.length - 1 ? breaks[breaks.length - 1] + (breaks.length > 1 ? breaks[breaks.length - 1] - breaks[breaks.length - 2] : 0) : (breaks[index] + breaks[index + 1]) / 2;
var newBreaks = (0, _utils.arrayInsert)(breaks, index + 1, newValue);
// asign breaks to color
return newColors.map(function (c, i) {
return i === newColors.length - 1 ? [null, c] : [newBreaks[i] === undefined ? null : newBreaks[i], c];
});
}
/**
* Add a new color to custom palette
*/
function addCustomPaletteColor(customPalette, index) {
var colors = customPalette.colors,
colorMap = customPalette.colorMap;
var update = {};
var newColor = index === colors.length - 1 ? colors[index] : interpolateHex(colors[index], colors[index + 1]);
update.colors = (0, _utils.arrayInsert)(colors, index + 1, newColor);
// add color to colorMap
if (colorMap) {
update.colorMap = customPalette.type === 'customOrdinal' ? addNewCategoricalStepAtIndex(colorMap, index, newColor) : addNewQuantativeColorBreakAtIndex(colorMap, index, update.colors);
}
return _objectSpread(_objectSpread({}, customPalette), update);
}
function replaceColorsInColorRange(colorRange, newColors) {
var oldColors = colorRange.colors;
var updated = _objectSpread(_objectSpread({}, colorRange), {}, {
colors: newColors
});
// update color map
// keep value, replace color
if (Array.isArray(updated.colorMap)) {
updated.colorMap = updated.colorMap.map(function (cm, i) {
return [cm[0], newColors[i]];
});
}
// update colorlegends
// keep value, replace color
if (updated.colorLegends) {
updated.colorLegends = Object.keys(updated.colorLegends).reduce(function (accu, key) {
var colorIdx = oldColors.findIndex(function (c) {
return c === key;
});
var newColor = newColors[colorIdx];
return newColor ? _objectSpread(_objectSpread({}, accu), {}, (0, _defineProperty2["default"])({}, newColor, updated.colorLegends[key])) : accu;
}, {});
}
return updated;
}
/**
* Sort custom palette
*/
function sortCustomPaletteColor(customPalette, oldIndex, newIndex) {
var colors = customPalette.colors;
var newColors = (0, _commonUtils.arrayMove)(colors, oldIndex, newIndex);
var update = replaceColorsInColorRange(customPalette, newColors);
// @ts-ignore
return _objectSpread(_objectSpread({}, customPalette), update);
}
/**
* remove a color in custom palette at index
*/
function removeCustomPaletteColor(customPalette, index) {
var colors = customPalette.colors,
colorMap = customPalette.colorMap,
colorLegends = customPalette.colorLegends;
var oldValue = colors[index];
var update = {};
update.colors = (0, _toConsumableArray2["default"])(colors);
if (update.colors.length > 1) {
update.colors.splice(index, 1);
}
// update color map
if (Array.isArray(colorMap)) {
// find colorMap index
var colorMapIndex = colorMap.findIndex(function (cm) {
return cm[1] === oldValue;
});
if (colorMapIndex >= 0) {
update.colorMap = (0, _toConsumableArray2["default"])(colorMap);
update.colorMap.splice(colorMapIndex, 1);
}
}
// update color legend
if (colorLegends !== null && colorLegends !== void 0 && colorLegends[oldValue]) {
update.colorLegends = _objectSpread({}, colorLegends);
delete update.colorLegends[oldValue];
}
return _objectSpread(_objectSpread({}, customPalette), update);
}
/**
* Update a color in custom palette at index
*/
function updateCustomPaletteColor(customPalette, index, newValue) {
var colors = customPalette.colors;
var hex = newValue.toUpperCase();
var newColors = (0, _toConsumableArray2["default"])(colors);
newColors[index] = hex;
var update = replaceColorsInColorRange(customPalette, newColors);
// @ts-ignore
return _objectSpread(_objectSpread({}, customPalette), update);
}
/**
* Get a reversed colorRange
*/
function reverseColorRange(reversed, colorRange) {
var newColors = colorRange === null || colorRange === void 0 ? void 0 : colorRange.colors.slice().reverse();
var updated = replaceColorsInColorRange(colorRange, newColors);
updated.reversed = reversed;
return updated;
}
/**
* Whether palette matches current ColorBlindSafe config
*/
function paletteIsColorBlindSafe(palette, colorBlindSafe) {
return !colorBlindSafe || colorBlindSafe && palette.colorBlindSafe;
}
/**
* Whether palette matches current steps config
*/
function isQuaPalette(palette) {
return palette.type === _constants.PALETTE_TYPES.QUA;
}
/**
* Whether palette matches current steps config
*/
function paletteIsSteps(palette, steps) {
return !isQuaPalette(palette) || palette.maxStep >= steps;
}
/**
* Whether palette matches current type config
*/
function paletteIsType(palette, type) {
return type === 'all' || type === palette.type;
}
/**
* Find best match palette based on config, update color range by it
*/
function updateColorRangeByMatchingPalette(currentColorRange, config) {
var steps = config.steps,
colorBlindSafe = config.colorBlindSafe,
type = config.type;
var matchingPalette = _constants.KEPLER_COLOR_PALETTES.filter(function (palette) {
return (
// palette match type
paletteIsType(palette, type) &&
// palette has same step
paletteIsSteps(palette, steps) &&
// palette is colorBlindSafe
paletteIsColorBlindSafe(palette, colorBlindSafe)
);
});
var bestMatch = matchingPalette.length ? matchingPalette.find(function (p) {
return p.name === currentColorRange.name;
}) || matchingPalette[0] : null;
if (bestMatch) {
return updateColorRangeBySelectedPalette(currentColorRange, bestMatch, config);
}
// we do nothing
_console["default"].warn("we cant find any preset palette matches requirments: steps=".concat(steps, " && colorBlindSafe=").concat(colorBlindSafe));
return currentColorRange;
}
/**
* Update custom palette when reverse the colors in custom palette, since changing 'steps',
* 'colorBindSafe', 'type' should fall back to predefined palette.
*/
function updateCustomColorRangeByColorUI(oldColorRange, colorConfig) {
var reversed = colorConfig.reversed;
var colors = oldColorRange.colors;
// for custom palette, one can only 'reverse' the colors in custom palette.
colors.reverse();
var colorRange = _objectSpread(_objectSpread(_objectSpread({
name: oldColorRange.name,
type: oldColorRange.type,
category: oldColorRange.category,
colors: colors
}, reversed ? {
reversed: reversed
} : {}), oldColorRange.colorMap ? {
colorMap: oldColorRange.colorMap
} : {}), oldColorRange.colorLegends ? {
colorLegends: oldColorRange.colorLegends
} : {});
return replaceColorsInColorRange(colorRange, colorRange.colors);
}
/**
* Update color range after selecting a palette from color range selectoer
* Copy over colorMap and colorLegends
*/
function updateColorRangeBySelectedPalette(oldColorRange, colorPalette, colorConfig) {
var _colorPaletteToColorR = (0, _constants.colorPaletteToColorRange)(colorPalette, colorConfig),
newColors = _colorPaletteToColorR.colors,
newColorRange = (0, _objectWithoutProperties2["default"])(_colorPaletteToColorR, _excluded);
var colorRange = _objectSpread(_objectSpread(_objectSpread({
colors: oldColorRange.colors
}, newColorRange), oldColorRange.colorMap ? {
colorMap: oldColorRange.colorMap
} : {}), oldColorRange.colorLegends ? {
colorLegends: oldColorRange.colorLegends
} : {});
return replaceColorsInColorRange(colorRange, newColors);
}
var UberNameRegex = new RegExp(/^([A-Za-z ])+/g);
var ColorBrewerRegex = new RegExp(/^ColorBrewer ([A-Za-z1-9])+/g);
/**
* convert saved colorRange to colorPalette objevt type/name/category/isColorBlind
*/
function colorRangeBackwardCompatibility(colorRange) {
if (!colorRange || colorRange.type === 'custom' || colorRange.colorMap) {
// don't do anything to custom color palette, or palette with custom breaks
return colorRange;
}
var trimName;
if (colorRange.category === 'Uber') {
var _colorRange$name;
var matchName = ((_colorRange$name = colorRange.name) !== null && _colorRange$name !== void 0 ? _colorRange$name : '').match(UberNameRegex);
trimName = matchName ? matchName[0].trim() : null;
// match Uber Viz Qualitative 1.4 -> Uber Viz Qualitative
} else if (colorRange.category === 'ColorBrewer') {
var _colorRange$name2;
var _matchName = ((_colorRange$name2 = colorRange.name) !== null && _colorRange$name2 !== void 0 ? _colorRange$name2 : '').match(ColorBrewerRegex);
trimName = _matchName ? _matchName[0].replace('ColorBrewer ', '').trim() : null;
}
if (trimName) {
var matchingPalette = _constants.KEPLER_COLOR_PALETTES.find(function (p) {
return p.name === trimName;
});
if (matchingPalette) {
return _objectSpread(_objectSpread({}, colorRange), {}, {
name: trimName,
type: matchingPalette === null || matchingPalette === void 0 ? void 0 : matchingPalette.type,
category: matchingPalette.category
});
}
}
return colorRange;
}
/**
* Initialize custom palette from current standard color range object
*/
function initializeCustomPalette(colorRange, colorMap) {
// TODO: check on `isReversed` key, whether we can remove it here
var customPalette = _objectSpread(_objectSpread({}, colorRange), {}, {
name: _constants.DEFAULT_CUSTOM_PALETTE.name,
type: _constants.DEFAULT_CUSTOM_PALETTE.type,
category: _constants.DEFAULT_CUSTOM_PALETTE.category
}, colorMap ? {
colorMap: colorMap
} : {});
// only customPalette.colors are needed for custom palette editor with custom ordinal scale
if (!colorMap && colorRange.type === _constants.SCALE_TYPES.customOrdinal) {
delete customPalette.colorMap;
}
return customPalette;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfY29uc3RhbnRzIiwicmVxdWlyZSIsIl9jb21tb25VdGlscyIsIl9kM0NvbG9yIiwiX2QzSW50ZXJwb2xhdGUiLCJfdXRpbHMiLCJfY29uc29sZSIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJfZXhjbHVkZWQiLCJvd25LZXlzIiwiZSIsInIiLCJ0IiwiT2JqZWN0Iiwia2V5cyIsImdldE93blByb3BlcnR5U3ltYm9scyIsIm8iLCJmaWx0ZXIiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJlbnVtZXJhYmxlIiwicHVzaCIsImFwcGx5IiwiX29iamVjdFNwcmVhZCIsImFyZ3VtZW50cyIsImxlbmd0aCIsImZvckVhY2giLCJfZGVmaW5lUHJvcGVydHkyIiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9ycyIsImRlZmluZVByb3BlcnRpZXMiLCJkZWZpbmVQcm9wZXJ0eSIsImhleFRvUmdiIiwiaGV4IiwicmVzdWx0IiwiaXNIZXhDb2xvciIsInBhcnNlSW50IiwiZyIsImIiLCJleGVjIiwiUGFkTnVtIiwiYyIsInRvU3RyaW5nIiwiY29uY2F0IiwicmdiVG9IZXgiLCJfcmVmIiwiX3JlZjIiLCJfc2xpY2VkVG9BcnJheTIiLCJtYXAiLCJuIiwiam9pbiIsInRvVXBwZXJDYXNlIiwiaGFzQ29sb3JNYXAiLCJjb2xvclJhbmdlIiwiQXJyYXkiLCJpc0FycmF5IiwiY29sb3JNYXAiLCJCb29sZWFuIiwiY3JlYXRlTGluZWFyR3JhZGllbnQiLCJkaXJlY3Rpb24iLCJjb2xvcnMiLCJzdGVwIiwicGFyc2VGbG9hdCIsInRvRml4ZWQiLCJiYW5kcyIsInJnYiIsImluZGV4IiwiY29sb3JNYXliZVRvUkdCIiwiY29sb3IiLCJpc1JnYkNvbG9yIiwicmdiT2JqIiwiZDNSZ2IiLCJOdW1iZXIiLCJpc0Zpbml0ZSIsImV2ZXJ5Iiwibm9ybWFsaXplQ29sb3IiLCJjb21wb25lbnQiLCJjb2xvck1heWJlVG9IZXgiLCJyZ2JDb2xvciIsImludGVycG9sYXRlSGV4IiwiaGV4MSIsImhleDIiLCJpbnRlcnBvbGF0ZSIsImFkZE5ld0NhdGVnb3JpY2FsU3RlcEF0SW5kZXgiLCJuZXdDb2xvciIsIm5ld0NvbG9yTWFwIiwiX3JlZjMiLCJfcmVmNCIsInZhbCIsIl90b0NvbnN1bWFibGVBcnJheTIiLCJhcnJheUluc2VydCIsImFkZE5ld1F1YW50YXRpdmVDb2xvckJyZWFrQXRJbmRleCIsIm5ld0NvbG9ycyIsImkiLCJicmVha3MiLCJjbSIsInNsaWNlIiwibmV3VmFsdWUiLCJuZXdCcmVha3MiLCJ1bmRlZmluZWQiLCJhZGRDdXN0b21QYWxldHRlQ29sb3IiLCJjdXN0b21QYWxldHRlIiwidXBkYXRlIiwidHlwZSIsInJlcGxhY2VDb2xvcnNJbkNvbG9yUmFuZ2UiLCJvbGRDb2xvcnMiLCJ1cGRhdGVkIiwiY29sb3JMZWdlbmRzIiwicmVkdWNlIiwiYWNjdSIsImtleSIsImNvbG9ySWR4IiwiZmluZEluZGV4Iiwic29ydEN1c3RvbVBhbGV0dGVDb2xvciIsIm9sZEluZGV4IiwibmV3SW5kZXgiLCJhcnJheU1vdmUiLCJyZW1vdmVDdXN0b21QYWxldHRlQ29sb3IiLCJvbGRWYWx1ZSIsInNwbGljZSIsImNvbG9yTWFwSW5kZXgiLCJ1cGRhdGVDdXN0b21QYWxldHRlQ29sb3IiLCJyZXZlcnNlQ29sb3JSYW5nZSIsInJldmVyc2VkIiwicmV2ZXJzZSIsInBhbGV0dGVJc0NvbG9yQmxpbmRTYWZlIiwicGFsZXR0ZSIsImNvbG9yQmxpbmRTYWZlIiwiaXNRdWFQYWxldHRlIiwiUEFMRVRURV9UWVBFUyIsIlFVQSIsInBhbGV0dGVJc1N0ZXBzIiwic3RlcHMiLCJtYXhTdGVwIiwicGFsZXR0ZUlzVHlwZSIsInVwZGF0ZUNvbG9yUmFuZ2VCeU1hdGNoaW5nUGFsZXR0ZSIsImN1cnJlbnRDb2xvclJhbmdlIiwiY29uZmlnIiwibWF0Y2hpbmdQYWxldHRlIiwiS0VQTEVSX0NPTE9SX1BBTEVUVEVTIiwiYmVzdE1hdGNoIiwiZmluZCIsInAiLCJuYW1lIiwidXBkYXRlQ29sb3JSYW5nZUJ5U2VsZWN0ZWRQYWxldHRlIiwiQ29uc29sZSIsIndhcm4iLCJ1cGRhdGVDdXN0b21Db2xvclJhbmdlQnlDb2xvclVJIiwib2xkQ29sb3JSYW5nZSIsImNvbG9yQ29uZmlnIiwiY2F0ZWdvcnkiLCJjb2xvclBhbGV0dGUiLCJfY29sb3JQYWxldHRlVG9Db2xvclIiLCJjb2xvclBhbGV0dGVUb0NvbG9yUmFuZ2UiLCJuZXdDb2xvclJhbmdlIiwiX29iamVjdFdpdGhvdXRQcm9wZXJ0aWVzMiIsIlViZXJOYW1lUmVnZXgiLCJSZWdFeHAiLCJDb2xvckJyZXdlclJlZ2V4IiwiY29sb3JSYW5nZUJhY2t3YXJkQ29tcGF0aWJpbGl0eSIsInRyaW1OYW1lIiwiX2NvbG9yUmFuZ2UkbmFtZSIsIm1hdGNoTmFtZSIsIm1hdGNoIiwidHJpbSIsIl9jb2xvclJhbmdlJG5hbWUyIiwicmVwbGFjZSIsImluaXRpYWxpemVDdXN0b21QYWxldHRlIiwiREVGQVVMVF9DVVNUT01fUEFMRVRURSIsIlNDQUxFX1RZUEVTIiwiY3VzdG9tT3JkaW5hbCJdLCJzb3VyY2VzIjpbIi4uL3NyYy9jb2xvci11dGlscy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogTUlUXG4vLyBDb3B5cmlnaHQgY29udHJpYnV0b3JzIHRvIHRoZSBrZXBsZXIuZ2wgcHJvamVjdFxuXG5pbXBvcnQge1xuICBDYXRlZ29yaWNhbFBhbGV0dGUsXG4gIENvbG9yUGFsZXR0ZSxcbiAgREVGQVVMVF9DVVNUT01fUEFMRVRURSxcbiAgY29sb3JQYWxldHRlVG9Db2xvclJhbmdlXG59IGZyb20gJ0BrZXBsZXIuZ2wvY29uc3RhbnRzJztcbmltcG9ydCB7YXJyYXlNb3ZlfSBmcm9tICdAa2VwbGVyLmdsL2NvbW1vbi11dGlscyc7XG5pbXBvcnQge1xuICBDb2xvck1hcCxcbiAgQ29sb3JSYW5nZSxcbiAgQ29sb3JSYW5nZUNvbmZpZyxcbiAgSGV4Q29sb3IsXG4gIFJHQkFDb2xvcixcbiAgUkdCQ29sb3Jcbn0gZnJvbSAnQGtlcGxlci5nbC90eXBlcyc7XG5pbXBvcnQge3JnYiBhcyBkM1JnYn0gZnJvbSAnZDMtY29sb3InO1xuaW1wb3J0IHtpbnRlcnBvbGF0ZX0gZnJvbSAnZDMtaW50ZXJwb2xhdGUnO1xuaW1wb3J0IHthcnJheUluc2VydH0gZnJvbSAnLi91dGlscyc7XG5pbXBvcnQgQ29uc29sZSBmcm9tICdnbG9iYWwvY29uc29sZSc7XG5pbXBvcnQge0tFUExFUl9DT0xPUl9QQUxFVFRFUywgUEFMRVRURV9UWVBFUywgU0NBTEVfVFlQRVN9IGZyb20gJ0BrZXBsZXIuZ2wvY29uc3RhbnRzJztcblxuLyoqXG4gKiBnZXQgciBnIGIgZnJvbSBoZXggY29kZVxuICpcbiAqIEBwYXJhbSBoZXhcbiAqIEByZXR1cm5zIGFycmF5IG9mIHIgZyBic1xuICovXG5leHBvcnQgZnVuY3Rpb24gaGV4VG9SZ2IoaGV4OiBzdHJpbmcpOiBSR0JDb2xvciB7XG4gIGNvbnN0IHJlc3VsdCA9IGlzSGV4Q29sb3IoaGV4KTtcblxuICBpZiAoIXJlc3VsdCkge1xuICAgIHJldHVybiBbMCwgMCwgMF07XG4gIH1cblxuICBjb25zdCByID0gcGFyc2VJbnQocmVzdWx0WzFdLCAxNik7XG4gIGNvbnN0IGcgPSBwYXJzZUludChyZXN1bHRbMl0sIDE2KTtcbiAgY29uc3QgYiA9IHBhcnNlSW50KHJlc3VsdFszXSwgMTYpO1xuXG4gIHJldHVybiBbciwgZywgYl07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc0hleENvbG9yKGhleDogc3RyaW5nKTogUmVnRXhwRXhlY0FycmF5IHwgbnVsbCB7XG4gIGNvbnN0IHJlc3VsdCA9IC9eIz8oW2EtZlxcZF17Mn0pKFthLWZcXGRdezJ9KShbYS1mXFxkXXsyfSkkL2kuZXhlYyhoZXgpO1xuXG4gIHJldHVybiByZXN1bHQ7XG59XG5cbmZ1bmN0aW9uIFBhZE51bShjKSB7XG4gIGNvbnN0IGhleCA9IGMudG9TdHJpbmcoMTYpO1xuICByZXR1cm4gaGV4Lmxlbmd0aCA9PT0gMSA/IGAwJHtoZXh9YCA6IGhleDtcbn1cblxuLyoqXG4gKiBnZXQgaGV4IGZyb20gciBnIGJcbiAqXG4gKiBAcGFyYW0gcmdiXG4gKiBAcmV0dXJucyBoZXggc3RyaW5nXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZ2JUb0hleChbciwgZywgYl06IFJHQkNvbG9yIHwgUkdCQUNvbG9yKTogSGV4Q29sb3Ige1xuICByZXR1cm4gYCMke1tyLCBnLCBiXS5tYXAobiA9PiBQYWROdW0obikpLmpvaW4oJycpfWAudG9VcHBlckNhc2UoKTtcbn1cblxuLyoqXG4gKiBXaGV0aGVyIGNvbG9yIHJhbmdlIGhhcyBjdXN0b20gY29sb3IgbWFwXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYXNDb2xvck1hcChjb2xvclJhbmdlOiBDb2xvclJhbmdlKTogYm9vbGVhbiB7XG4gIHJldHVybiBBcnJheS5pc0FycmF5KGNvbG9yUmFuZ2UuY29sb3JNYXApICYmIEJvb2xlYW4oY29sb3JSYW5nZS5jb2xvck1hcC5sZW5ndGgpO1xufVxuXG4vKipcbiAqIGdpdmVuIGEgbGlzdCBvZiByZ2IgYXJyYXlzIGl0IHdpbGwgZ2VuZXJhdGUgYSBsaW5lYXIgZ3JhZGllbnQgY3NzIHJ1bGVcbiAqIEBwYXJhbSBkaXJlY3Rpb25cbiAqIEBwYXJhbSBjb2xvcnNcbiAqIEByZXR1cm5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUxpbmVhckdyYWRpZW50KGRpcmVjdGlvbjogc3RyaW5nLCBjb2xvcnM6IFJHQkNvbG9yW10pOiBzdHJpbmcge1xuICBjb25zdCBzdGVwID0gcGFyc2VGbG9hdCgoMTAwLjAgLyBjb2xvcnMubGVuZ3RoKS50b0ZpeGVkKDIpKTtcbiAgY29uc3QgYmFuZHMgPSBjb2xvcnMubWFwKChyZ2IsIGluZGV4KSA9PiB7XG4gICAgcmV0dXJuIGByZ2JhKCR7cmdiLmpvaW4oJywnKX0sIDEpICR7c3RlcCAqIGluZGV4fSUsIHJnYmEoJHtyZ2Iuam9pbignLCcpfSwgMSkgJHtcbiAgICAgIHN0ZXAgKiAoaW5kZXggKyAxKVxuICAgIH0lYDtcbiAgfSk7XG5cbiAgcmV0dXJuIGBsaW5lYXItZ3JhZGllbnQodG8gJHtkaXJlY3Rpb259LCAke2JhbmRzLmpvaW4oJywnKX0pYDtcbn1cblxuLyoqXG4gKiBDb252ZXJ0IGNvbG9yIHRvIFJHQlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29sb3JNYXliZVRvUkdCKGNvbG9yOiB1bmtub3duKTogUkdCQ29sb3IgfCBudWxsIHtcbiAgaWYgKGlzUmdiQ29sb3IoY29sb3IpKSB7XG4gICAgcmV0dXJuIGNvbG9yIGFzIFJHQkNvbG9yO1xuICB9XG5cbiAgaWYgKHR5cGVvZiBjb2xvciA9PT0gJ3N0cmluZycpIHtcbiAgICBjb25zdCByZ2JPYmogPSBkM1JnYihjb2xvcik7XG4gICAgaWYgKE51bWJlci5pc0Zpbml0ZShyZ2JPYmo/LnIpICYmIE51bWJlci5pc0Zpbml0ZShyZ2JPYmo/LmcpICYmIE51bWJlci5pc0Zpbml0ZShyZ2JPYmo/LmIpKSB7XG4gICAgICByZXR1cm4gW3JnYk9iai5yLCByZ2JPYmouZywgcmdiT2JqLmJdO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBudWxsO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgY29sb3IgaXMgcmdiXG4gKiBAcmV0dXJuc1xuICovXG5leHBvcnQgZnVuY3Rpb24gaXNSZ2JDb2xvcihjb2xvcjogdW5rbm93bik6IGJvb2xlYW4ge1xuICByZXR1cm4gQm9vbGVhbihcbiAgICBjb2xvciAmJlxuICAgICAgQXJyYXkuaXNBcnJheShjb2xvcikgJiZcbiAgICAgIGNvbG9yLmxlbmd0aCA9PT0gMyAmJlxuICAgICAgY29sb3IuZXZlcnkobiA9PiBOdW1iZXIuaXNGaW5pdGUobikgJiYgbiA8PSAyNTUgJiYgbiA+PSAwKVxuICApO1xufVxuXG4vKipcbiAqIFRha2UgY29sb3IgdmFsdWVzIGluIDAtMjU1IHJhbmdlIGFuZCBtYXAgdG8gWzAsIDFdXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBub3JtYWxpemVDb2xvcihjb2xvcjogbnVtYmVyW10pOiBudW1iZXJbXSB7XG4gIHJldHVybiBjb2xvci5tYXAoY29tcG9uZW50ID0+IGNvbXBvbmVudCAvIDI1NS4wKTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0IGNvbG9yIHRvIEhleFxuICovXG5leHBvcnQgZnVuY3Rpb24gY29sb3JNYXliZVRvSGV4KGNvbG9yOiB1bmtub3duKTogSGV4Q29sb3Ige1xuICBjb25zdCByZ2JDb2xvciA9IGNvbG9yTWF5YmVUb1JHQihjb2xvcik7XG4gIGlmIChyZ2JDb2xvcikgcmV0dXJuIHJnYlRvSGV4KHJnYkNvbG9yKTtcbiAgcmV0dXJuICcjMDAwMDAwJztcbn1cblxuLyoqXG4gKiBDb252ZXJ0IGNvbG9yIHRvIEhleFxuICovXG5cbmV4cG9ydCBmdW5jdGlvbiBpbnRlcnBvbGF0ZUhleChoZXgxOiBIZXhDb2xvciwgaGV4MjogSGV4Q29sb3IpOiBIZXhDb2xvciB7XG4gIHJldHVybiBkM1JnYihpbnRlcnBvbGF0ZShoZXgxLCBoZXgyKSgwLjUpKS5oZXgoKS50b1VwcGVyQ2FzZSgpO1xufVxuXG5mdW5jdGlvbiBhZGROZXdDYXRlZ29yaWNhbFN0ZXBBdEluZGV4KGNvbG9yTWFwLCBpbmRleCwgbmV3Q29sb3IpIHtcbiAgaWYgKCFBcnJheS5pc0FycmF5KGNvbG9yTWFwKSB8fCAhY29sb3JNYXAubGVuZ3RoKSB7XG4gICAgcmV0dXJuIGNvbG9yTWFwO1xuICB9XG5cbiAgbGV0IG5ld0NvbG9yTWFwID0gY29sb3JNYXAubWFwKChbdmFsLCBjXSkgPT4gW0FycmF5LmlzQXJyYXkodmFsKSA/IFsuLi52YWxdIDogdmFsLCBjXSk7XG4gIG5ld0NvbG9yTWFwID0gYXJyYXlJbnNlcnQobmV3Q29sb3JNYXAsIGluZGV4ICsgMSwgW251bGwsIG5ld0NvbG9yXSk7XG5cbiAgcmV0dXJuIG5ld0NvbG9yTWFwO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gYWRkTmV3UXVhbnRhdGl2ZUNvbG9yQnJlYWtBdEluZGV4KGNvbG9yTWFwLCBpbmRleCwgbmV3Q29sb3JzKSB7XG4gIGlmICghQXJyYXkuaXNBcnJheShjb2xvck1hcCkgfHwgIWNvbG9yTWFwLmxlbmd0aCkge1xuICAgIHJldHVybiBjb2xvck1hcDtcbiAgfVxuXG4gIGlmIChjb2xvck1hcC5sZW5ndGggPCAyKSB7XG4gICAgLy8gbGVzcyB0aGVuIDIsIGFkZCAxIGF0IGVuZFxuICAgIC8vIGhvd2V2ZXIgc2hvdWxkbid0IGFsbG93IGRlbGV0ZSB3aGVuIHRoZXJlIGFyZSAyXG4gICAgcmV0dXJuIG5ld0NvbG9ycy5tYXAoKGMsIGkpID0+IChpID09PSAwID8gY29sb3JNYXBbaV0gOiBbbnVsbCwgY10pKTtcbiAgfVxuXG4gIC8vIGJyZWFrcyBzaG91bGQgYmUgMSBsZXNzIHRoYW4gY29sb3JzXG4gIGNvbnN0IGJyZWFrcyA9IGNvbG9yTWFwLm1hcChjbSA9PiBjbVswXSkuc2xpY2UoMCwgY29sb3JNYXAubGVuZ3RoIC0gMSk7XG5cbiAgLy8gaW5zZXJ0IG5ldyBicmVha1xuICBjb25zdCBuZXdWYWx1ZSA9XG4gICAgaW5kZXggPj0gYnJlYWtzLmxlbmd0aCAtIDFcbiAgICAgID8gYnJlYWtzW2JyZWFrcy5sZW5ndGggLSAxXSArXG4gICAgICAgIChicmVha3MubGVuZ3RoID4gMSA/IGJyZWFrc1ticmVha3MubGVuZ3RoIC0gMV0gLSBicmVha3NbYnJlYWtzLmxlbmd0aCAtIDJdIDogMClcbiAgICAgIDogKGJyZWFrc1tpbmRleF0gKyBicmVha3NbaW5kZXggKyAxXSkgLyAyO1xuXG4gIGNvbnN0IG5ld0JyZWFrcyA9IGFycmF5SW5zZXJ0KGJyZWFrcywgaW5kZXggKyAxLCBuZXdWYWx1ZSk7XG5cbiAgLy8gYXNpZ24gYnJlYWtzIHRvIGNvbG9yXG4gIHJldHVybiBuZXdDb2xvcnMubWFwKChjLCBpKSA9PlxuICAgIGkgPT09IG5ld0NvbG9ycy5sZW5ndGggLSAxID8gW251bGwsIGNdIDogW25ld0JyZWFrc1tpXSA9PT0gdW5kZWZpbmVkID8gbnVsbCA6IG5ld0JyZWFrc1tpXSwgY11cbiAgKTtcbn1cblxuLyoqXG4gKiBBZGQgYSBuZXcgY29sb3IgdG8gY3VzdG9tIHBhbGV0dGVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFkZEN1c3RvbVBhbGV0dGVDb2xvcihjdXN0b21QYWxldHRlOiBDb2xvclJhbmdlLCBpbmRleDogbnVtYmVyKTogQ29sb3JSYW5nZSB7XG4gIGNvbnN0IHtjb2xvcnMsIGNvbG9yTWFwfSA9IGN1c3RvbVBhbGV0dGU7XG4gIGNvbnN0IHVwZGF0ZTogUGFydGlhbDxDb2xvclJhbmdlPiA9IHt9O1xuXG4gIGNvbnN0IG5ld0NvbG9yID1cbiAgICBpbmRleCA9PT0gY29sb3JzLmxlbmd0aCAtIDEgPyBjb2xvcnNbaW5kZXhdIDogaW50ZXJwb2xhdGVIZXgoY29sb3JzW2luZGV4XSwgY29sb3JzW2luZGV4ICsgMV0pO1xuXG4gIHVwZGF0ZS5jb2xvcnMgPSBhcnJheUluc2VydChjb2xvcnMsIGluZGV4ICsgMSwgbmV3Q29sb3IpO1xuXG4gIC8vIGFkZCBjb2xvciB0byBjb2xvck1hcFxuICBpZiAoY29sb3JNYXApIHtcbiAgICB1cGRhdGUuY29sb3JNYXAgPVxuICAgICAgY3VzdG9tUGFsZXR0ZS50eXBlID09PSAnY3VzdG9tT3JkaW5hbCdcbiAgICAgICAgPyBhZGROZXdDYXRlZ29yaWNhbFN0ZXBBdEluZGV4KGNvbG9yTWFwLCBpbmRleCwgbmV3Q29sb3IpXG4gICAgICAgIDogYWRkTmV3UXVhbnRhdGl2ZUNvbG9yQnJlYWtBdEluZGV4KGNvbG9yTWFwLCBpbmRleCwgdXBkYXRlLmNvbG9ycyk7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIC4uLmN1c3RvbVBhbGV0dGUsXG4gICAgLi4udXBkYXRlXG4gIH07XG59XG5cbmZ1bmN0aW9uIHJlcGxhY2VDb2xvcnNJbkNvbG9yUmFuZ2UoY29sb3JSYW5nZSwgbmV3Q29sb3JzKSB7XG4gIGNvbnN0IG9sZENvbG9ycyA9IGNvbG9yUmFuZ2UuY29sb3JzO1xuICBjb25zdCB1cGRhdGVkID0ge1xuICAgIC4uLmNvbG9yUmFuZ2UsXG4gICAgY29sb3JzOiBuZXdDb2xvcnNcbiAgfTtcblxuICAvLyB1cGRhdGUgY29sb3IgbWFwXG4gIC8vIGtlZXAgdmFsdWUsIHJlcGxhY2UgY29sb3JcbiAgaWYgKEFycmF5LmlzQXJyYXkodXBkYXRlZC5jb2xvck1hcCkpIHtcbiAgICB1cGRhdGVkLmNvbG9yTWFwID0gdXBkYXRlZC5jb2xvck1hcC5tYXAoKGNtLCBpKSA9PiBbY21bMF0sIG5ld0NvbG9yc1tpXV0pO1xuICB9XG4gIC8vIHVwZGF0ZSBjb2xvcmxlZ2VuZHNcbiAgLy8ga2VlcCB2YWx1ZSwgcmVwbGFjZSBjb2xvclxuICBpZiAodXBkYXRlZC5jb2xvckxlZ2VuZHMpIHtcbiAgICB1cGRhdGVkLmNvbG9yTGVnZW5kcyA9IE9iamVjdC5rZXlzKHVwZGF0ZWQuY29sb3JMZWdlbmRzKS5yZWR1Y2UoKGFjY3UsIGtleSkgPT4ge1xuICAgICAgY29uc3QgY29sb3JJZHggPSBvbGRDb2xvcnMuZmluZEluZGV4KGMgPT4gYyA9PT0ga2V5KTtcbiAgICAgIGNvbnN0IG5ld0NvbG9yID0gbmV3Q29sb3JzW2NvbG9ySWR4XTtcblxuICAgICAgcmV0dXJuIG5ld0NvbG9yXG4gICAgICAgID8ge1xuICAgICAgICAgICAgLi4uYWNjdSxcbiAgICAgICAgICAgIFtuZXdDb2xvcl06IHVwZGF0ZWQuY29sb3JMZWdlbmRzW2tleV1cbiAgICAgICAgICB9XG4gICAgICAgIDogYWNjdTtcbiAgICB9LCB7fSk7XG4gIH1cblxuICByZXR1cm4gdXBkYXRlZDtcbn1cblxuLyoqXG4gKiBTb3J0IGN1c3RvbSBwYWxldHRlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzb3J0Q3VzdG9tUGFsZXR0ZUNvbG9yKFxuICBjdXN0b21QYWxldHRlOiBDb2xvclJhbmdlLFxuICBvbGRJbmRleDogbnVtYmVyLFxuICBuZXdJbmRleDogbnVtYmVyXG4pOiBDb2xvclJhbmdlIHtcbiAgY29uc3Qge2NvbG9yc30gPSBjdXN0b21QYWxldHRlO1xuXG4gIGNvbnN0IG5ld0NvbG9ycyA9IGFycmF5TW92ZShjb2xvcnMsIG9sZEluZGV4LCBuZXdJbmRleCk7XG4gIGNvbnN0IHVwZGF0ZSA9IHJlcGxhY2VDb2xvcnNJbkNvbG9yUmFuZ2UoY3VzdG9tUGFsZXR0ZSwgbmV3Q29sb3JzKTtcblxuICAvLyBAdHMtaWdub3JlXG4gIHJldHVybiB7XG4gICAgLi4uY3VzdG9tUGFsZXR0ZSxcbiAgICAuLi51cGRhdGVcbiAgfTtcbn1cblxuLyoqXG4gKiByZW1vdmUgYSBjb2xvciBpbiBjdXN0b20gcGFsZXR0ZSBhdCBpbmRleFxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVtb3ZlQ3VzdG9tUGFsZXR0ZUNvbG9yKGN1c3RvbVBhbGV0dGU6IENvbG9yUmFuZ2UsIGluZGV4OiBudW1iZXIpOiBDb2xvclJhbmdlIHtcbiAgY29uc3Qge2NvbG9ycywgY29sb3JNYXAsIGNvbG9yTGVnZW5kc30gPSBjdXN0b21QYWxldHRlO1xuICBjb25zdCBvbGRWYWx1ZSA9IGNvbG9yc1tpbmRleF07XG4gIGNvbnN0IHVwZGF0ZTogUGFydGlhbDxDb2xvclJhbmdlPiA9IHt9O1xuICB1cGRhdGUuY29sb3JzID0gWy4uLmNvbG9yc107XG5cbiAgaWYgKHVwZGF0ZS5jb2xvcnMubGVuZ3RoID4gMSkge1xuICAgIHVwZGF0ZS5jb2xvcnMuc3BsaWNlKGluZGV4LCAxKTtcbiAgfVxuICAvLyB1cGRhdGUgY29sb3IgbWFwXG4gIGlmIChBcnJheS5pc0FycmF5KGNvbG9yTWFwKSkge1xuICAgIC8vIGZpbmQgY29sb3JNYXAgaW5kZXhcbiAgICBjb25zdCBjb2xvck1hcEluZGV4ID0gY29sb3JNYXAuZmluZEluZGV4KGNtID0+IGNtWzFdID09PSBvbGRWYWx1ZSk7XG4gICAgaWYgKGNvbG9yTWFwSW5kZXggPj0gMCkge1xuICAgICAgdXBkYXRlLmNvbG9yTWFwID0gWy4uLmNvbG9yTWFwXTtcbiAgICAgIHVwZGF0ZS5jb2xvck1hcC5zcGxpY2UoY29sb3JNYXBJbmRleCwgMSk7XG4gICAgfVxuICB9XG4gIC8vIHVwZGF0ZSBjb2xvciBsZWdlbmRcbiAgaWYgKGNvbG9yTGVnZW5kcz8uW29sZFZhbHVlXSkge1xuICAgIHVwZGF0ZS5jb2xvckxlZ2VuZHMgPSB7Li4uY29sb3JMZWdlbmRzfTtcbiAgICBkZWxldGUgdXBkYXRlLmNvbG9yTGVnZW5kc1tvbGRWYWx1ZV07XG4gIH1cblxuICByZXR1cm4ge1xuICAgIC4uLmN1c3RvbVBhbGV0dGUsXG4gICAgLi4udXBkYXRlXG4gIH07XG59XG5cbi8qKlxuICogVXBkYXRlIGEgY29sb3IgaW4gY3VzdG9tIHBhbGV0dGUgYXQgaW5kZXhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVwZGF0ZUN1c3RvbVBhbGV0dGVDb2xvcihcbiAgY3VzdG9tUGFsZXR0ZTogQ29sb3JSYW5nZSxcbiAgaW5kZXg6IG51bWJlcixcbiAgbmV3VmFsdWU6IEhleENvbG9yXG4pOiBDb2xvclJhbmdlIHtcbiAgY29uc3Qge2NvbG9yc30gPSBjdXN0b21QYWxldHRlO1xuICBjb25zdCBoZXggPSBuZXdWYWx1ZS50b1VwcGVyQ2FzZSgpO1xuICBjb25zdCBuZXdDb2xvcnMgPSBbLi4uY29sb3JzXTtcbiAgbmV3Q29sb3JzW2luZGV4XSA9IGhleDtcblxuICBjb25zdCB1cGRhdGUgPSByZXBsYWNlQ29sb3JzSW5Db2xvclJhbmdlKGN1c3RvbVBhbGV0dGUsIG5ld0NvbG9ycyk7XG5cbiAgLy8gQHRzLWlnbm9yZVxuICByZXR1cm4ge1xuICAgIC4uLmN1c3RvbVBhbGV0dGUsXG4gICAgLi4udXBkYXRlXG4gIH07XG59XG5cbi8qKlxuICogR2V0IGEgcmV2ZXJzZWQgY29sb3JSYW5nZVxuICovXG5leHBvcnQgZnVuY3Rpb24gcmV2ZXJzZUNvbG9yUmFuZ2UocmV2ZXJzZWQ6IGJvb2xlYW4sIGNvbG9yUmFuZ2U6IENvbG9yUmFuZ2UpOiBDb2xvclJhbmdlIHtcbiAgY29uc3QgbmV3Q29sb3JzID0gY29sb3JSYW5nZT8uY29sb3JzLnNsaWNlKCkucmV2ZXJzZSgpO1xuICBjb25zdCB1cGRhdGVkID0gcmVwbGFjZUNvbG9yc0luQ29sb3JSYW5nZShjb2xvclJhbmdlLCBuZXdDb2xvcnMpO1xuICB1cGRhdGVkLnJldmVyc2VkID0gcmV2ZXJzZWQ7XG5cbiAgcmV0dXJuIHVwZGF0ZWQ7XG59XG5cbi8qKlxuICogV2hldGhlciBwYWxldHRlIG1hdGNoZXMgY3VycmVudCBDb2xvckJsaW5kU2FmZSBjb25maWdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhbGV0dGVJc0NvbG9yQmxpbmRTYWZlKHBhbGV0dGU6IENvbG9yUGFsZXR0ZSwgY29sb3JCbGluZFNhZmU6IGJvb2xlYW4pIHtcbiAgcmV0dXJuICFjb2xvckJsaW5kU2FmZSB8fCAoY29sb3JCbGluZFNhZmUgJiYgcGFsZXR0ZS5jb2xvckJsaW5kU2FmZSk7XG59XG5cbi8qKlxuICogV2hldGhlciBwYWxldHRlIG1hdGNoZXMgY3VycmVudCBzdGVwcyBjb25maWdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzUXVhUGFsZXR0ZShwYWxldHRlOiBDb2xvclBhbGV0dGUpOiBwYWxldHRlIGlzIENhdGVnb3JpY2FsUGFsZXR0ZSB7XG4gIHJldHVybiBwYWxldHRlLnR5cGUgPT09IFBBTEVUVEVfVFlQRVMuUVVBO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgcGFsZXR0ZSBtYXRjaGVzIGN1cnJlbnQgc3RlcHMgY29uZmlnXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYWxldHRlSXNTdGVwcyhwYWxldHRlOiBDb2xvclBhbGV0dGUsIHN0ZXBzOiBudW1iZXIpOiBib29sZWFuIHtcbiAgcmV0dXJuICFpc1F1YVBhbGV0dGUocGFsZXR0ZSkgfHwgcGFsZXR0ZS5tYXhTdGVwID49IHN0ZXBzO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgcGFsZXR0ZSBtYXRjaGVzIGN1cnJlbnQgdHlwZSBjb25maWdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhbGV0dGVJc1R5cGUocGFsZXR0ZTogQ29sb3JQYWxldHRlLCB0eXBlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIHR5cGUgPT09ICdhbGwnIHx8IHR5cGUgPT09IHBhbGV0dGUudHlwZTtcbn1cbi8qKlxuICogRmluZCBiZXN0IG1hdGNoIHBhbGV0dGUgYmFzZWQgb24gY29uZmlnLCB1cGRhdGUgY29sb3IgcmFuZ2UgYnkgaXRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVwZGF0ZUNvbG9yUmFuZ2VCeU1hdGNoaW5nUGFsZXR0ZShcbiAgY3VycmVudENvbG9yUmFuZ2U6IENvbG9yUmFuZ2UsXG4gIGNvbmZpZzogQ29sb3JSYW5nZUNvbmZpZ1xuKTogQ29sb3JSYW5nZSB7XG4gIGNvbnN0IHtzdGVwcywgY29sb3JCbGluZFNhZmUsIHR5cGV9ID0gY29uZmlnO1xuXG4gIGNvbnN0IG1hdGNoaW5nUGFsZXR0ZSA9IEtFUExFUl9DT0xPUl9QQUxFVFRFUy5maWx0ZXIoXG4gICAgcGFsZXR0ZSA9PlxuICAgICAgLy8gcGFsZXR0ZSBtYXRjaCB0eXBlXG4gICAgICBwYWxldHRlSXNUeXBlKHBhbGV0dGUsIHR5cGUpICYmXG4gICAgICAvLyBwYWxldHRlIGhhcyBzYW1lIHN0ZXBcbiAgICAgIHBhbGV0dGVJc1N0ZXBzKHBhbGV0dGUsIHN0ZXBzKSAmJlxuICAgICAgLy8gcGFsZXR0ZSBpcyBjb2xvckJsaW5kU2FmZVxuICAgICAgcGFsZXR0ZUlzQ29sb3JCbGluZFNhZmUocGFsZXR0ZSwgY29sb3JCbGluZFNhZmUpXG4gICk7XG5cbiAgY29uc3QgYmVzdE1hdGNoID0gbWF0Y2hpbmdQYWxldHRlLmxlbmd0aFxuICAgID8gbWF0Y2hpbmdQYWxldHRlLmZpbmQocCA9PiBwLm5hbWUgPT09IGN1cnJlbnRDb2xvclJhbmdlLm5hbWUpIHx8IG1hdGNoaW5nUGFsZXR0ZVswXVxuICAgIDogbnVsbDtcblxuICBpZiAoYmVzdE1hdGNoKSB7XG4gICAgcmV0dXJuIHVwZGF0ZUNvbG9yUmFuZ2VCeVNlbGVjdGVkUGFsZXR0ZShjdXJyZW50Q29sb3JSYW5nZSwgYmVzdE1hdGNoLCBjb25maWcpO1xuICB9XG4gIC8vIHdlIGRvIG5vdGhpbmdcbiAgQ29uc29sZS53YXJuKFxuICAgIGB3ZSBjYW50IGZpbmQgYW55IHByZXNldCBwYWxldHRlIG1hdGNoZXMgcmVxdWlybWVudHM6IHN0ZXBzPSR7c3RlcHN9ICYmIGNvbG9yQmxpbmRTYWZlPSR7Y29sb3JCbGluZFNhZmV9YFxuICApO1xuXG4gIHJldHVybiBjdXJyZW50Q29sb3JSYW5nZTtcbn1cblxuLyoqXG4gKiBVcGRhdGUgY3VzdG9tIHBhbGV0dGUgd2hlbiByZXZlcnNlIHRoZSBjb2xvcnMgaW4gY3VzdG9tIHBhbGV0dGUsIHNpbmNlIGNoYW5naW5nICdzdGVwcycsXG4gKiAnY29sb3JCaW5kU2FmZScsICd0eXBlJyBzaG91bGQgZmFsbCBiYWNrIHRvIHByZWRlZmluZWQgcGFsZXR0ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVwZGF0ZUN1c3RvbUNvbG9yUmFuZ2VCeUNvbG9yVUkoXG4gIG9sZENvbG9yUmFuZ2U6IENvbG9yUmFuZ2UsXG4gIGNvbG9yQ29uZmlnOiBDb2xvclJhbmdlQ29uZmlnXG4pOiBDb2xvclJhbmdlIHtcbiAgY29uc3Qge3JldmVyc2VkfSA9IGNvbG9yQ29uZmlnO1xuICBjb25zdCBjb2xvcnMgPSBvbGRDb2xvclJhbmdlLmNvbG9ycztcbiAgLy8gZm9yIGN1c3RvbSBwYWxldHRlLCBvbmUgY2FuIG9ubHkgJ3JldmVyc2UnIHRoZSBjb2xvcnMgaW4gY3VzdG9tIHBhbGV0dGUuXG4gIGNvbG9ycy5yZXZlcnNlKCk7XG5cbiAgY29uc3QgY29sb3JSYW5nZSA9IHtcbiAgICBuYW1lOiBvbGRDb2xvclJhbmdlLm5hbWUsXG4gICAgdHlwZTogb2xkQ29sb3JSYW5nZS50eXBlLFxuICAgIGNhdGVnb3J5OiBvbGRDb2xvclJhbmdlLmNhdGVnb3J5LFxuICAgIGNvbG9ycyxcbiAgICAuLi4ocmV2ZXJzZWQgPyB7cmV2ZXJzZWR9IDoge30pLFxuICAgIC4uLihvbGRDb2xvclJhbmdlLmNvbG9yTWFwID8ge2NvbG9yTWFwOiBvbGRDb2xvclJhbmdlLmNvbG9yTWFwfSA6IHt9KSxcbiAgICAuLi4ob2xkQ29sb3JSYW5nZS5jb2xvckxlZ2VuZHMgPyB7Y29sb3JMZWdlbmRzOiBvbGRDb2xvclJhbmdlLmNvbG9yTGVnZW5kc30gOiB7fSlcbiAgfTtcblxuICByZXR1cm4gcmVwbGFjZUNvbG9yc0luQ29sb3JSYW5nZShjb2xvclJhbmdlLCBjb2xvclJhbmdlLmNvbG9ycyk7XG59XG5cbi8qKlxuICogVXBkYXRlIGNvbG9yIHJhbmdlIGFmdGVyIHNlbGVjdGluZyBhIHBhbGV0dGUgZnJvbSBjb2xvciByYW5nZSBzZWxlY3RvZXJcbiAqIENvcHkgb3ZlciBjb2xvck1hcCBhbmQgY29sb3JMZWdlbmRzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1cGRhdGVDb2xvclJhbmdlQnlTZWxlY3RlZFBhbGV0dGUob2xkQ29sb3JSYW5nZSwgY29sb3JQYWxldHRlLCBjb2xvckNvbmZpZykge1xuICBjb25zdCB7Y29sb3JzOiBuZXdDb2xvcnMsIC4uLm5ld0NvbG9yUmFuZ2V9ID0gY29sb3JQYWxldHRlVG9Db2xvclJhbmdlKGNvbG9yUGFsZXR0ZSwgY29sb3JDb25maWcpO1xuXG4gIGNvbnN0IGNvbG9yUmFuZ2UgPSB7XG4gICAgY29sb3JzOiBvbGRDb2xvclJhbmdlLmNvbG9ycyxcbiAgICAuLi5uZXdDb2xvclJhbmdlLFxuICAgIC4uLihvbGRDb2xvclJhbmdlLmNvbG9yTWFwID8ge2NvbG9yTWFwOiBvbGRDb2xvclJhbmdlLmNvbG9yTWFwfSA6IHt9KSxcbiAgICAuLi4ob2xkQ29sb3JSYW5nZS5jb2xvckxlZ2VuZHMgPyB7Y29sb3JMZWdlbmRzOiBvbGRDb2xvclJhbmdlLmNvbG9yTGVnZW5kc30gOiB7fSlcbiAgfTtcblxuICByZXR1cm4gcmVwbGFjZUNvbG9yc0luQ29sb3JSYW5nZShjb2xvclJhbmdlLCBuZXdDb2xvcnMpO1xufVxuXG5jb25zdCBVYmVyTmFtZVJlZ2V4ID0gbmV3IFJlZ0V4cCgvXihbQS1aYS16IF0pKy9nKTtcbmNvbnN0IENvbG9yQnJld2VyUmVnZXggPSBuZXcgUmVnRXhwKC9eQ29sb3JCcmV3ZXIgKFtBLVphLXoxLTldKSsvZyk7XG5cbi8qKlxuICogY29udmVydCBzYXZlZCBjb2xvclJhbmdlIHRvIGNvbG9yUGFsZXR0ZSBvYmpldnQgdHlwZS9uYW1lL2NhdGVnb3J5L2lzQ29sb3JCbGluZFxuICovXG5leHBvcnQgZnVuY3Rpb24gY29sb3JSYW5nZUJhY2t3YXJkQ29tcGF0aWJpbGl0eShjb2xvclJhbmdlOiBDb2xvclJhbmdlKTogQ29sb3JSYW5nZSB7XG4gIGlmICghY29sb3JSYW5nZSB8fCBjb2xvclJhbmdlLnR5cGUgPT09ICdjdXN0b20nIHx8IGNvbG9yUmFuZ2UuY29sb3JNYXApIHtcbiAgICAvLyBkb24ndCBkbyBhbnl0aGluZyB0byBjdXN0b20gY29sb3IgcGFsZXR0ZSwgb3IgcGFsZXR0ZSB3aXRoIGN1c3RvbSBicmVha3NcbiAgICByZXR1cm4gY29sb3JSYW5nZTtcbiAgfVxuICBsZXQgdHJpbU5hbWU7XG4gIGlmIChjb2xvclJhbmdlLmNhdGVnb3J5ID09PSAnVWJlcicpIHtcbiAgICBjb25zdCBtYXRjaE5hbWUgPSAoY29sb3JSYW5nZS5uYW1lID8/ICcnKS5tYXRjaChVYmVyTmFtZVJlZ2V4KTtcbiAgICB0cmltTmFtZSA9IG1hdGNoTmFtZSA/IG1hdGNoTmFtZVswXS50cmltKCkgOiBudWxsO1xuICAgIC8vIG1hdGNoIFViZXIgVml6IFF1YWxpdGF0aXZlIDEuNCAtPiBVYmVyIFZpeiBRdWFsaXRhdGl2ZVxuICB9IGVsc2UgaWYgKGNvbG9yUmFuZ2UuY2F0ZWdvcnkgPT09ICdDb2xvckJyZXdlcicpIHtcbiAgICBjb25zdCBtYXRjaE5hbWUgPSAoY29sb3JSYW5nZS5uYW1lID8/ICcnKS5tYXRjaChDb2xvckJyZXdlclJlZ2V4KTtcbiAgICB0cmltTmFtZSA9IG1hdGNoTmFtZSA/IG1hdGNoTmFtZVswXS5yZXBsYWNlKCdDb2xvckJyZXdlciAnLCAnJykudHJpbSgpIDogbnVsbDtcbiAgfVxuXG4gIGlmICh0cmltTmFtZSkge1xuICAgIGNvbnN0IG1hdGNoaW5nUGFsZXR0ZSA9IEtFUExFUl9DT0xPUl9QQUxFVFRFUy5maW5kKHAgPT4gcC5uYW1lID09PSB0cmltTmFtZSk7XG4gICAgaWYgKG1hdGNoaW5nUGFsZXR0ZSkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgLi4uY29sb3JSYW5nZSxcbiAgICAgICAgbmFtZTogdHJpbU5hbWUsXG4gICAgICAgIHR5cGU6IG1hdGNoaW5nUGFsZXR0ZT8udHlwZSxcbiAgICAgICAgY2F0ZWdvcnk6IG1hdGNoaW5nUGFsZXR0ZS5jYXRlZ29yeVxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gY29sb3JSYW5nZTtcbn1cblxuLyoqXG4gKiBJbml0aWFsaXplIGN1c3RvbSBwYWxldHRlIGZyb20gY3VycmVudCBzdGFuZGFyZCBjb2xvciByYW5nZSBvYmplY3RcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGluaXRpYWxpemVDdXN0b21QYWxldHRlKGNvbG9yUmFuZ2U6IENvbG9yUmFuZ2UsIGNvbG9yTWFwPzogQ29sb3JNYXApOiBDb2xvclJhbmdlIHtcbiAgLy8gVE9ETzogY2hlY2sgb24gYGlzUmV2ZXJzZWRgIGtleSwgd2hldGhlciB3ZSBjYW4gcmVtb3ZlIGl0IGhlcmVcbiAgY29uc3QgY3VzdG9tUGFsZXR0ZSA9IHtcbiAgICAuLi5jb2xvclJhbmdlLFxuICAgIG5hbWU6IERFRkFVTFRfQ1VTVE9NX1BBTEVUVEUubmFtZSxcbiAgICB0eXBlOiBERUZBVUxUX0NVU1RPTV9QQUxFVFRFLnR5cGUsXG4gICAgY2F0ZWdvcnk6IERFRkFVTFRfQ1VTVE9NX1BBTEVUVEUuY2F0ZWdvcnksXG4gICAgLi4uKGNvbG9yTWFwID8ge2NvbG9yTWFwfSA6IHt9KVxuICB9O1xuXG4gIC8vIG9ubHkgY3VzdG9tUGFsZXR0ZS5jb2xvcnMgYXJlIG5lZWRlZCBmb3IgY3VzdG9tIHBhbGV0dGUgZWRpdG9yIHdpdGggY3VzdG9tIG9yZGluYWwgc2NhbGVcbiAgaWYgKCFjb2xvck1hcCAmJiBjb2xvclJhbmdlLnR5cGUgPT09IFNDQUxFX1RZUEVTLmN1c3RvbU9yZGluYWwpIHtcbiAgICBkZWxldGUgY3VzdG9tUGFsZXR0ZS5jb2xv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