kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
461 lines (430 loc) • 56.6 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 _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, _utils.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,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfY29uc3RhbnRzIiwicmVxdWlyZSIsIl9kM0NvbG9yIiwiX2QzSW50ZXJwb2xhdGUiLCJfdXRpbHMiLCJfY29uc29sZSIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJfZXhjbHVkZWQiLCJvd25LZXlzIiwiZSIsInIiLCJ0IiwiT2JqZWN0Iiwia2V5cyIsImdldE93blByb3BlcnR5U3ltYm9scyIsIm8iLCJmaWx0ZXIiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJlbnVtZXJhYmxlIiwicHVzaCIsImFwcGx5IiwiX29iamVjdFNwcmVhZCIsImFyZ3VtZW50cyIsImxlbmd0aCIsImZvckVhY2giLCJfZGVmaW5lUHJvcGVydHkyIiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9ycyIsImRlZmluZVByb3BlcnRpZXMiLCJkZWZpbmVQcm9wZXJ0eSIsImhleFRvUmdiIiwiaGV4IiwicmVzdWx0IiwiaXNIZXhDb2xvciIsInBhcnNlSW50IiwiZyIsImIiLCJleGVjIiwiUGFkTnVtIiwiYyIsInRvU3RyaW5nIiwiY29uY2F0IiwicmdiVG9IZXgiLCJfcmVmIiwiX3JlZjIiLCJfc2xpY2VkVG9BcnJheTIiLCJtYXAiLCJuIiwiam9pbiIsInRvVXBwZXJDYXNlIiwiaGFzQ29sb3JNYXAiLCJjb2xvclJhbmdlIiwiQXJyYXkiLCJpc0FycmF5IiwiY29sb3JNYXAiLCJCb29sZWFuIiwiY3JlYXRlTGluZWFyR3JhZGllbnQiLCJkaXJlY3Rpb24iLCJjb2xvcnMiLCJzdGVwIiwicGFyc2VGbG9hdCIsInRvRml4ZWQiLCJiYW5kcyIsInJnYiIsImluZGV4IiwiY29sb3JNYXliZVRvUkdCIiwiY29sb3IiLCJpc1JnYkNvbG9yIiwicmdiT2JqIiwiZDNSZ2IiLCJOdW1iZXIiLCJpc0Zpbml0ZSIsImV2ZXJ5Iiwibm9ybWFsaXplQ29sb3IiLCJjb21wb25lbnQiLCJjb2xvck1heWJlVG9IZXgiLCJyZ2JDb2xvciIsImludGVycG9sYXRlSGV4IiwiaGV4MSIsImhleDIiLCJpbnRlcnBvbGF0ZSIsImFkZE5ld0NhdGVnb3JpY2FsU3RlcEF0SW5kZXgiLCJuZXdDb2xvciIsIm5ld0NvbG9yTWFwIiwiX3JlZjMiLCJfcmVmNCIsInZhbCIsIl90b0NvbnN1bWFibGVBcnJheTIiLCJhcnJheUluc2VydCIsImFkZE5ld1F1YW50YXRpdmVDb2xvckJyZWFrQXRJbmRleCIsIm5ld0NvbG9ycyIsImkiLCJicmVha3MiLCJjbSIsInNsaWNlIiwibmV3VmFsdWUiLCJuZXdCcmVha3MiLCJ1bmRlZmluZWQiLCJhZGRDdXN0b21QYWxldHRlQ29sb3IiLCJjdXN0b21QYWxldHRlIiwidXBkYXRlIiwidHlwZSIsInJlcGxhY2VDb2xvcnNJbkNvbG9yUmFuZ2UiLCJvbGRDb2xvcnMiLCJ1cGRhdGVkIiwiY29sb3JMZWdlbmRzIiwicmVkdWNlIiwiYWNjdSIsImtleSIsImNvbG9ySWR4IiwiZmluZEluZGV4Iiwic29ydEN1c3RvbVBhbGV0dGVDb2xvciIsIm9sZEluZGV4IiwibmV3SW5kZXgiLCJhcnJheU1vdmUiLCJyZW1vdmVDdXN0b21QYWxldHRlQ29sb3IiLCJvbGRWYWx1ZSIsInNwbGljZSIsImNvbG9yTWFwSW5kZXgiLCJ1cGRhdGVDdXN0b21QYWxldHRlQ29sb3IiLCJyZXZlcnNlQ29sb3JSYW5nZSIsInJldmVyc2VkIiwicmV2ZXJzZSIsInBhbGV0dGVJc0NvbG9yQmxpbmRTYWZlIiwicGFsZXR0ZSIsImNvbG9yQmxpbmRTYWZlIiwiaXNRdWFQYWxldHRlIiwiUEFMRVRURV9UWVBFUyIsIlFVQSIsInBhbGV0dGVJc1N0ZXBzIiwic3RlcHMiLCJtYXhTdGVwIiwicGFsZXR0ZUlzVHlwZSIsInVwZGF0ZUNvbG9yUmFuZ2VCeU1hdGNoaW5nUGFsZXR0ZSIsImN1cnJlbnRDb2xvclJhbmdlIiwiY29uZmlnIiwibWF0Y2hpbmdQYWxldHRlIiwiS0VQTEVSX0NPTE9SX1BBTEVUVEVTIiwiYmVzdE1hdGNoIiwiZmluZCIsInAiLCJuYW1lIiwidXBkYXRlQ29sb3JSYW5nZUJ5U2VsZWN0ZWRQYWxldHRlIiwiQ29uc29sZSIsIndhcm4iLCJ1cGRhdGVDdXN0b21Db2xvclJhbmdlQnlDb2xvclVJIiwib2xkQ29sb3JSYW5nZSIsImNvbG9yQ29uZmlnIiwiY2F0ZWdvcnkiLCJjb2xvclBhbGV0dGUiLCJfY29sb3JQYWxldHRlVG9Db2xvclIiLCJjb2xvclBhbGV0dGVUb0NvbG9yUmFuZ2UiLCJuZXdDb2xvclJhbmdlIiwiX29iamVjdFdpdGhvdXRQcm9wZXJ0aWVzMiIsIlViZXJOYW1lUmVnZXgiLCJSZWdFeHAiLCJDb2xvckJyZXdlclJlZ2V4IiwiY29sb3JSYW5nZUJhY2t3YXJkQ29tcGF0aWJpbGl0eSIsInRyaW1OYW1lIiwiX2NvbG9yUmFuZ2UkbmFtZSIsIm1hdGNoTmFtZSIsIm1hdGNoIiwidHJpbSIsIl9jb2xvclJhbmdlJG5hbWUyIiwicmVwbGFjZSIsImluaXRpYWxpemVDdXN0b21QYWxldHRlIiwiREVGQVVMVF9DVVNUT01fUEFMRVRURSIsIlNDQUxFX1RZUEVTIiwiY3VzdG9tT3JkaW5hbCJdLCJzb3VyY2VzIjpbIi4uL3NyYy9jb2xvci11dGlscy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogTUlUXG4vLyBDb3B5cmlnaHQgY29udHJpYnV0b3JzIHRvIHRoZSBrZXBsZXIuZ2wgcHJvamVjdFxuXG5pbXBvcnQge1xuICBDYXRlZ29yaWNhbFBhbGV0dGUsXG4gIENvbG9yUGFsZXR0ZSxcbiAgREVGQVVMVF9DVVNUT01fUEFMRVRURSxcbiAgY29sb3JQYWxldHRlVG9Db2xvclJhbmdlXG59IGZyb20gJ0BrZXBsZXIuZ2wvY29uc3RhbnRzJztcbmltcG9ydCB7XG4gIENvbG9yTWFwLFxuICBDb2xvclJhbmdlLFxuICBDb2xvclJhbmdlQ29uZmlnLFxuICBIZXhDb2xvcixcbiAgUkdCQUNvbG9yLFxuICBSR0JDb2xvclxufSBmcm9tICdAa2VwbGVyLmdsL3R5cGVzJztcbmltcG9ydCB7cmdiIGFzIGQzUmdifSBmcm9tICdkMy1jb2xvcic7XG5pbXBvcnQge2ludGVycG9sYXRlfSBmcm9tICdkMy1pbnRlcnBvbGF0ZSc7XG5pbXBvcnQge2FycmF5SW5zZXJ0LCBhcnJheU1vdmV9IGZyb20gJy4vdXRpbHMnO1xuaW1wb3J0IENvbnNvbGUgZnJvbSAnZ2xvYmFsL2NvbnNvbGUnO1xuaW1wb3J0IHtLRVBMRVJfQ09MT1JfUEFMRVRURVMsIFBBTEVUVEVfVFlQRVMsIFNDQUxFX1RZUEVTfSBmcm9tICdAa2VwbGVyLmdsL2NvbnN0YW50cyc7XG5cbi8qKlxuICogZ2V0IHIgZyBiIGZyb20gaGV4IGNvZGVcbiAqXG4gKiBAcGFyYW0gaGV4XG4gKiBAcmV0dXJucyBhcnJheSBvZiByIGcgYnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGhleFRvUmdiKGhleDogc3RyaW5nKTogUkdCQ29sb3Ige1xuICBjb25zdCByZXN1bHQgPSBpc0hleENvbG9yKGhleCk7XG5cbiAgaWYgKCFyZXN1bHQpIHtcbiAgICByZXR1cm4gWzAsIDAsIDBdO1xuICB9XG5cbiAgY29uc3QgciA9IHBhcnNlSW50KHJlc3VsdFsxXSwgMTYpO1xuICBjb25zdCBnID0gcGFyc2VJbnQocmVzdWx0WzJdLCAxNik7XG4gIGNvbnN0IGIgPSBwYXJzZUludChyZXN1bHRbM10sIDE2KTtcblxuICByZXR1cm4gW3IsIGcsIGJdO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNIZXhDb2xvcihoZXg6IHN0cmluZyk6IFJlZ0V4cEV4ZWNBcnJheSB8IG51bGwge1xuICBjb25zdCByZXN1bHQgPSAvXiM/KFthLWZcXGRdezJ9KShbYS1mXFxkXXsyfSkoW2EtZlxcZF17Mn0pJC9pLmV4ZWMoaGV4KTtcblxuICByZXR1cm4gcmVzdWx0O1xufVxuXG5mdW5jdGlvbiBQYWROdW0oYykge1xuICBjb25zdCBoZXggPSBjLnRvU3RyaW5nKDE2KTtcbiAgcmV0dXJuIGhleC5sZW5ndGggPT09IDEgPyBgMCR7aGV4fWAgOiBoZXg7XG59XG5cbi8qKlxuICogZ2V0IGhleCBmcm9tIHIgZyBiXG4gKlxuICogQHBhcmFtIHJnYlxuICogQHJldHVybnMgaGV4IHN0cmluZ1xuICovXG5leHBvcnQgZnVuY3Rpb24gcmdiVG9IZXgoW3IsIGcsIGJdOiBSR0JDb2xvciB8IFJHQkFDb2xvcik6IEhleENvbG9yIHtcbiAgcmV0dXJuIGAjJHtbciwgZywgYl0ubWFwKG4gPT4gUGFkTnVtKG4pKS5qb2luKCcnKX1gLnRvVXBwZXJDYXNlKCk7XG59XG5cbi8qKlxuICogV2hldGhlciBjb2xvciByYW5nZSBoYXMgY3VzdG9tIGNvbG9yIG1hcFxuICovXG5leHBvcnQgZnVuY3Rpb24gaGFzQ29sb3JNYXAoY29sb3JSYW5nZTogQ29sb3JSYW5nZSk6IGJvb2xlYW4ge1xuICByZXR1cm4gQXJyYXkuaXNBcnJheShjb2xvclJhbmdlLmNvbG9yTWFwKSAmJiBCb29sZWFuKGNvbG9yUmFuZ2UuY29sb3JNYXAubGVuZ3RoKTtcbn1cblxuLyoqXG4gKiBnaXZlbiBhIGxpc3Qgb2YgcmdiIGFycmF5cyBpdCB3aWxsIGdlbmVyYXRlIGEgbGluZWFyIGdyYWRpZW50IGNzcyBydWxlXG4gKiBAcGFyYW0gZGlyZWN0aW9uXG4gKiBAcGFyYW0gY29sb3JzXG4gKiBAcmV0dXJuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVMaW5lYXJHcmFkaWVudChkaXJlY3Rpb246IHN0cmluZywgY29sb3JzOiBSR0JDb2xvcltdKTogc3RyaW5nIHtcbiAgY29uc3Qgc3RlcCA9IHBhcnNlRmxvYXQoKDEwMC4wIC8gY29sb3JzLmxlbmd0aCkudG9GaXhlZCgyKSk7XG4gIGNvbnN0IGJhbmRzID0gY29sb3JzLm1hcCgocmdiLCBpbmRleCkgPT4ge1xuICAgIHJldHVybiBgcmdiYSgke3JnYi5qb2luKCcsJyl9LCAxKSAke3N0ZXAgKiBpbmRleH0lLCByZ2JhKCR7cmdiLmpvaW4oJywnKX0sIDEpICR7XG4gICAgICBzdGVwICogKGluZGV4ICsgMSlcbiAgICB9JWA7XG4gIH0pO1xuXG4gIHJldHVybiBgbGluZWFyLWdyYWRpZW50KHRvICR7ZGlyZWN0aW9ufSwgJHtiYW5kcy5qb2luKCcsJyl9KWA7XG59XG5cbi8qKlxuICogQ29udmVydCBjb2xvciB0byBSR0JcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbG9yTWF5YmVUb1JHQihjb2xvcjogdW5rbm93bik6IFJHQkNvbG9yIHwgbnVsbCB7XG4gIGlmIChpc1JnYkNvbG9yKGNvbG9yKSkge1xuICAgIHJldHVybiBjb2xvciBhcyBSR0JDb2xvcjtcbiAgfVxuXG4gIGlmICh0eXBlb2YgY29sb3IgPT09ICdzdHJpbmcnKSB7XG4gICAgY29uc3QgcmdiT2JqID0gZDNSZ2IoY29sb3IpO1xuICAgIGlmIChOdW1iZXIuaXNGaW5pdGUocmdiT2JqPy5yKSAmJiBOdW1iZXIuaXNGaW5pdGUocmdiT2JqPy5nKSAmJiBOdW1iZXIuaXNGaW5pdGUocmdiT2JqPy5iKSkge1xuICAgICAgcmV0dXJuIFtyZ2JPYmouciwgcmdiT2JqLmcsIHJnYk9iai5iXTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gbnVsbDtcbn1cblxuLyoqXG4gKiBXaGV0aGVyIGNvbG9yIGlzIHJnYlxuICogQHJldHVybnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzUmdiQ29sb3IoY29sb3I6IHVua25vd24pOiBib29sZWFuIHtcbiAgcmV0dXJuIEJvb2xlYW4oXG4gICAgY29sb3IgJiZcbiAgICAgIEFycmF5LmlzQXJyYXkoY29sb3IpICYmXG4gICAgICBjb2xvci5sZW5ndGggPT09IDMgJiZcbiAgICAgIGNvbG9yLmV2ZXJ5KG4gPT4gTnVtYmVyLmlzRmluaXRlKG4pICYmIG4gPD0gMjU1ICYmIG4gPj0gMClcbiAgKTtcbn1cblxuLyoqXG4gKiBUYWtlIGNvbG9yIHZhbHVlcyBpbiAwLTI1NSByYW5nZSBhbmQgbWFwIHRvIFswLCAxXVxuICovXG5leHBvcnQgZnVuY3Rpb24gbm9ybWFsaXplQ29sb3IoY29sb3I6IG51bWJlcltdKTogbnVtYmVyW10ge1xuICByZXR1cm4gY29sb3IubWFwKGNvbXBvbmVudCA9PiBjb21wb25lbnQgLyAyNTUuMCk7XG59XG5cbi8qKlxuICogQ29udmVydCBjb2xvciB0byBIZXhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbG9yTWF5YmVUb0hleChjb2xvcjogdW5rbm93bik6IEhleENvbG9yIHtcbiAgY29uc3QgcmdiQ29sb3IgPSBjb2xvck1heWJlVG9SR0IoY29sb3IpO1xuICBpZiAocmdiQ29sb3IpIHJldHVybiByZ2JUb0hleChyZ2JDb2xvcik7XG4gIHJldHVybiAnIzAwMDAwMCc7XG59XG5cbi8qKlxuICogQ29udmVydCBjb2xvciB0byBIZXhcbiAqL1xuXG5leHBvcnQgZnVuY3Rpb24gaW50ZXJwb2xhdGVIZXgoaGV4MTogSGV4Q29sb3IsIGhleDI6IEhleENvbG9yKTogSGV4Q29sb3Ige1xuICByZXR1cm4gZDNSZ2IoaW50ZXJwb2xhdGUoaGV4MSwgaGV4MikoMC41KSkuaGV4KCkudG9VcHBlckNhc2UoKTtcbn1cblxuZnVuY3Rpb24gYWRkTmV3Q2F0ZWdvcmljYWxTdGVwQXRJbmRleChjb2xvck1hcCwgaW5kZXgsIG5ld0NvbG9yKSB7XG4gIGlmICghQXJyYXkuaXNBcnJheShjb2xvck1hcCkgfHwgIWNvbG9yTWFwLmxlbmd0aCkge1xuICAgIHJldHVybiBjb2xvck1hcDtcbiAgfVxuXG4gIGxldCBuZXdDb2xvck1hcCA9IGNvbG9yTWFwLm1hcCgoW3ZhbCwgY10pID0+IFtBcnJheS5pc0FycmF5KHZhbCkgPyBbLi4udmFsXSA6IHZhbCwgY10pO1xuICBuZXdDb2xvck1hcCA9IGFycmF5SW5zZXJ0KG5ld0NvbG9yTWFwLCBpbmRleCArIDEsIFtudWxsLCBuZXdDb2xvcl0pO1xuXG4gIHJldHVybiBuZXdDb2xvck1hcDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGFkZE5ld1F1YW50YXRpdmVDb2xvckJyZWFrQXRJbmRleChjb2xvck1hcCwgaW5kZXgsIG5ld0NvbG9ycykge1xuICBpZiAoIUFycmF5LmlzQXJyYXkoY29sb3JNYXApIHx8ICFjb2xvck1hcC5sZW5ndGgpIHtcbiAgICByZXR1cm4gY29sb3JNYXA7XG4gIH1cblxuICBpZiAoY29sb3JNYXAubGVuZ3RoIDwgMikge1xuICAgIC8vIGxlc3MgdGhlbiAyLCBhZGQgMSBhdCBlbmRcbiAgICAvLyBob3dldmVyIHNob3VsZG4ndCBhbGxvdyBkZWxldGUgd2hlbiB0aGVyZSBhcmUgMlxuICAgIHJldHVybiBuZXdDb2xvcnMubWFwKChjLCBpKSA9PiAoaSA9PT0gMCA/IGNvbG9yTWFwW2ldIDogW251bGwsIGNdKSk7XG4gIH1cblxuICAvLyBicmVha3Mgc2hvdWxkIGJlIDEgbGVzcyB0aGFuIGNvbG9yc1xuICBjb25zdCBicmVha3MgPSBjb2xvck1hcC5tYXAoY20gPT4gY21bMF0pLnNsaWNlKDAsIGNvbG9yTWFwLmxlbmd0aCAtIDEpO1xuXG4gIC8vIGluc2VydCBuZXcgYnJlYWtcbiAgY29uc3QgbmV3VmFsdWUgPVxuICAgIGluZGV4ID49IGJyZWFrcy5sZW5ndGggLSAxXG4gICAgICA/IGJyZWFrc1ticmVha3MubGVuZ3RoIC0gMV0gK1xuICAgICAgICAoYnJlYWtzLmxlbmd0aCA+IDEgPyBicmVha3NbYnJlYWtzLmxlbmd0aCAtIDFdIC0gYnJlYWtzW2JyZWFrcy5sZW5ndGggLSAyXSA6IDApXG4gICAgICA6IChicmVha3NbaW5kZXhdICsgYnJlYWtzW2luZGV4ICsgMV0pIC8gMjtcblxuICBjb25zdCBuZXdCcmVha3MgPSBhcnJheUluc2VydChicmVha3MsIGluZGV4ICsgMSwgbmV3VmFsdWUpO1xuXG4gIC8vIGFzaWduIGJyZWFrcyB0byBjb2xvclxuICByZXR1cm4gbmV3Q29sb3JzLm1hcCgoYywgaSkgPT5cbiAgICBpID09PSBuZXdDb2xvcnMubGVuZ3RoIC0gMSA/IFtudWxsLCBjXSA6IFtuZXdCcmVha3NbaV0gPT09IHVuZGVmaW5lZCA/IG51bGwgOiBuZXdCcmVha3NbaV0sIGNdXG4gICk7XG59XG5cbi8qKlxuICogQWRkIGEgbmV3IGNvbG9yIHRvIGN1c3RvbSBwYWxldHRlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhZGRDdXN0b21QYWxldHRlQ29sb3IoY3VzdG9tUGFsZXR0ZTogQ29sb3JSYW5nZSwgaW5kZXg6IG51bWJlcik6IENvbG9yUmFuZ2Uge1xuICBjb25zdCB7Y29sb3JzLCBjb2xvck1hcH0gPSBjdXN0b21QYWxldHRlO1xuICBjb25zdCB1cGRhdGU6IFBhcnRpYWw8Q29sb3JSYW5nZT4gPSB7fTtcblxuICBjb25zdCBuZXdDb2xvciA9XG4gICAgaW5kZXggPT09IGNvbG9ycy5sZW5ndGggLSAxID8gY29sb3JzW2luZGV4XSA6IGludGVycG9sYXRlSGV4KGNvbG9yc1tpbmRleF0sIGNvbG9yc1tpbmRleCArIDFdKTtcblxuICB1cGRhdGUuY29sb3JzID0gYXJyYXlJbnNlcnQoY29sb3JzLCBpbmRleCArIDEsIG5ld0NvbG9yKTtcblxuICAvLyBhZGQgY29sb3IgdG8gY29sb3JNYXBcbiAgaWYgKGNvbG9yTWFwKSB7XG4gICAgdXBkYXRlLmNvbG9yTWFwID1cbiAgICAgIGN1c3RvbVBhbGV0dGUudHlwZSA9PT0gJ2N1c3RvbU9yZGluYWwnXG4gICAgICAgID8gYWRkTmV3Q2F0ZWdvcmljYWxTdGVwQXRJbmRleChjb2xvck1hcCwgaW5kZXgsIG5ld0NvbG9yKVxuICAgICAgICA6IGFkZE5ld1F1YW50YXRpdmVDb2xvckJyZWFrQXRJbmRleChjb2xvck1hcCwgaW5kZXgsIHVwZGF0ZS5jb2xvcnMpO1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICAuLi5jdXN0b21QYWxldHRlLFxuICAgIC4uLnVwZGF0ZVxuICB9O1xufVxuXG5mdW5jdGlvbiByZXBsYWNlQ29sb3JzSW5Db2xvclJhbmdlKGNvbG9yUmFuZ2UsIG5ld0NvbG9ycykge1xuICBjb25zdCBvbGRDb2xvcnMgPSBjb2xvclJhbmdlLmNvbG9ycztcbiAgY29uc3QgdXBkYXRlZCA9IHtcbiAgICAuLi5jb2xvclJhbmdlLFxuICAgIGNvbG9yczogbmV3Q29sb3JzXG4gIH07XG5cbiAgLy8gdXBkYXRlIGNvbG9yIG1hcFxuICAvLyBrZWVwIHZhbHVlLCByZXBsYWNlIGNvbG9yXG4gIGlmIChBcnJheS5pc0FycmF5KHVwZGF0ZWQuY29sb3JNYXApKSB7XG4gICAgdXBkYXRlZC5jb2xvck1hcCA9IHVwZGF0ZWQuY29sb3JNYXAubWFwKChjbSwgaSkgPT4gW2NtWzBdLCBuZXdDb2xvcnNbaV1dKTtcbiAgfVxuICAvLyB1cGRhdGUgY29sb3JsZWdlbmRzXG4gIC8vIGtlZXAgdmFsdWUsIHJlcGxhY2UgY29sb3JcbiAgaWYgKHVwZGF0ZWQuY29sb3JMZWdlbmRzKSB7XG4gICAgdXBkYXRlZC5jb2xvckxlZ2VuZHMgPSBPYmplY3Qua2V5cyh1cGRhdGVkLmNvbG9yTGVnZW5kcykucmVkdWNlKChhY2N1LCBrZXkpID0+IHtcbiAgICAgIGNvbnN0IGNvbG9ySWR4ID0gb2xkQ29sb3JzLmZpbmRJbmRleChjID0+IGMgPT09IGtleSk7XG4gICAgICBjb25zdCBuZXdDb2xvciA9IG5ld0NvbG9yc1tjb2xvcklkeF07XG5cbiAgICAgIHJldHVybiBuZXdDb2xvclxuICAgICAgICA/IHtcbiAgICAgICAgICAgIC4uLmFjY3UsXG4gICAgICAgICAgICBbbmV3Q29sb3JdOiB1cGRhdGVkLmNvbG9yTGVnZW5kc1trZXldXG4gICAgICAgICAgfVxuICAgICAgICA6IGFjY3U7XG4gICAgfSwge30pO1xuICB9XG5cbiAgcmV0dXJuIHVwZGF0ZWQ7XG59XG5cbi8qKlxuICogU29ydCBjdXN0b20gcGFsZXR0ZVxuICovXG5leHBvcnQgZnVuY3Rpb24gc29ydEN1c3RvbVBhbGV0dGVDb2xvcihcbiAgY3VzdG9tUGFsZXR0ZTogQ29sb3JSYW5nZSxcbiAgb2xkSW5kZXg6IG51bWJlcixcbiAgbmV3SW5kZXg6IG51bWJlclxuKTogQ29sb3JSYW5nZSB7XG4gIGNvbnN0IHtjb2xvcnN9ID0gY3VzdG9tUGFsZXR0ZTtcblxuICBjb25zdCBuZXdDb2xvcnMgPSBhcnJheU1vdmUoY29sb3JzLCBvbGRJbmRleCwgbmV3SW5kZXgpO1xuICBjb25zdCB1cGRhdGUgPSByZXBsYWNlQ29sb3JzSW5Db2xvclJhbmdlKGN1c3RvbVBhbGV0dGUsIG5ld0NvbG9ycyk7XG5cbiAgLy8gQHRzLWlnbm9yZVxuICByZXR1cm4ge1xuICAgIC4uLmN1c3RvbVBhbGV0dGUsXG4gICAgLi4udXBkYXRlXG4gIH07XG59XG5cbi8qKlxuICogcmVtb3ZlIGEgY29sb3IgaW4gY3VzdG9tIHBhbGV0dGUgYXQgaW5kZXhcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlbW92ZUN1c3RvbVBhbGV0dGVDb2xvcihjdXN0b21QYWxldHRlOiBDb2xvclJhbmdlLCBpbmRleDogbnVtYmVyKTogQ29sb3JSYW5nZSB7XG4gIGNvbnN0IHtjb2xvcnMsIGNvbG9yTWFwLCBjb2xvckxlZ2VuZHN9ID0gY3VzdG9tUGFsZXR0ZTtcbiAgY29uc3Qgb2xkVmFsdWUgPSBjb2xvcnNbaW5kZXhdO1xuICBjb25zdCB1cGRhdGU6IFBhcnRpYWw8Q29sb3JSYW5nZT4gPSB7fTtcbiAgdXBkYXRlLmNvbG9ycyA9IFsuLi5jb2xvcnNdO1xuXG4gIGlmICh1cGRhdGUuY29sb3JzLmxlbmd0aCA+IDEpIHtcbiAgICB1cGRhdGUuY29sb3JzLnNwbGljZShpbmRleCwgMSk7XG4gIH1cbiAgLy8gdXBkYXRlIGNvbG9yIG1hcFxuICBpZiAoQXJyYXkuaXNBcnJheShjb2xvck1hcCkpIHtcbiAgICAvLyBmaW5kIGNvbG9yTWFwIGluZGV4XG4gICAgY29uc3QgY29sb3JNYXBJbmRleCA9IGNvbG9yTWFwLmZpbmRJbmRleChjbSA9PiBjbVsxXSA9PT0gb2xkVmFsdWUpO1xuICAgIGlmIChjb2xvck1hcEluZGV4ID49IDApIHtcbiAgICAgIHVwZGF0ZS5jb2xvck1hcCA9IFsuLi5jb2xvck1hcF07XG4gICAgICB1cGRhdGUuY29sb3JNYXAuc3BsaWNlKGNvbG9yTWFwSW5kZXgsIDEpO1xuICAgIH1cbiAgfVxuICAvLyB1cGRhdGUgY29sb3IgbGVnZW5kXG4gIGlmIChjb2xvckxlZ2VuZHM/LltvbGRWYWx1ZV0pIHtcbiAgICB1cGRhdGUuY29sb3JMZWdlbmRzID0gey4uLmNvbG9yTGVnZW5kc307XG4gICAgZGVsZXRlIHVwZGF0ZS5jb2xvckxlZ2VuZHNbb2xkVmFsdWVdO1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICAuLi5jdXN0b21QYWxldHRlLFxuICAgIC4uLnVwZGF0ZVxuICB9O1xufVxuXG4vKipcbiAqIFVwZGF0ZSBhIGNvbG9yIGluIGN1c3RvbSBwYWxldHRlIGF0IGluZGV4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1cGRhdGVDdXN0b21QYWxldHRlQ29sb3IoXG4gIGN1c3RvbVBhbGV0dGU6IENvbG9yUmFuZ2UsXG4gIGluZGV4OiBudW1iZXIsXG4gIG5ld1ZhbHVlOiBIZXhDb2xvclxuKTogQ29sb3JSYW5nZSB7XG4gIGNvbnN0IHtjb2xvcnN9ID0gY3VzdG9tUGFsZXR0ZTtcbiAgY29uc3QgaGV4ID0gbmV3VmFsdWUudG9VcHBlckNhc2UoKTtcbiAgY29uc3QgbmV3Q29sb3JzID0gWy4uLmNvbG9yc107XG4gIG5ld0NvbG9yc1tpbmRleF0gPSBoZXg7XG5cbiAgY29uc3QgdXBkYXRlID0gcmVwbGFjZUNvbG9yc0luQ29sb3JSYW5nZShjdXN0b21QYWxldHRlLCBuZXdDb2xvcnMpO1xuXG4gIC8vIEB0cy1pZ25vcmVcbiAgcmV0dXJuIHtcbiAgICAuLi5jdXN0b21QYWxldHRlLFxuICAgIC4uLnVwZGF0ZVxuICB9O1xufVxuXG4vKipcbiAqIEdldCBhIHJldmVyc2VkIGNvbG9yUmFuZ2VcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJldmVyc2VDb2xvclJhbmdlKHJldmVyc2VkOiBib29sZWFuLCBjb2xvclJhbmdlOiBDb2xvclJhbmdlKTogQ29sb3JSYW5nZSB7XG4gIGNvbnN0IG5ld0NvbG9ycyA9IGNvbG9yUmFuZ2U/LmNvbG9ycy5zbGljZSgpLnJldmVyc2UoKTtcbiAgY29uc3QgdXBkYXRlZCA9IHJlcGxhY2VDb2xvcnNJbkNvbG9yUmFuZ2UoY29sb3JSYW5nZSwgbmV3Q29sb3JzKTtcbiAgdXBkYXRlZC5yZXZlcnNlZCA9IHJldmVyc2VkO1xuXG4gIHJldHVybiB1cGRhdGVkO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgcGFsZXR0ZSBtYXRjaGVzIGN1cnJlbnQgQ29sb3JCbGluZFNhZmUgY29uZmlnXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYWxldHRlSXNDb2xvckJsaW5kU2FmZShwYWxldHRlOiBDb2xvclBhbGV0dGUsIGNvbG9yQmxpbmRTYWZlOiBib29sZWFuKSB7XG4gIHJldHVybiAhY29sb3JCbGluZFNhZmUgfHwgKGNvbG9yQmxpbmRTYWZlICYmIHBhbGV0dGUuY29sb3JCbGluZFNhZmUpO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgcGFsZXR0ZSBtYXRjaGVzIGN1cnJlbnQgc3RlcHMgY29uZmlnXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1F1YVBhbGV0dGUocGFsZXR0ZTogQ29sb3JQYWxldHRlKTogcGFsZXR0ZSBpcyBDYXRlZ29yaWNhbFBhbGV0dGUge1xuICByZXR1cm4gcGFsZXR0ZS50eXBlID09PSBQQUxFVFRFX1RZUEVTLlFVQTtcbn1cblxuLyoqXG4gKiBXaGV0aGVyIHBhbGV0dGUgbWF0Y2hlcyBjdXJyZW50IHN0ZXBzIGNvbmZpZ1xuICovXG5leHBvcnQgZnVuY3Rpb24gcGFsZXR0ZUlzU3RlcHMocGFsZXR0ZTogQ29sb3JQYWxldHRlLCBzdGVwczogbnVtYmVyKTogYm9vbGVhbiB7XG4gIHJldHVybiAhaXNRdWFQYWxldHRlKHBhbGV0dGUpIHx8IHBhbGV0dGUubWF4U3RlcCA+PSBzdGVwcztcbn1cblxuLyoqXG4gKiBXaGV0aGVyIHBhbGV0dGUgbWF0Y2hlcyBjdXJyZW50IHR5cGUgY29uZmlnXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYWxldHRlSXNUeXBlKHBhbGV0dGU6IENvbG9yUGFsZXR0ZSwgdHlwZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gIHJldHVybiB0eXBlID09PSAnYWxsJyB8fCB0eXBlID09PSBwYWxldHRlLnR5cGU7XG59XG4vKipcbiAqIEZpbmQgYmVzdCBtYXRjaCBwYWxldHRlIGJhc2VkIG9uIGNvbmZpZywgdXBkYXRlIGNvbG9yIHJhbmdlIGJ5IGl0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1cGRhdGVDb2xvclJhbmdlQnlNYXRjaGluZ1BhbGV0dGUoXG4gIGN1cnJlbnRDb2xvclJhbmdlOiBDb2xvclJhbmdlLFxuICBjb25maWc6IENvbG9yUmFuZ2VDb25maWdcbik6IENvbG9yUmFuZ2Uge1xuICBjb25zdCB7c3RlcHMsIGNvbG9yQmxpbmRTYWZlLCB0eXBlfSA9IGNvbmZpZztcblxuICBjb25zdCBtYXRjaGluZ1BhbGV0dGUgPSBLRVBMRVJfQ09MT1JfUEFMRVRURVMuZmlsdGVyKFxuICAgIHBhbGV0dGUgPT5cbiAgICAgIC8vIHBhbGV0dGUgbWF0Y2ggdHlwZVxuICAgICAgcGFsZXR0ZUlzVHlwZShwYWxldHRlLCB0eXBlKSAmJlxuICAgICAgLy8gcGFsZXR0ZSBoYXMgc2FtZSBzdGVwXG4gICAgICBwYWxldHRlSXNTdGVwcyhwYWxldHRlLCBzdGVwcykgJiZcbiAgICAgIC8vIHBhbGV0dGUgaXMgY29sb3JCbGluZFNhZmVcbiAgICAgIHBhbGV0dGVJc0NvbG9yQmxpbmRTYWZlKHBhbGV0dGUsIGNvbG9yQmxpbmRTYWZlKVxuICApO1xuXG4gIGNvbnN0IGJlc3RNYXRjaCA9IG1hdGNoaW5nUGFsZXR0ZS5sZW5ndGhcbiAgICA/IG1hdGNoaW5nUGFsZXR0ZS5maW5kKHAgPT4gcC5uYW1lID09PSBjdXJyZW50Q29sb3JSYW5nZS5uYW1lKSB8fCBtYXRjaGluZ1BhbGV0dGVbMF1cbiAgICA6IG51bGw7XG5cbiAgaWYgKGJlc3RNYXRjaCkge1xuICAgIHJldHVybiB1cGRhdGVDb2xvclJhbmdlQnlTZWxlY3RlZFBhbGV0dGUoY3VycmVudENvbG9yUmFuZ2UsIGJlc3RNYXRjaCwgY29uZmlnKTtcbiAgfVxuICAvLyB3ZSBkbyBub3RoaW5nXG4gIENvbnNvbGUud2FybihcbiAgICBgd2UgY2FudCBmaW5kIGFueSBwcmVzZXQgcGFsZXR0ZSBtYXRjaGVzIHJlcXVpcm1lbnRzOiBzdGVwcz0ke3N0ZXBzfSAmJiBjb2xvckJsaW5kU2FmZT0ke2NvbG9yQmxpbmRTYWZlfWBcbiAgKTtcblxuICByZXR1cm4gY3VycmVudENvbG9yUmFuZ2U7XG59XG5cbi8qKlxuICogVXBkYXRlIGN1c3RvbSBwYWxldHRlIHdoZW4gcmV2ZXJzZSB0aGUgY29sb3JzIGluIGN1c3RvbSBwYWxldHRlLCBzaW5jZSBjaGFuZ2luZyAnc3RlcHMnLFxuICogJ2NvbG9yQmluZFNhZmUnLCAndHlwZScgc2hvdWxkIGZhbGwgYmFjayB0byBwcmVkZWZpbmVkIHBhbGV0dGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1cGRhdGVDdXN0b21Db2xvclJhbmdlQnlDb2xvclVJKFxuICBvbGRDb2xvclJhbmdlOiBDb2xvclJhbmdlLFxuICBjb2xvckNvbmZpZzogQ29sb3JSYW5nZUNvbmZpZ1xuKTogQ29sb3JSYW5nZSB7XG4gIGNvbnN0IHtyZXZlcnNlZH0gPSBjb2xvckNvbmZpZztcbiAgY29uc3QgY29sb3JzID0gb2xkQ29sb3JSYW5nZS5jb2xvcnM7XG4gIC8vIGZvciBjdXN0b20gcGFsZXR0ZSwgb25lIGNhbiBvbmx5ICdyZXZlcnNlJyB0aGUgY29sb3JzIGluIGN1c3RvbSBwYWxldHRlLlxuICBjb2xvcnMucmV2ZXJzZSgpO1xuXG4gIGNvbnN0IGNvbG9yUmFuZ2UgPSB7XG4gICAgbmFtZTogb2xkQ29sb3JSYW5nZS5uYW1lLFxuICAgIHR5cGU6IG9sZENvbG9yUmFuZ2UudHlwZSxcbiAgICBjYXRlZ29yeTogb2xkQ29sb3JSYW5nZS5jYXRlZ29yeSxcbiAgICBjb2xvcnMsXG4gICAgLi4uKHJldmVyc2VkID8ge3JldmVyc2VkfSA6IHt9KSxcbiAgICAuLi4ob2xkQ29sb3JSYW5nZS5jb2xvck1hcCA/IHtjb2xvck1hcDogb2xkQ29sb3JSYW5nZS5jb2xvck1hcH0gOiB7fSksXG4gICAgLi4uKG9sZENvbG9yUmFuZ2UuY29sb3JMZWdlbmRzID8ge2NvbG9yTGVnZW5kczogb2xkQ29sb3JSYW5nZS5jb2xvckxlZ2VuZHN9IDoge30pXG4gIH07XG5cbiAgcmV0dXJuIHJlcGxhY2VDb2xvcnNJbkNvbG9yUmFuZ2UoY29sb3JSYW5nZSwgY29sb3JSYW5nZS5jb2xvcnMpO1xufVxuXG4vKipcbiAqIFVwZGF0ZSBjb2xvciByYW5nZSBhZnRlciBzZWxlY3RpbmcgYSBwYWxldHRlIGZyb20gY29sb3IgcmFuZ2Ugc2VsZWN0b2VyXG4gKiBDb3B5IG92ZXIgY29sb3JNYXAgYW5kIGNvbG9yTGVnZW5kc1xuICovXG5leHBvcnQgZnVuY3Rpb24gdXBkYXRlQ29sb3JSYW5nZUJ5U2VsZWN0ZWRQYWxldHRlKG9sZENvbG9yUmFuZ2UsIGNvbG9yUGFsZXR0ZSwgY29sb3JDb25maWcpIHtcbiAgY29uc3Qge2NvbG9yczogbmV3Q29sb3JzLCAuLi5uZXdDb2xvclJhbmdlfSA9IGNvbG9yUGFsZXR0ZVRvQ29sb3JSYW5nZShjb2xvclBhbGV0dGUsIGNvbG9yQ29uZmlnKTtcblxuICBjb25zdCBjb2xvclJhbmdlID0ge1xuICAgIGNvbG9yczogb2xkQ29sb3JSYW5nZS5jb2xvcnMsXG4gICAgLi4ubmV3Q29sb3JSYW5nZSxcbiAgICAuLi4ob2xkQ29sb3JSYW5nZS5jb2xvck1hcCA/IHtjb2xvck1hcDogb2xkQ29sb3JSYW5nZS5jb2xvck1hcH0gOiB7fSksXG4gICAgLi4uKG9sZENvbG9yUmFuZ2UuY29sb3JMZWdlbmRzID8ge2NvbG9yTGVnZW5kczogb2xkQ29sb3JSYW5nZS5jb2xvckxlZ2VuZHN9IDoge30pXG4gIH07XG5cbiAgcmV0dXJuIHJlcGxhY2VDb2xvcnNJbkNvbG9yUmFuZ2UoY29sb3JSYW5nZSwgbmV3Q29sb3JzKTtcbn1cblxuY29uc3QgVWJlck5hbWVSZWdleCA9IG5ldyBSZWdFeHAoL14oW0EtWmEteiBdKSsvZyk7XG5jb25zdCBDb2xvckJyZXdlclJlZ2V4ID0gbmV3IFJlZ0V4cCgvXkNvbG9yQnJld2VyIChbQS1aYS16MS05XSkrL2cpO1xuXG4vKipcbiAqIGNvbnZlcnQgc2F2ZWQgY29sb3JSYW5nZSB0byBjb2xvclBhbGV0dGUgb2JqZXZ0IHR5cGUvbmFtZS9jYXRlZ29yeS9pc0NvbG9yQmxpbmRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbG9yUmFuZ2VCYWNrd2FyZENvbXBhdGliaWxpdHkoY29sb3JSYW5nZTogQ29sb3JSYW5nZSk6IENvbG9yUmFuZ2Uge1xuICBpZiAoIWNvbG9yUmFuZ2UgfHwgY29sb3JSYW5nZS50eXBlID09PSAnY3VzdG9tJyB8fCBjb2xvclJhbmdlLmNvbG9yTWFwKSB7XG4gICAgLy8gZG9uJ3QgZG8gYW55dGhpbmcgdG8gY3VzdG9tIGNvbG9yIHBhbGV0dGUsIG9yIHBhbGV0dGUgd2l0aCBjdXN0b20gYnJlYWtzXG4gICAgcmV0dXJuIGNvbG9yUmFuZ2U7XG4gIH1cbiAgbGV0IHRyaW1OYW1lO1xuICBpZiAoY29sb3JSYW5nZS5jYXRlZ29yeSA9PT0gJ1ViZXInKSB7XG4gICAgY29uc3QgbWF0Y2hOYW1lID0gKGNvbG9yUmFuZ2UubmFtZSA/PyAnJykubWF0Y2goVWJlck5hbWVSZWdleCk7XG4gICAgdHJpbU5hbWUgPSBtYXRjaE5hbWUgPyBtYXRjaE5hbWVbMF0udHJpbSgpIDogbnVsbDtcbiAgICAvLyBtYXRjaCBVYmVyIFZpeiBRdWFsaXRhdGl2ZSAxLjQgLT4gVWJlciBWaXogUXVhbGl0YXRpdmVcbiAgfSBlbHNlIGlmIChjb2xvclJhbmdlLmNhdGVnb3J5ID09PSAnQ29sb3JCcmV3ZXInKSB7XG4gICAgY29uc3QgbWF0Y2hOYW1lID0gKGNvbG9yUmFuZ2UubmFtZSA/PyAnJykubWF0Y2goQ29sb3JCcmV3ZXJSZWdleCk7XG4gICAgdHJpbU5hbWUgPSBtYXRjaE5hbWUgPyBtYXRjaE5hbWVbMF0ucmVwbGFjZSgnQ29sb3JCcmV3ZXIgJywgJycpLnRyaW0oKSA6IG51bGw7XG4gIH1cblxuICBpZiAodHJpbU5hbWUpIHtcbiAgICBjb25zdCBtYXRjaGluZ1BhbGV0dGUgPSBLRVBMRVJfQ09MT1JfUEFMRVRURVMuZmluZChwID0+IHAubmFtZSA9PT0gdHJpbU5hbWUpO1xuICAgIGlmIChtYXRjaGluZ1BhbGV0dGUpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIC4uLmNvbG9yUmFuZ2UsXG4gICAgICAgIG5hbWU6IHRyaW1OYW1lLFxuICAgICAgICB0eXBlOiBtYXRjaGluZ1BhbGV0dGU/LnR5cGUsXG4gICAgICAgIGNhdGVnb3J5OiBtYXRjaGluZ1BhbGV0dGUuY2F0ZWdvcnlcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGNvbG9yUmFuZ2U7XG59XG5cbi8qKlxuICogSW5pdGlhbGl6ZSBjdXN0b20gcGFsZXR0ZSBmcm9tIGN1cnJlbnQgc3RhbmRhcmQgY29sb3IgcmFuZ2Ugb2JqZWN0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpbml0aWFsaXplQ3VzdG9tUGFsZXR0ZShjb2xvclJhbmdlOiBDb2xvclJhbmdlLCBjb2xvck1hcD86IENvbG9yTWFwKTogQ29sb3JSYW5nZSB7XG4gIC8vIFRPRE86IGNoZWNrIG9uIGBpc1JldmVyc2VkYCBrZXksIHdoZXRoZXIgd2UgY2FuIHJlbW92ZSBpdCBoZXJlXG4gIGNvbnN0IGN1c3RvbVBhbGV0dGUgPSB7XG4gICAgLi4uY29sb3JSYW5nZSxcbiAgICBuYW1lOiBERUZBVUxUX0NVU1RPTV9QQUxFVFRFLm5hbWUsXG4gICAgdHlwZTogREVGQVVMVF9DVVNUT01fUEFMRVRURS50eXBlLFxuICAgIGNhdGVnb3J5OiBERUZBVUxUX0NVU1RPTV9QQUxFVFRFLmNhdGVnb3J5LFxuICAgIC4uLihjb2xvck1hcCA/IHtjb2xvck1hcH0gOiB7fSlcbiAgfTtcblxuICAvLyBvbmx5IGN1c3RvbVBhbGV0dGUuY29sb3JzIGFyZSBuZWVkZWQgZm9yIGN1c3RvbSBwYWxldHRlIGVkaXRvciB3aXRoIGN1c3RvbSBvcmRpbmFsIHNjYWxlXG4gIGlmICghY29sb3JNYXAgJiYgY29sb3JSYW5nZS50eXBlID09PSBTQ0FMRV9UWVBFUy5jdXN0b21PcmRpbmFsKSB7XG4gICAgZGVsZXRlIGN1c3RvbVBhbGV0dGUuY29sb3JNYXA7XG4gIH1cbiAgcmV0dXJuIGN1c3RvbVBhbGV0dGU7XG59XG4iXSwibWFwcGluZ3MiOiI7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