UNPKG

kepler.gl

Version:

kepler.gl is a webgl based application to visualize large scale location data in the browser

358 lines (348 loc) 76.5 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral")); var _react = _interopRequireWildcard(require("/Users/ihordykhta/Desktop/unfolded/kepler.gl/node_modules/react")); var _styledComponents = _interopRequireDefault(require("/Users/ihordykhta/Desktop/unfolded/kepler.gl/node_modules/styled-components")); var _src = require("/Users/ihordykhta/Desktop/unfolded/kepler.gl/src/constants/src"); var _src2 = require("/Users/ihordykhta/Desktop/unfolded/kepler.gl/src/layers/src"); var _src3 = require("/Users/ihordykhta/Desktop/unfolded/kepler.gl/src/localization/src"); var _src4 = require("/Users/ihordykhta/Desktop/unfolded/kepler.gl/src/utils/src"); var _rasterTileColormapListItem = require("./raster-tile-colormap-list-item"); var _styledComponents2 = require("../../common/styled-components"); var _switch = _interopRequireDefault(require("../../common/switch")); var _infoHelper = _interopRequireDefault(require("../../common/info-helper")); var _itemSelector = _interopRequireDefault(require("../../common/item-selector/item-selector")); var _visConfigSlider = _interopRequireDefault(require("../../side-panel/layer-panel/vis-config-slider")); var _layerConfigGroup = _interopRequireWildcard(require("../../side-panel/layer-panel/layer-config-group")); var _visConfigSwitch = _interopRequireDefault(require("../../side-panel/layer-panel/vis-config-switch")); var _templateObject, _templateObject2, _templateObject3; // SPDX-License-Identifier: MIT // Copyright contributors to the kepler.gl project 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; } 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; } var STAC_SEARCH_UI_ENABLED = true; var StyledVisConfigSwitch = _styledComponents["default"].div(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2["default"])(["\n display: flex;\n justify-content: space-between;\n\n .vis-config-switch__title {\n display: flex;\n }\n"]))); var CustomVisConfigSwitch = function CustomVisConfigSwitch(_ref) { var _ref$layer = _ref.layer, id = _ref$layer.id, config = _ref$layer.config, property = _ref.property, _onChange2 = _ref.onChange, label = _ref.label, disabled = _ref.disabled; return /*#__PURE__*/_react["default"].createElement(_styledComponents2.SidePanelSection, { disabled: Boolean(disabled) }, /*#__PURE__*/_react["default"].createElement(StyledVisConfigSwitch, { className: "vis-config-switch" }, /*#__PURE__*/_react["default"].createElement("div", { className: "vis-config-switch__title" }, /*#__PURE__*/_react["default"].createElement(_styledComponents2.PanelLabelWrapper, null, label ? /*#__PURE__*/_react["default"].createElement(_styledComponents2.PanelLabel, null, label && /*#__PURE__*/_react["default"].createElement(_src3.FormattedMessage, { id: label }) || (0, _src4.capitalizeFirstLetter)(property)) : null)), /*#__PURE__*/_react["default"].createElement("div", { className: "vis-config-switch__switch" }, /*#__PURE__*/_react["default"].createElement(_switch["default"], { checked: config.visConfig[property], id: "".concat(id, "-").concat(property, "-switch"), onChange: function onChange() { return _onChange2((0, _defineProperty2["default"])({}, property, !config.visConfig[property])); } })))); }; var StyledLayerConfigurator = _styledComponents["default"].div(_templateObject2 || (_templateObject2 = (0, _taggedTemplateLiteral2["default"])(["\n margin-top: 12px;\n"]))); var DescriptionText = (0, _styledComponents["default"])(_styledComponents2.PanelLabel)(_templateObject3 || (_templateObject3 = (0, _taggedTemplateLiteral2["default"])(["\n text-transform: none;\n display: inline;\n color: ", ";\n\n a {\n text-decoration: underline;\n margin-left: 4px;\n }\n"])), function (props) { return props.theme.subtextColor; }); // TODO: combine these two helpers into one function findVisConfigItemById(layer, prop) { return layer.visConfigSettings[prop].options.find(function (op) { return op.id === layer.config.visConfig[prop]; }); } function findItemById(layer, options, prop) { // For now it's possible that non-raster metadata will be passed to the raster configurator, so // options may be null return options === null || options === void 0 ? void 0 : options.find(function (op) { return op.id === layer.config.visConfig[prop]; }); } /** * Generate drop down labels for single band selector * @param stac - STAC item metadata object * @returns array of {id, label} elements */ function getBandSelectorOptions(stac) { var eoBands = (0, _src2.getEOBands)(stac) || []; return eoBands.map(function (eoBand) { return { id: eoBand.name || eoBand.common_name, label: eoBand.common_name ? "".concat(eoBand.name || eoBand.common_name, " (").concat(eoBand.common_name, ")") : eoBand.name }; }); } function getCategoricalColormapListItem(categoricalColorMap) { var categoricalItem; if (categoricalColorMap) { categoricalItem = { label: 'Categorical', id: _src2.CATEGORICAL_COLORMAP_ID }; } return categoricalItem; } /** * Check if data source global pixel color range is calculated correctly * @param layer - raster layer * @param stac - STAC metadata object * @param preset - preset name * @param singleBandPresetOptions - options for single band preset * @returns boolean value */ function isDataSourceColorRangeAvailable(layer, stac, preset, singleBandPresetOptions) { var minPixelValue = null; var maxPixelValue = null; var dataSourceParams = layer.getDataSourceParams(stac, preset, { singleBand: singleBandPresetOptions }); if (dataSourceParams) { minPixelValue = dataSourceParams.minPixelValue; maxPixelValue = dataSourceParams.maxPixelValue; } return minPixelValue !== null && maxPixelValue !== null; } /** * Updates color parameters based on a change in visualization preset. * * This function adjusts the color processing parameters when the visualization * preset changes, based on whether the preset is switching to or from a * single-band. Determines whether to apply color * enhancements or reset parameters based on the preset transition. * * @param stac A STAC (SpatioTemporal Asset Catalog) object representing the dataset. * @param newPreset The old visualization preset being applied. * @param newPreset The new visualization preset being applied. * @returns The updated color parameters to apply. */ function updateColorParamsOnPresetChange(stac, oldPreset, newPreset) { var colorParams = {}; var colorOverrides = _src2.DATA_SOURCE_COLOR_DEFAULTS[stac.id]; if (colorOverrides) return colorParams; var bandOfInterest = 'singleBand'; if (oldPreset === bandOfInterest && newPreset !== bandOfInterest) { // enchance colors for multiband combinations colorParams = colorOverrides; } else if (oldPreset !== bandOfInterest && newPreset === bandOfInterest) { // reset image processng params colorParams = _src2.RASTER_COLOR_RESET_PARAMS; } return colorParams; } RasterTileLayerConfiguratorFactory.deps = [_layerConfigGroup["default"], _visConfigSlider["default"], _infoHelper["default"], _visConfigSwitch["default"]]; function RasterTileLayerConfiguratorFactory(LayerConfigGroup, VisConfigSlider, InfoHelper, VisConfigSwitch) { /** * Wrapper around configurator to check for dataset.metadata being null/undefined */ var STACCheckConfiguratorWrapper = function STACCheckConfiguratorWrapper(_ref2) { var layer = _ref2.layer, visConfiguratorProps = _ref2.visConfiguratorProps, dataset = _ref2.dataset; var stac = dataset === null || dataset === void 0 ? void 0 : dataset.metadata; // If no dataset is loaded into Kepler, stac can be undefined if (!stac) { return null; } return /*#__PURE__*/_react["default"].createElement(RasterTileLayerConfigurator, { layer: layer, visConfiguratorProps: visConfiguratorProps, dataset: dataset }); }; // eslint-disable-next-line complexity var RasterTileLayerConfigurator = function RasterTileLayerConfigurator(_ref3) { var _stac$rasterTileServe; var layer = _ref3.layer, visConfiguratorProps = _ref3.visConfiguratorProps, dataset = _ref3.dataset; var _layer$config$visConf = layer.config.visConfig, preset = _layer$config$visConf.preset, nonLinearRescaling = _layer$config$visConf.nonLinearRescaling, useSTACSearching = _layer$config$visConf.useSTACSearching, categoricalColorMap = _layer$config$visConf.colorRange.colorMap, dynamicColor = _layer$config$visConf.dynamicColor, singleBandName = _layer$config$visConf.singleBandName; var stac = dataset === null || dataset === void 0 ? void 0 : dataset.metadata; var availablePresets = (0, _react.useMemo)(function () { return (0, _src2.filterAvailablePresets)(stac, _src2.PRESET_OPTIONS); }, [stac]); var presetOptions = (0, _react.useMemo)(function () { return layer.visConfigSettings.preset.options.filter(function (_ref4) { var id = _ref4.id; return availablePresets === null || availablePresets === void 0 ? void 0 : availablePresets.includes(id); }); }, [layer.visConfigSettings.preset.options, availablePresets]); var singleBandOptions = (0, _react.useMemo)(function () { return getBandSelectorOptions(stac); }, [stac]); var colormapOptions = (0, _react.useMemo)(function () { var options = (0, _toConsumableArray2["default"])(layer.visConfigSettings.colormapId.options); var categoricalListItem = getCategoricalColormapListItem(categoricalColorMap); if (categoricalListItem) { options.push(categoricalListItem); } return options; }, [layer.visConfigSettings.colormapId.options, categoricalColorMap]); var _ref5 = _src2.PRESET_OPTIONS[preset] || {}, bandCombination = _ref5.bandCombination; var colormapAllowed = (0, _src2.isColormapAllowed)(bandCombination); var rescalingAllowed = !categoricalColorMap && (0, _src2.isRescalingAllowed)(bandCombination); var filterAllowed = (0, _src2.isFilterAllowed)(bandCombination); // Here we show the UI when useSTACSearching is explicitly set to true so that the UI shows up var stacSearchAllowed = (0, _src2.isSearchableStac)(stac) || useSTACSearching; var selectedColormap = findVisConfigItemById(layer, 'colormapId') || getCategoricalColormapListItem(categoricalColorMap); var selectedPreset = findVisConfigItemById(layer, 'preset'); var selectedSingleBandName = findItemById(layer, singleBandOptions, 'singleBandName'); var singleBandPresetOptions = (0, _src2.getSingleBandPresetOptions)(stac, singleBandName); var _getRasterStatisticsM = (0, _src2.getRasterStatisticsMinMax)(stac, preset, singleBandPresetOptions), _getRasterStatisticsM2 = (0, _slicedToArray2["default"])(_getRasterStatisticsM, 2), minCategoricalBandValue = _getRasterStatisticsM2[0], maxCategoricalBandValue = _getRasterStatisticsM2[1]; var ColorMapListItem = (0, _react.useMemo)(function () { return (0, _rasterTileColormapListItem.getColorMapListItemComponent)({ colorMap: categoricalColorMap, minValue: minCategoricalBandValue, maxValue: maxCategoricalBandValue }); }, [categoricalColorMap, minCategoricalBandValue, maxCategoricalBandValue]); var isDynamicColorsOnly = !isDataSourceColorRangeAvailable(layer, stac, preset, singleBandPresetOptions); // Default of `dynamicColor` is false. Set it true if it is not possible to get data source // wide color range (0, _react.useEffect)(function () { if (isDynamicColorsOnly && !dynamicColor) { visConfiguratorProps.onChange({ dynamicColor: true }); } }, [visConfiguratorProps, dynamicColor, isDynamicColorsOnly]); var elevationUI = /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, (0, _src4.getApplicationConfig)().rasterServerSupportsElevation && ((_stac$rasterTileServe = stac.rasterTileServerUrls) === null || _stac$rasterTileServe === void 0 ? void 0 : _stac$rasterTileServe.length) && /*#__PURE__*/_react["default"].createElement(LayerConfigGroup, (0, _extends2["default"])({}, layer.visConfigSettings.enableTerrain || { label: 'layer.color' }, visConfiguratorProps, { collapsible: true }), /*#__PURE__*/_react["default"].createElement(_layerConfigGroup.ConfigGroupCollapsibleContent, null, /*#__PURE__*/_react["default"].createElement(VisConfigSwitch, (0, _extends2["default"])({}, visConfiguratorProps, layer.visConfigSettings.enableTerrainTopView))))); // For PMTiles in raster format, only show opacity and terrain options for now if (stac.pmtilesType === _src.PMTilesType.RASTER) { return /*#__PURE__*/_react["default"].createElement(StyledLayerConfigurator, null, /*#__PURE__*/_react["default"].createElement(LayerConfigGroup, (0, _extends2["default"])({}, visConfiguratorProps, { label: "Visual Settings", collapsible: false }), /*#__PURE__*/_react["default"].createElement(VisConfigSlider, (0, _extends2["default"])({}, layer.visConfigSettings.opacity, visConfiguratorProps))), elevationUI); } return /*#__PURE__*/_react["default"].createElement(StyledLayerConfigurator, null, availablePresets && /*#__PURE__*/_react["default"].createElement(LayerConfigGroup, (0, _extends2["default"])({}, visConfiguratorProps, { label: "Image Selection", collapsible: false }), /*#__PURE__*/_react["default"].createElement(_styledComponents2.SidePanelSection, null, /*#__PURE__*/_react["default"].createElement(_styledComponents2.PanelLabelWrapper, null, /*#__PURE__*/_react["default"].createElement(_styledComponents2.PanelLabel, null, "Preset"), /*#__PURE__*/_react["default"].createElement(InfoHelper, { id: "preset", description: "Select a preset to describe how to combine spectral bands." })), /*#__PURE__*/_react["default"].createElement(_itemSelector["default"], { selectedItems: selectedPreset, options: presetOptions, multiSelect: false, searchable: false, displayOption: "label", getOptionValue: "id", onChange: function onChange(newPreset) { var overrides = updateColorParamsOnPresetChange(stac, visConfiguratorProps.layer.config.visConfig.preset, newPreset); visConfiguratorProps.onChange(_objectSpread(_objectSpread({}, overrides), {}, { preset: newPreset })); } }), selectedPreset !== null && selectedPreset !== void 0 && selectedPreset.description ? /*#__PURE__*/_react["default"].createElement(DescriptionText, null, selectedPreset === null || selectedPreset === void 0 ? void 0 : selectedPreset.description, selectedPreset !== null && selectedPreset !== void 0 && selectedPreset.infoUrl ? /*#__PURE__*/_react["default"].createElement("a", { target: "_blank", rel: "noopener noreferrer", href: selectedPreset === null || selectedPreset === void 0 ? void 0 : selectedPreset.infoUrl }, "More Info") : null) : null), selectedPreset.id === 'singleBand' && /*#__PURE__*/_react["default"].createElement(_styledComponents2.SidePanelSection, null, /*#__PURE__*/_react["default"].createElement(_styledComponents2.PanelLabelWrapper, null, /*#__PURE__*/_react["default"].createElement(_styledComponents2.PanelLabel, null, "Single Band Name"), /*#__PURE__*/_react["default"].createElement(InfoHelper, { id: "".concat(layer.id, "-single-band-name"), description: "Select a single band." })), /*#__PURE__*/_react["default"].createElement(_itemSelector["default"], { selectedItems: selectedSingleBandName, options: singleBandOptions, multiSelect: false, searchable: false, displayOption: "label", getOptionValue: "id", onChange: function onChange(val) { visConfiguratorProps.onChange({ singleBandName: val }); } })), STAC_SEARCH_UI_ENABLED && stacSearchAllowed && /*#__PURE__*/_react["default"].createElement(CustomVisConfigSwitch, (0, _extends2["default"])({}, layer.visConfigSettings.useSTACSearching, visConfiguratorProps)), STAC_SEARCH_UI_ENABLED && /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, stacSearchAllowed && useSTACSearching ? /*#__PURE__*/_react["default"].createElement(_styledComponents2.SidePanelSection, null, /*#__PURE__*/_react["default"].createElement(_styledComponents2.PanelLabelWrapper, null, /*#__PURE__*/_react["default"].createElement(_styledComponents2.PanelLabel, null, "STAC Search Provider")), /*#__PURE__*/_react["default"].createElement(_itemSelector["default"], (0, _extends2["default"])({}, layer.visConfigSettings.stacSearchProvider, { selectedItems: findVisConfigItemById(layer, 'stacSearchProvider'), placeholder: "Choose search provider", multiSelect: false, searchable: false, displayOption: "label", getOptionValue: "id", onChange: function onChange(val) { // TODO: check when switching layers so that you don't mismatch allowed mosaics with layers visConfiguratorProps.onChange({ stacSearchProvider: val }); } })), /*#__PURE__*/_react["default"].createElement(_styledComponents2.PanelLabelWrapper, null, /*#__PURE__*/_react["default"].createElement(_styledComponents2.PanelLabel, null, "Date Range")), /*#__PURE__*/_react["default"].createElement(_styledComponents2.Input, { type: "text", id: "".concat(layer.id, "-startDate"), onChange: function onChange(_ref6) { var value = _ref6.target.value; visConfiguratorProps.onChange({ startDate: value }); }, value: layer.config.visConfig.startDate }), /*#__PURE__*/_react["default"].createElement(_styledComponents2.Input, { type: "text", id: "".concat(layer.id, "-endDate"), onChange: function onChange(_ref7) { var value = _ref7.target.value; visConfiguratorProps.onChange({ endDate: value }); }, value: layer.config.visConfig.endDate }), /*#__PURE__*/_react["default"].createElement(DescriptionText, null, "Date format must be \"YYYY-MM-DD\"")) : null)), /*#__PURE__*/_react["default"].createElement(LayerConfigGroup, (0, _extends2["default"])({}, visConfiguratorProps, { label: "Visual Settings", collapsible: false }), /*#__PURE__*/_react["default"].createElement(VisConfigSlider, (0, _extends2["default"])({}, layer.visConfigSettings.opacity, visConfiguratorProps)), colormapAllowed && /*#__PURE__*/_react["default"].createElement(_styledComponents2.SidePanelSection, null, /*#__PURE__*/_react["default"].createElement(_styledComponents2.PanelLabel, null, "Colormap"), /*#__PURE__*/_react["default"].createElement(_itemSelector["default"], { selectedItems: selectedColormap, options: colormapOptions, multiSelect: false, displayOption: "label", getOptionValue: "id", onChange: function onChange(val) { visConfiguratorProps.onChange({ colormapId: val }); }, DropDownLineItemRenderComponent: ColorMapListItem, filterOption: "label", searchable: true }))), rescalingAllowed && /*#__PURE__*/_react["default"].createElement(LayerConfigGroup, (0, _extends2["default"])({}, visConfiguratorProps, { label: "Rescaling" }), /*#__PURE__*/_react["default"].createElement(VisConfigSwitch, (0, _extends2["default"])({}, visConfiguratorProps, layer.visConfigSettings.dynamicColor, { disabled: isDynamicColorsOnly })), /*#__PURE__*/_react["default"].createElement(VisConfigSwitch, (0, _extends2["default"])({}, layer.visConfigSettings.nonLinearRescaling, visConfiguratorProps, { label: nonLinearRescaling ? 'Non-Linear Rescaling' : 'Linear Rescaling' })), nonLinearRescaling ? /*#__PURE__*/_react["default"].createElement("div", null, /*#__PURE__*/_react["default"].createElement(VisConfigSlider, (0, _extends2["default"])({}, layer.visConfigSettings.gammaContrastFactor, visConfiguratorProps)), /*#__PURE__*/_react["default"].createElement(VisConfigSlider, (0, _extends2["default"])({}, layer.visConfigSettings.sigmoidalContrastFactor, visConfiguratorProps)), /*#__PURE__*/_react["default"].createElement(VisConfigSlider, (0, _extends2["default"])({}, layer.visConfigSettings.sigmoidalBiasFactor, visConfiguratorProps))) : /*#__PURE__*/_react["default"].createElement(VisConfigSlider, (0, _extends2["default"])({}, layer.visConfigSettings.linearRescalingFactor, visConfiguratorProps)), /*#__PURE__*/_react["default"].createElement(VisConfigSlider, (0, _extends2["default"])({}, layer.visConfigSettings.saturationValue, visConfiguratorProps))), filterAllowed && /*#__PURE__*/_react["default"].createElement(LayerConfigGroup, (0, _extends2["default"])({}, layer.visConfigSettings.filterEnabled, visConfiguratorProps, { collapsible: true }), /*#__PURE__*/_react["default"].createElement(VisConfigSlider, (0, _extends2["default"])({}, layer.visConfigSettings.filterRange, visConfiguratorProps))), elevationUI); }; return STACCheckConfiguratorWrapper; } var _default = exports["default"] = RasterTileLayerConfiguratorFactory; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVXaWxkY2FyZCIsInJlcXVpcmUiLCJfc3R5bGVkQ29tcG9uZW50cyIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJfc3JjIiwiX3NyYzIiLCJfc3JjMyIsIl9zcmM0IiwiX3Jhc3RlclRpbGVDb2xvcm1hcExpc3RJdGVtIiwiX3N0eWxlZENvbXBvbmVudHMyIiwiX3N3aXRjaCIsIl9pbmZvSGVscGVyIiwiX2l0ZW1TZWxlY3RvciIsIl92aXNDb25maWdTbGlkZXIiLCJfbGF5ZXJDb25maWdHcm91cCIsIl92aXNDb25maWdTd2l0Y2giLCJfdGVtcGxhdGVPYmplY3QiLCJfdGVtcGxhdGVPYmplY3QyIiwiX3RlbXBsYXRlT2JqZWN0MyIsIl9nZXRSZXF1aXJlV2lsZGNhcmRDYWNoZSIsImUiLCJXZWFrTWFwIiwiciIsInQiLCJfX2VzTW9kdWxlIiwiX3R5cGVvZiIsImhhcyIsImdldCIsIm4iLCJfX3Byb3RvX18iLCJhIiwiT2JqZWN0IiwiZGVmaW5lUHJvcGVydHkiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJ1IiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiaSIsInNldCIsIm93bktleXMiLCJrZXlzIiwiZ2V0T3duUHJvcGVydHlTeW1ib2xzIiwibyIsImZpbHRlciIsImVudW1lcmFibGUiLCJwdXNoIiwiYXBwbHkiLCJfb2JqZWN0U3ByZWFkIiwiYXJndW1lbnRzIiwibGVuZ3RoIiwiZm9yRWFjaCIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzIiwiZGVmaW5lUHJvcGVydGllcyIsIlNUQUNfU0VBUkNIX1VJX0VOQUJMRUQiLCJTdHlsZWRWaXNDb25maWdTd2l0Y2giLCJzdHlsZWQiLCJkaXYiLCJfdGFnZ2VkVGVtcGxhdGVMaXRlcmFsMiIsIkN1c3RvbVZpc0NvbmZpZ1N3aXRjaCIsIl9yZWYiLCJfcmVmJGxheWVyIiwibGF5ZXIiLCJpZCIsImNvbmZpZyIsInByb3BlcnR5Iiwib25DaGFuZ2UiLCJsYWJlbCIsImRpc2FibGVkIiwiY3JlYXRlRWxlbWVudCIsIlNpZGVQYW5lbFNlY3Rpb24iLCJCb29sZWFuIiwiY2xhc3NOYW1lIiwiUGFuZWxMYWJlbFdyYXBwZXIiLCJQYW5lbExhYmVsIiwiRm9ybWF0dGVkTWVzc2FnZSIsImNhcGl0YWxpemVGaXJzdExldHRlciIsImNoZWNrZWQiLCJ2aXNDb25maWciLCJjb25jYXQiLCJTdHlsZWRMYXllckNvbmZpZ3VyYXRvciIsIkRlc2NyaXB0aW9uVGV4dCIsInByb3BzIiwidGhlbWUiLCJzdWJ0ZXh0Q29sb3IiLCJmaW5kVmlzQ29uZmlnSXRlbUJ5SWQiLCJwcm9wIiwidmlzQ29uZmlnU2V0dGluZ3MiLCJvcHRpb25zIiwiZmluZCIsIm9wIiwiZmluZEl0ZW1CeUlkIiwiZ2V0QmFuZFNlbGVjdG9yT3B0aW9ucyIsInN0YWMiLCJlb0JhbmRzIiwiZ2V0RU9CYW5kcyIsIm1hcCIsImVvQmFuZCIsIm5hbWUiLCJjb21tb25fbmFtZSIsImdldENhdGVnb3JpY2FsQ29sb3JtYXBMaXN0SXRlbSIsImNhdGVnb3JpY2FsQ29sb3JNYXAiLCJjYXRlZ29yaWNhbEl0ZW0iLCJDQVRFR09SSUNBTF9DT0xPUk1BUF9JRCIsImlzRGF0YVNvdXJjZUNvbG9yUmFuZ2VBdmFpbGFibGUiLCJwcmVzZXQiLCJzaW5nbGVCYW5kUHJlc2V0T3B0aW9ucyIsIm1pblBpeGVsVmFsdWUiLCJtYXhQaXhlbFZhbHVlIiwiZGF0YVNvdXJjZVBhcmFtcyIsImdldERhdGFTb3VyY2VQYXJhbXMiLCJzaW5nbGVCYW5kIiwidXBkYXRlQ29sb3JQYXJhbXNPblByZXNldENoYW5nZSIsIm9sZFByZXNldCIsIm5ld1ByZXNldCIsImNvbG9yUGFyYW1zIiwiY29sb3JPdmVycmlkZXMiLCJEQVRBX1NPVVJDRV9DT0xPUl9ERUZBVUxUUyIsImJhbmRPZkludGVyZXN0IiwiUkFTVEVSX0NPTE9SX1JFU0VUX1BBUkFNUyIsIlJhc3RlclRpbGVMYXllckNvbmZpZ3VyYXRvckZhY3RvcnkiLCJkZXBzIiwiTGF5ZXJDb25maWdHcm91cEZhY3RvcnkiLCJWaXNDb25maWdTbGlkZXJGYWN0b3J5IiwiSW5mb0hlbHBlckZhY3RvcnkiLCJWaXNDb25maWdTd2l0Y2hGYWN0b3J5IiwiTGF5ZXJDb25maWdHcm91cCIsIlZpc0NvbmZpZ1NsaWRlciIsIkluZm9IZWxwZXIiLCJWaXNDb25maWdTd2l0Y2giLCJTVEFDQ2hlY2tDb25maWd1cmF0b3JXcmFwcGVyIiwiX3JlZjIiLCJ2aXNDb25maWd1cmF0b3JQcm9wcyIsImRhdGFzZXQiLCJtZXRhZGF0YSIsIlJhc3RlclRpbGVMYXllckNvbmZpZ3VyYXRvciIsIl9yZWYzIiwiX3N0YWMkcmFzdGVyVGlsZVNlcnZlIiwiX2xheWVyJGNvbmZpZyR2aXNDb25mIiwibm9uTGluZWFyUmVzY2FsaW5nIiwidXNlU1RBQ1NlYXJjaGluZyIsImNvbG9yUmFuZ2UiLCJjb2xvck1hcCIsImR5bmFtaWNDb2xvciIsInNpbmdsZUJhbmROYW1lIiwiYXZhaWxhYmxlUHJlc2V0cyIsInVzZU1lbW8iLCJmaWx0ZXJBdmFpbGFibGVQcmVzZXRzIiwiUFJFU0VUX09QVElPTlMiLCJwcmVzZXRPcHRpb25zIiwiX3JlZjQiLCJpbmNsdWRlcyIsInNpbmdsZUJhbmRPcHRpb25zIiwiY29sb3JtYXBPcHRpb25zIiwiX3RvQ29uc3VtYWJsZUFycmF5MiIsImNvbG9ybWFwSWQiLCJjYXRlZ29yaWNhbExpc3RJdGVtIiwiX3JlZjUiLCJiYW5kQ29tYmluYXRpb24iLCJjb2xvcm1hcEFsbG93ZWQiLCJpc0NvbG9ybWFwQWxsb3dlZCIsInJlc2NhbGluZ0FsbG93ZWQiLCJpc1Jlc2NhbGluZ0FsbG93ZWQiLCJmaWx0ZXJBbGxvd2VkIiwiaXNGaWx0ZXJBbGxvd2VkIiwic3RhY1NlYXJjaEFsbG93ZWQiLCJpc1NlYXJjaGFibGVTdGFjIiwic2VsZWN0ZWRDb2xvcm1hcCIsInNlbGVjdGVkUHJlc2V0Iiwic2VsZWN0ZWRTaW5nbGVCYW5kTmFtZSIsImdldFNpbmdsZUJhbmRQcmVzZXRPcHRpb25zIiwiX2dldFJhc3RlclN0YXRpc3RpY3NNIiwiZ2V0UmFzdGVyU3RhdGlzdGljc01pbk1heCIsIl9nZXRSYXN0ZXJTdGF0aXN0aWNzTTIiLCJfc2xpY2VkVG9BcnJheTIiLCJtaW5DYXRlZ29yaWNhbEJhbmRWYWx1ZSIsIm1heENhdGVnb3JpY2FsQmFuZFZhbHVlIiwiQ29sb3JNYXBMaXN0SXRlbSIsImdldENvbG9yTWFwTGlzdEl0ZW1Db21wb25lbnQiLCJtaW5WYWx1ZSIsIm1heFZhbHVlIiwiaXNEeW5hbWljQ29sb3JzT25seSIsInVzZUVmZmVjdCIsImVsZXZhdGlvblVJIiwiRnJhZ21lbnQiLCJnZXRBcHBsaWNhdGlvbkNvbmZpZyIsInJhc3RlclNlcnZlclN1cHBvcnRzRWxldmF0aW9uIiwicmFzdGVyVGlsZVNlcnZlclVybHMiLCJfZXh0ZW5kczIiLCJlbmFibGVUZXJyYWluIiwiY29sbGFwc2libGUiLCJDb25maWdHcm91cENvbGxhcHNpYmxlQ29udGVudCIsImVuYWJsZVRlcnJhaW5Ub3BWaWV3IiwicG10aWxlc1R5cGUiLCJQTVRpbGVzVHlwZSIsIlJBU1RFUiIsIm9wYWNpdHkiLCJkZXNjcmlwdGlvbiIsInNlbGVjdGVkSXRlbXMiLCJtdWx0aVNlbGVjdCIsInNlYXJjaGFibGUiLCJkaXNwbGF5T3B0aW9uIiwiZ2V0T3B0aW9uVmFsdWUiLCJvdmVycmlkZXMiLCJpbmZvVXJsIiwidGFyZ2V0IiwicmVsIiwiaHJlZiIsInZhbCIsInN0YWNTZWFyY2hQcm92aWRlciIsInBsYWNlaG9sZGVyIiwiSW5wdXQiLCJ0eXBlIiwiX3JlZjYiLCJ2YWx1ZSIsInN0YXJ0RGF0ZSIsIl9yZWY3IiwiZW5kRGF0ZSIsIkRyb3BEb3duTGluZUl0ZW1SZW5kZXJDb21wb25lbnQiLCJmaWx0ZXJPcHRpb24iLCJnYW1tYUNvbnRyYXN0RmFjdG9yIiwic2lnbW9pZGFsQ29udHJhc3RGYWN0b3IiLCJzaWdtb2lkYWxCaWFzRmFjdG9yIiwibGluZWFyUmVzY2FsaW5nRmFjdG9yIiwic2F0dXJhdGlvblZhbHVlIiwiZmlsdGVyRW5hYmxlZCIsImZpbHRlclJhbmdlIiwiX2RlZmF1bHQiLCJleHBvcnRzIl0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvc3JjL3NpZGUtcGFuZWwvbGF5ZXItcGFuZWwvcmFzdGVyLXRpbGUtbGF5ZXItY29uZmlndXJhdG9yLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogTUlUXG4vLyBDb3B5cmlnaHQgY29udHJpYnV0b3JzIHRvIHRoZSBrZXBsZXIuZ2wgcHJvamVjdFxuXG5pbXBvcnQgUmVhY3QsIHt1c2VFZmZlY3QsIHVzZU1lbW99IGZyb20gJ3JlYWN0JztcbmltcG9ydCBzdHlsZWQgZnJvbSAnc3R5bGVkLWNvbXBvbmVudHMnO1xuXG5pbXBvcnQge1BNVGlsZXNUeXBlfSBmcm9tICdAa2VwbGVyLmdsL2NvbnN0YW50cyc7XG5pbXBvcnQge1xuICBmaWx0ZXJBdmFpbGFibGVQcmVzZXRzLFxuICBnZXRFT0JhbmRzLFxuICBnZXRSYXN0ZXJTdGF0aXN0aWNzTWluTWF4LFxuICBnZXRTaW5nbGVCYW5kUHJlc2V0T3B0aW9ucyxcbiAgaXNDb2xvcm1hcEFsbG93ZWQsXG4gIGlzRmlsdGVyQWxsb3dlZCxcbiAgaXNSZXNjYWxpbmdBbGxvd2VkLFxuICBpc1NlYXJjaGFibGVTdGFjLFxuICBDb21wbGV0ZVNUQUNPYmplY3QsXG4gIEdldFRpbGVEYXRhQ3VzdG9tUHJvcHMsXG4gIERhdGFTb3VyY2VQYXJhbXMsXG4gIFByZXNldE9wdGlvbixcbiAgUmFzdGVyVGlsZUxheWVyLFxuICBDQVRFR09SSUNBTF9DT0xPUk1BUF9JRCxcbiAgUFJFU0VUX09QVElPTlMsXG4gIFJBU1RFUl9DT0xPUl9SRVNFVF9QQVJBTVMsXG4gIERBVEFfU09VUkNFX0NPTE9SX0RFRkFVTFRTXG59IGZyb20gJ0BrZXBsZXIuZ2wvbGF5ZXJzJztcbmltcG9ydCB7Rm9ybWF0dGVkTWVzc2FnZX0gZnJvbSAnQGtlcGxlci5nbC9sb2NhbGl6YXRpb24nO1xuaW1wb3J0IHtjYXBpdGFsaXplRmlyc3RMZXR0ZXIsIGdldEFwcGxpY2F0aW9uQ29uZmlnfSBmcm9tICdAa2VwbGVyLmdsL3V0aWxzJztcbmltcG9ydCB7S2VwbGVyVGFibGUgYXMgS2VwbGVyRGF0YXNldH0gZnJvbSAnQGtlcGxlci5nbC90YWJsZSc7XG5pbXBvcnQgdHlwZSB7U3RhY1R5cGVzfSBmcm9tICdAa2VwbGVyLmdsL3R5cGVzJztcblxuaW1wb3J0IHtnZXRDb2xvck1hcExpc3RJdGVtQ29tcG9uZW50fSBmcm9tICcuL3Jhc3Rlci10aWxlLWNvbG9ybWFwLWxpc3QtaXRlbSc7XG5cbmltcG9ydCB7XG4gIElucHV0LFxuICBQYW5lbExhYmVsLFxuICBQYW5lbExhYmVsV3JhcHBlcixcbiAgU2lkZVBhbmVsU2VjdGlvblxufSBmcm9tICcuLi8uLi9jb21tb24vc3R5bGVkLWNvbXBvbmVudHMnO1xuaW1wb3J0IFN3aXRjaCBmcm9tICcuLi8uLi9jb21tb24vc3dpdGNoJztcbmltcG9ydCBJbmZvSGVscGVyRmFjdG9yeSBmcm9tICcuLi8uLi9jb21tb24vaW5mby1oZWxwZXInO1xuaW1wb3J0IEl0ZW1TZWxlY3RvciBmcm9tICcuLi8uLi9jb21tb24vaXRlbS1zZWxlY3Rvci9pdGVtLXNlbGVjdG9yJztcbmltcG9ydCBWaXNDb25maWdTbGlkZXJGYWN0b3J5IGZyb20gJy4uLy4uL3NpZGUtcGFuZWwvbGF5ZXItcGFuZWwvdmlzLWNvbmZpZy1zbGlkZXInO1xuaW1wb3J0IExheWVyQ29uZmlnR3JvdXBGYWN0b3J5LCB7XG4gIENvbmZpZ0dyb3VwQ29sbGFwc2libGVDb250ZW50XG59IGZyb20gJy4uLy4uL3NpZGUtcGFuZWwvbGF5ZXItcGFuZWwvbGF5ZXItY29uZmlnLWdyb3VwJztcbmltcG9ydCBWaXNDb25maWdTd2l0Y2hGYWN0b3J5IGZyb20gJy4uLy4uL3NpZGUtcGFuZWwvbGF5ZXItcGFuZWwvdmlzLWNvbmZpZy1zd2l0Y2gnO1xuXG50eXBlIEVPQmFuZCA9IFN0YWNUeXBlcy5CYW5kO1xuXG5jb25zdCBTVEFDX1NFQVJDSF9VSV9FTkFCTEVEID0gdHJ1ZTtcblxuY29uc3QgU3R5bGVkVmlzQ29uZmlnU3dpdGNoID0gc3R5bGVkLmRpdmBcbiAgZGlzcGxheTogZmxleDtcbiAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xuXG4gIC52aXMtY29uZmlnLXN3aXRjaF9fdGl0bGUge1xuICAgIGRpc3BsYXk6IGZsZXg7XG4gIH1cbmA7XG5cbmNvbnN0IEN1c3RvbVZpc0NvbmZpZ1N3aXRjaCA9ICh7XG4gIGxheWVyOiB7aWQsIGNvbmZpZ30sXG4gIHByb3BlcnR5LFxuICBvbkNoYW5nZSxcbiAgbGFiZWwsXG4gIGRpc2FibGVkXG59OiB7XG4gIGxheWVyOiBSYXN0ZXJUaWxlTGF5ZXI7XG4gIHByb3BlcnR5OiBzdHJpbmc7XG4gIG9uQ2hhbmdlOiAodmFsdWU6IGFueSkgPT4gdm9pZDtcbiAgbGFiZWw6IHN0cmluZztcbiAgZGlzYWJsZWQ6IGJvb2xlYW47XG59KSA9PiAoXG4gIDxTaWRlUGFuZWxTZWN0aW9uIGRpc2FibGVkPXtCb29sZWFuKGRpc2FibGVkKX0+XG4gICAgPFN0eWxlZFZpc0NvbmZpZ1N3aXRjaCBjbGFzc05hbWU9XCJ2aXMtY29uZmlnLXN3aXRjaFwiPlxuICAgICAgPGRpdiBjbGFzc05hbWU9XCJ2aXMtY29uZmlnLXN3aXRjaF9fdGl0bGVcIj5cbiAgICAgICAgPFBhbmVsTGFiZWxXcmFwcGVyPlxuICAgICAgICAgIHtsYWJlbCA/IChcbiAgICAgICAgICAgIDxQYW5lbExhYmVsPlxuICAgICAgICAgICAgICB7KGxhYmVsICYmIDxGb3JtYXR0ZWRNZXNzYWdlIGlkPXtsYWJlbH0gLz4pIHx8IGNhcGl0YWxpemVGaXJzdExldHRlcihwcm9wZXJ0eSl9XG4gICAgICAgICAgICA8L1BhbmVsTGFiZWw+XG4gICAgICAgICAgKSA6IG51bGx9XG4gICAgICAgIDwvUGFuZWxMYWJlbFdyYXBwZXI+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3NOYW1lPVwidmlzLWNvbmZpZy1zd2l0Y2hfX3N3aXRjaFwiPlxuICAgICAgICA8U3dpdGNoXG4gICAgICAgICAgY2hlY2tlZD17Y29uZmlnLnZpc0NvbmZpZ1twcm9wZXJ0eV19XG4gICAgICAgICAgaWQ9e2Ake2lkfS0ke3Byb3BlcnR5fS1zd2l0Y2hgfVxuICAgICAgICAgIG9uQ2hhbmdlPXsoKSA9PiBvbkNoYW5nZSh7W3Byb3BlcnR5XTogIWNvbmZpZy52aXNDb25maWdbcHJvcGVydHldfSl9XG4gICAgICAgIC8+XG4gICAgICA8L2Rpdj5cbiAgICA8L1N0eWxlZFZpc0NvbmZpZ1N3aXRjaD5cbiAgPC9TaWRlUGFuZWxTZWN0aW9uPlxuKTtcblxuY29uc3QgU3R5bGVkTGF5ZXJDb25maWd1cmF0b3IgPSBzdHlsZWQuZGl2YFxuICBtYXJnaW4tdG9wOiAxMnB4O1xuYDtcblxuY29uc3QgRGVzY3JpcHRpb25UZXh0ID0gc3R5bGVkKFBhbmVsTGFiZWwpYFxuICB0ZXh0LXRyYW5zZm9ybTogbm9uZTtcbiAgZGlzcGxheTogaW5saW5lO1xuICBjb2xvcjogJHtwcm9wcyA9PiBwcm9wcy50aGVtZS5zdWJ0ZXh0Q29sb3J9O1xuXG4gIGEge1xuICAgIHRleHQtZGVjb3JhdGlvbjogdW5kZXJsaW5lO1xuICAgIG1hcmdpbi1sZWZ0OiA0cHg7XG4gIH1cbmA7XG5cbi8vIFRPRE86IGNvbWJpbmUgdGhlc2UgdHdvIGhlbHBlcnMgaW50byBvbmVcbmZ1bmN0aW9uIGZpbmRWaXNDb25maWdJdGVtQnlJZChsYXllciwgcHJvcCkge1xuICByZXR1cm4gbGF5ZXIudmlzQ29uZmlnU2V0dGluZ3NbcHJvcF0ub3B0aW9ucy5maW5kKG9wID0+IG9wLmlkID09PSBsYXllci5jb25maWcudmlzQ29uZmlnW3Byb3BdKTtcbn1cblxuZnVuY3Rpb24gZmluZEl0ZW1CeUlkKGxheWVyLCBvcHRpb25zLCBwcm9wKSB7XG4gIC8vIEZvciBub3cgaXQncyBwb3NzaWJsZSB0aGF0IG5vbi1yYXN0ZXIgbWV0YWRhdGEgd2lsbCBiZSBwYXNzZWQgdG8gdGhlIHJhc3RlciBjb25maWd1cmF0b3IsIHNvXG4gIC8vIG9wdGlvbnMgbWF5IGJlIG51bGxcbiAgcmV0dXJuIG9wdGlvbnM/LmZpbmQob3AgPT4gb3AuaWQgPT09IGxheWVyLmNvbmZpZy52aXNDb25maWdbcHJvcF0pO1xufVxuXG4vKipcbiAqIEdlbmVyYXRlIGRyb3AgZG93biBsYWJlbHMgZm9yIHNpbmdsZSBiYW5kIHNlbGVjdG9yXG4gKiBAcGFyYW0gc3RhYyAtIFNUQUMgaXRlbSBtZXRhZGF0YSBvYmplY3RcbiAqIEByZXR1cm5zIGFycmF5IG9mIHtpZCwgbGFiZWx9IGVsZW1lbnRzXG4gKi9cbmZ1bmN0aW9uIGdldEJhbmRTZWxlY3Rvck9wdGlvbnMoc3RhYzogQ29tcGxldGVTVEFDT2JqZWN0KToge2lkPzogc3RyaW5nOyBsYWJlbD86IHN0cmluZ31bXSB7XG4gIGNvbnN0IGVvQmFuZHMgPSBnZXRFT0JhbmRzKHN0YWMpIHx8IFtdO1xuICByZXR1cm4gZW9CYW5kcy5tYXAoKGVvQmFuZDogRU9CYW5kKSA9PiAoe1xuICAgIGlkOiBlb0JhbmQubmFtZSB8fCBlb0JhbmQuY29tbW9uX25hbWUsXG4gICAgbGFiZWw6IGVvQmFuZC5jb21tb25fbmFtZVxuICAgICAgPyBgJHtlb0JhbmQubmFtZSB8fCBlb0JhbmQuY29tbW9uX25hbWV9ICgke2VvQmFuZC5jb21tb25fbmFtZX0pYFxuICAgICAgOiBlb0JhbmQubmFtZVxuICB9KSk7XG59XG5cbmZ1bmN0aW9uIGdldENhdGVnb3JpY2FsQ29sb3JtYXBMaXN0SXRlbShjYXRlZ29yaWNhbENvbG9yTWFwKSB7XG4gIGxldCBjYXRlZ29yaWNhbEl0ZW06IHtsYWJlbDogc3RyaW5nOyBpZDogc3RyaW5nfSB8IHVuZGVmaW5lZDtcbiAgaWYgKGNhdGVnb3JpY2FsQ29sb3JNYXApIHtcbiAgICBjYXRlZ29yaWNhbEl0ZW0gPSB7bGFiZWw6ICdDYXRlZ29yaWNhbCcsIGlkOiBDQVRFR09SSUNBTF9DT0xPUk1BUF9JRH07XG4gIH1cbiAgcmV0dXJuIGNhdGVnb3JpY2FsSXRlbTtcbn1cblxuLyoqXG4gKiBDaGVjayBpZiBkYXRhIHNvdXJjZSBnbG9iYWwgcGl4ZWwgY29sb3IgcmFuZ2UgaXMgY2FsY3VsYXRlZCBjb3JyZWN0bHlcbiAqIEBwYXJhbSBsYXllciAtIHJhc3RlciBsYXllclxuICogQHBhcmFtIHN0YWMgLSBTVEFDIG1ldGFkYXRhIG9iamVjdFxuICogQHBhcmFtIHByZXNldCAtIHByZXNldCBuYW1lXG4gKiBAcGFyYW0gc2luZ2xlQmFuZFByZXNldE9wdGlvbnMgLSBvcHRpb25zIGZvciBzaW5nbGUgYmFuZCBwcmVzZXRcbiAqIEByZXR1cm5zIGJvb2xlYW4gdmFsdWVcbiAqL1xuZnVuY3Rpb24gaXNEYXRhU291cmNlQ29sb3JSYW5nZUF2YWlsYWJsZShcbiAgbGF5ZXI6IFJhc3RlclRpbGVMYXllcixcbiAgc3RhYzogQ29tcGxldGVTVEFDT2JqZWN0LFxuICBwcmVzZXQ6IHN0cmluZyxcbiAgc2luZ2xlQmFuZFByZXNldE9wdGlvbnM6IFByZXNldE9wdGlvblsnc2luZ2xlQmFuZCddXG4pOiBib29sZWFuIHtcbiAgbGV0IG1pblBpeGVsVmFsdWU6IG51bWJlciB8IG51bGwgPSBudWxsO1xuICBsZXQgbWF4UGl4ZWxWYWx1ZTogbnVtYmVyIHwgbnVsbCA9IG51bGw7XG4gIGNvbnN0IGRhdGFTb3VyY2VQYXJhbXM6IERhdGFTb3VyY2VQYXJhbXMgfCBudWxsID0gbGF5ZXIuZ2V0RGF0YVNvdXJjZVBhcmFtcyhzdGFjLCBwcmVzZXQsIHtcbiAgICBzaW5nbGVCYW5kOiBzaW5nbGVCYW5kUHJlc2V0T3B0aW9uc1xuICB9KTtcbiAgaWYgKGRhdGFTb3VyY2VQYXJhbXMpIHtcbiAgICBtaW5QaXhlbFZhbHVlID0gZGF0YVNvdXJjZVBhcmFtcy5taW5QaXhlbFZhbHVlO1xuICAgIG1heFBpeGVsVmFsdWUgPSBkYXRhU291cmNlUGFyYW1zLm1heFBpeGVsVmFsdWU7XG4gIH1cbiAgcmV0dXJuIG1pblBpeGVsVmFsdWUgIT09IG51bGwgJiYgbWF4UGl4ZWxWYWx1ZSAhPT0gbnVsbDtcbn1cblxuLyoqXG4gKiBVcGRhdGVzIGNvbG9yIHBhcmFtZXRlcnMgYmFzZWQgb24gYSBjaGFuZ2UgaW4gdmlzdWFsaXphdGlvbiBwcmVzZXQuXG4gKlxuICogVGhpcyBmdW5jdGlvbiBhZGp1c3RzIHRoZSBjb2xvciBwcm9jZXNzaW5nIHBhcmFtZXRlcnMgd2hlbiB0aGUgdmlzdWFsaXphdGlvblxuICogcHJlc2V0IGNoYW5nZXMsIGJhc2VkIG9uIHdoZXRoZXIgdGhlIHByZXNldCBpcyBzd2l0Y2hpbmcgdG8gb3IgZnJvbSBhXG4gKiBzaW5nbGUtYmFuZC4gRGV0ZXJtaW5lcyB3aGV0aGVyIHRvIGFwcGx5IGNvbG9yXG4gKiBlbmhhbmNlbWVudHMgb3IgcmVzZXQgcGFyYW1ldGVycyBiYXNlZCBvbiB0aGUgcHJlc2V0IHRyYW5zaXRpb24uXG4gKlxuICogQHBhcmFtIHN0YWMgQSBTVEFDIChTcGF0aW9UZW1wb3JhbCBBc3NldCBDYXRhbG9nKSBvYmplY3QgcmVwcmVzZW50aW5nIHRoZSBkYXRhc2V0LlxuICogQHBhcmFtIG5ld1ByZXNldCBUaGUgb2xkIHZpc3VhbGl6YXRpb24gcHJlc2V0IGJlaW5nIGFwcGxpZWQuXG4gKiBAcGFyYW0gbmV3UHJlc2V0IFRoZSBuZXcgdmlzdWFsaXphdGlvbiBwcmVzZXQgYmVpbmcgYXBwbGllZC5cbiAqIEByZXR1cm5zIFRoZSB1cGRhdGVkIGNvbG9yIHBhcmFtZXRlcnMgdG8gYXBwbHkuXG4gKi9cbmZ1bmN0aW9uIHVwZGF0ZUNvbG9yUGFyYW1zT25QcmVzZXRDaGFuZ2UoXG4gIHN0YWM6IENvbXBsZXRlU1RBQ09iamVjdCxcbiAgb2xkUHJlc2V0OiBzdHJpbmcsXG4gIG5ld1ByZXNldDogc3RyaW5nXG4pIHtcbiAgbGV0IGNvbG9yUGFyYW1zID0ge307XG4gIGNvbnN0IGNvbG9yT3ZlcnJpZGVzID0gREFUQV9TT1VSQ0VfQ09MT1JfREVGQVVMVFNbc3RhYy5pZF07XG4gIGlmIChjb2xvck92ZXJyaWRlcykgcmV0dXJuIGNvbG9yUGFyYW1zO1xuXG4gIGNvbnN0IGJhbmRPZkludGVyZXN0ID0gJ3NpbmdsZUJhbmQnO1xuICBpZiAob2xkUHJlc2V0ID09PSBiYW5kT2ZJbnRlcmVzdCAmJiBuZXdQcmVzZXQgIT09IGJhbmRPZkludGVyZXN0KSB7XG4gICAgLy8gZW5jaGFuY2UgY29sb3JzIGZvciBtdWx0aWJhbmQgY29tYmluYXRpb25zXG4gICAgY29sb3JQYXJhbXMgPSBjb2xvck92ZXJyaWRlcztcbiAgfSBlbHNlIGlmIChvbGRQcmVzZXQgIT09IGJhbmRPZkludGVyZXN0ICYmIG5ld1ByZXNldCA9PT0gYmFuZE9mSW50ZXJlc3QpIHtcbiAgICAvLyByZXNldCBpbWFnZSBwcm9jZXNzbmcgcGFyYW1zXG4gICAgY29sb3JQYXJhbXMgPSBSQVNURVJfQ09MT1JfUkVTRVRfUEFSQU1TO1xuICB9XG5cbiAgcmV0dXJuIGNvbG9yUGFyYW1zO1xufVxuXG50eXBlIFJhc3RlclRpbGVMYXllckNvbmZpZ3VyYXRvclByb3BzID0ge1xuICBsYXllcjogUmFzdGVyVGlsZUxheWVyO1xuICB2aXNDb25maWd1cmF0b3JQcm9wczogYW55O1xuICBkYXRhc2V0OiBLZXBsZXJEYXRhc2V0O1xufTtcblxuUmFzdGVyVGlsZUxheWVyQ29uZmlndXJhdG9yRmFjdG9yeS5kZXBzID0gW1xuICBMYXllckNvbmZpZ0dyb3VwRmFjdG9yeSxcbiAgVmlzQ29uZmlnU2xpZGVyRmFjdG9yeSxcbiAgSW5mb0hlbHBlckZhY3RvcnksXG4gIFZpc0NvbmZpZ1N3aXRjaEZhY3Rvcnlcbl07XG5cbmZ1bmN0aW9uIFJhc3RlclRpbGVMYXllckNvbmZpZ3VyYXRvckZhY3RvcnkoXG4gIExheWVyQ29uZmlnR3JvdXA6IFJldHVyblR5cGU8dHlwZW9mIExheWVyQ29uZmlnR3JvdXBGYWN0b3J5PixcbiAgVmlzQ29uZmlnU2xpZGVyOiBSZXR1cm5UeXBlPHR5cGVvZiBWaXNDb25maWdTbGlkZXJGYWN0b3J5PixcbiAgSW5mb0hlbHBlcjogUmV0dXJuVHlwZTx0eXBlb2YgSW5mb0hlbHBlckZhY3Rvcnk+LFxuICBWaXNDb25maWdTd2l0Y2g6IFJldHVyblR5cGU8dHlwZW9mIFZpc0NvbmZpZ1N3aXRjaEZhY3Rvcnk+XG4pOiBSZWFjdC5GQzxSYXN0ZXJUaWxlTGF5ZXJDb25maWd1cmF0b3JQcm9wcz4ge1xuICAvKipcbiAgICogV3JhcHBlciBhcm91bmQgY29uZmlndXJhdG9yIHRvIGNoZWNrIGZvciBkYXRhc2V0Lm1ldGFkYXRhIGJlaW5nIG51bGwvdW5kZWZpbmVkXG4gICAqL1xuICBjb25zdCBTVEFDQ2hlY2tDb25maWd1cmF0b3JXcmFwcGVyID0gKHtcbiAgICBsYXllcixcbiAgICB2aXNDb25maWd1cmF0b3JQcm9wcyxcbiAgICBkYXRhc2V0XG4gIH06IFJhc3RlclRpbGVMYXllckNvbmZpZ3VyYXRvclByb3BzKSA9PiB7XG4gICAgY29uc3Qgc3RhYyA9IGRhdGFzZXQ/Lm1ldGFkYXRhO1xuXG4gICAgLy8gSWYgbm8gZGF0YXNldCBpcyBsb2FkZWQgaW50byBLZXBsZXIsIHN0YWMgY2FuIGJlIHVuZGVmaW5lZFxuICAgIGlmICghc3RhYykge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgcmV0dXJuIChcbiAgICAgIDxSYXN0ZXJUaWxlTGF5ZXJDb25maWd1cmF0b3JcbiAgICAgICAgbGF5ZXI9e2xheWVyfVxuICAgICAgICB2aXNDb25maWd1cmF0b3JQcm9wcz17dmlzQ29uZmlndXJhdG9yUHJvcHN9XG4gICAgICAgIGRhdGFzZXQ9e2RhdGFzZXR9XG4gICAgICAvPlxuICAgICk7XG4gIH07XG5cbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNvbXBsZXhpdHlcbiAgY29uc3QgUmFzdGVyVGlsZUxheWVyQ29uZmlndXJhdG9yOiBSZWFjdC5GQzxSYXN0ZXJUaWxlTGF5ZXJDb25maWd1cmF0b3JQcm9wcz4gPSAoe1xuICAgIGxheWVyLFxuICAgIHZpc0NvbmZpZ3VyYXRvclByb3BzLFxuICAgIGRhdGFzZXRcbiAgfSkgPT4ge1xuICAgIGNvbnN0IHtcbiAgICAgIHByZXNldCxcbiAgICAgIG5vbkxpbmVhclJlc2NhbGluZyxcbiAgICAgIHVzZVNUQUNTZWFyY2hpbmcsXG4gICAgICBjb2xvclJhbmdlOiB7Y29sb3JNYXA6IGNhdGVnb3JpY2FsQ29sb3JNYXB9LFxuICAgICAgZHluYW1pY0NvbG9yLFxuICAgICAgc2luZ2xlQmFuZE5hbWVcbiAgICB9ID0gbGF5ZXIuY29uZmlnLnZpc0NvbmZpZztcblxuICAgIGNvbnN0IHN0YWMgPSBkYXRhc2V0Py5tZXRhZGF0YSBhcyBHZXRUaWxlRGF0YUN1c3RvbVByb3BzWydzdGFjJ107XG5cbiAgICBjb25zdCBhdmFpbGFibGVQcmVzZXRzID0gdXNlTWVtbygoKSA9PiBmaWx0ZXJBdmFpbGFibGVQcmVzZXRzKHN0YWMsIFBSRVNFVF9PUFRJT05TKSwgW3N0YWNdKTtcblxuICAgIGNvbnN0IHByZXNldE9wdGlvbnMgPSB1c2VNZW1vKFxuICAgICAgKCkgPT5cbiAgICAgICAgKFxuICAgICAgICAgIGxheWVyLnZpc0NvbmZpZ1NldHRpbmdzLnByZXNldC5vcHRpb25zIGFzIHVua25vd24gYXMge1xuICAgICAgICAgICAgaWQ6IHN0cmluZztcbiAgICAgICAgICAgIGxhYmVsOiBzdHJpbmc7XG4gICAgICAgICAgfVtdXG4gICAgICAgICkuZmlsdGVyKCh7aWR9KSA9PiBhdmFpbGFibGVQcmVzZXRzPy5pbmNsdWRlcyhpZCkpLFxuICAgICAgW2xheWVyLnZpc0NvbmZpZ1NldHRpbmdzLnByZXNldC5vcHRpb25zLCBhdmFpbGFibGVQcmVzZXRzXVxuICAgICk7XG4gICAgY29uc3Qgc2luZ2xlQmFuZE9wdGlvbnMgPSB1c2VNZW1vKCgpID0+IGdldEJhbmRTZWxlY3Rvck9wdGlvbnMoc3RhYyksIFtzdGFjXSk7XG4gICAgY29uc3QgY29sb3JtYXBPcHRpb25zID0gdXNlTWVtbygoKSA9PiB7XG4gICAgICBjb25zdCBvcHRpb25zID0gW1xuICAgICAgICAuLi4obGF5ZXIudmlzQ29uZmlnU2V0dGluZ3MuY29sb3JtYXBJZC5vcHRpb25zIGFzIHVua25vd24gYXMge1xuICAgICAgICAgIGlkOiBzdHJpbmc7XG4gICAgICAgICAgbGFiZWw6IHN0cmluZztcbiAgICAgICAgfVtdKVxuICAgICAgXTtcbiAgICAgIGNvbnN0IGNhdGVnb3JpY2FsTGlzdEl0ZW0gPSBnZXRDYXRlZ29yaWNhbENvbG9ybWFwTGlzdEl0ZW0oY2F0ZWdvcmljYWxDb2xvck1hcCk7XG4gICAgICBpZiAoY2F0ZWdvcmljYWxMaXN0SXRlbSkge1xuICAgICAgICBvcHRpb25zLnB1c2goY2F0ZWdvcmljYWxMaXN0SXRlbSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gb3B0aW9ucztcbiAgICB9LCBbbGF5ZXIudmlzQ29uZmlnU2V0dGluZ3MuY29sb3JtYXBJZC5vcHRpb25zLCBjYXRlZ29yaWNhbENvbG9yTWFwXSk7XG5cbiAgICBjb25zdCB7YmFuZENvbWJpbmF0aW9ufSA9IFBSRVNFVF9PUFRJT05TW3ByZXNldF0gfHwge307XG4gICAgY29uc3QgY29sb3JtYXBBbGxvd2VkID0gaXNDb2xvcm1hcEFsbG93ZWQoYmFuZENvbWJpbmF0aW9uKTtcbiAgICBjb25zdCByZXNjYWxpbmdBbGxvd2VkID0gIWNhdGVnb3JpY2FsQ29sb3JNYXAgJiYgaXNSZXNjYWxpbmdBbGxvd2VkKGJhbmRDb21iaW5hdGlvbik7XG4gICAgY29uc3QgZmlsdGVyQWxsb3dlZCA9IGlzRmlsdGVyQWxsb3dlZChiYW5kQ29tYmluYXRpb24pO1xuXG4gICAgLy8gSGVyZSB3ZSBzaG93IHRoZSBVSSB3aGVuIHVzZVNUQUNTZWFyY2hpbmcgaXMgZXhwbGljaXRseSBzZXQgdG8gdHJ1ZSBzbyB0aGF0IHRoZSBVSSBzaG93cyB1cFxuICAgIGNvbnN0IHN0YWNTZWFyY2hBbGxvd2VkID0gaXNTZWFyY2hhYmxlU3RhYyhzdGFjKSB8fCB1c2VTVEFDU2VhcmNoaW5nO1xuXG4gICAgY29uc3Qgc2VsZWN0ZWRDb2xvcm1hcCA9XG4gICAgICBmaW5kVmlzQ29uZmlnSXRlbUJ5SWQobGF5ZXIsICdjb2xvcm1hcElkJykgfHxcbiAgICAgIGdldENhdGVnb3JpY2FsQ29sb3JtYXBMaXN0SXRlbShjYXRlZ29yaWNhbENvbG9yTWFwKTtcbiAgICBjb25zdCBzZWxlY3RlZFByZXNldCA9IGZpbmRWaXNDb25maWdJdGVtQnlJZChsYXllciwgJ3ByZXNldCcpO1xuICAgIGNvbnN0IHNlbGVjdGVkU2luZ2xlQmFuZE5hbWUgPSBmaW5kSXRlbUJ5SWQobGF5ZXIsIHNpbmdsZUJhbmRPcHRpb25zLCAnc2luZ2xlQmFuZE5hbWUnKTtcblxuICAgIGNvbnN0IHNpbmdsZUJhbmRQcmVzZXRPcHRpb25zID0gZ2V0U2luZ2xlQmFuZFByZXNldE9wdGlvbnMoc3RhYywgc2luZ2xlQmFuZE5hbWUpO1xuICAgIGNvbnN0IFttaW5DYXRlZ29yaWNhbEJhbmRWYWx1ZSwgbWF4Q2F0ZWdvcmljYWxCYW5kVmFsdWVdID0gZ2V0UmFzdGVyU3RhdGlzdGljc01pbk1heChcbiAgICAgIHN0YWMsXG4gICAgICBwcmVzZXQsXG4gICAgICBzaW5nbGVCYW5kUHJlc2V0T3B0aW9uc1xuICAgICk7XG4gICAgY29uc3QgQ29sb3JNYXBMaXN0SXRlbSA9IHVzZU1lbW8oXG4gICAgICAoKSA9PlxuICAgICAgICBnZXRDb2xvck1hcExpc3RJdGVtQ29tcG9uZW50KHtcbiAgICAgICAgICBjb2xvck1hcDogY2F0ZWdvcmljYWxDb2xvck1hcCxcbiAgICAgICAgICBtaW5WYWx1ZTogbWluQ2F0ZWdvcmljYWxCYW5kVmFsdWUsXG4gICAgICAgICAgbWF4VmFsdWU6IG1heENhdGVnb3JpY2FsQmFuZFZhbHVlXG4gICAgICAgIH0pLFxuICAgICAgW2NhdGVnb3JpY2FsQ29sb3JNYXAsIG1pbkNhdGVnb3JpY2FsQmFuZFZhbHVlLCBtYXhDYXRlZ29yaWNhbEJhbmRWYWx1ZV1cbiAgICApO1xuICAgIGNvbnN0IGlzRHluYW1pY0NvbG9yc09ubHkgPSAhaXNEYXRhU291cmNlQ29sb3JSYW5nZUF2YWlsYWJsZShcbiAgICAgIGxheWVyLFxuICAgICAgc3RhYyxcbiAgICAgIHByZXNldCxcbiAgICAgIHNpbmdsZUJhbmRQcmVzZXRPcHRpb25zXG4gICAgKTtcblxuICAgIC8vIERlZmF1bHQgb2YgYGR5bmFtaWNDb2xvcmAgaXMgZmFsc2UuIFNldCBpdCB0cnVlIGlmIGl0IGlzIG5vdCBwb3NzaWJsZSB0byBnZXQgZGF0YSBzb3VyY2VcbiAgICAvLyB3aWRlIGNvbG9yIHJhbmdlXG4gICAgdXNlRWZmZWN0KCgpID0+IHtcbiAgICAgIGlmIChpc0R5bmFtaWNDb2xvcnNPbmx5ICYmICFkeW5hbWljQ29sb3IpIHtcbiAgICAgICAgdmlzQ29uZmlndXJhdG9yUHJvcHMub25DaGFuZ2Uoe2R5bmFtaWNDb2xvcjogdHJ1ZX0pO1xuICAgICAgfVxuICAgIH0sIFt2aXNDb25maWd1cmF0b3JQcm9wcywgZHluYW1pY0NvbG9yLCBpc0R5bmFtaWNDb2xvcnNPbmx5XSk7XG5cbiAgICBjb25zdCBlbGV2YXRpb25VSSA9IChcbiAgICAgIDw+XG4gICAgICAgIHtnZXRBcHBsaWNhdGlvbkNvbmZpZygpLnJhc3RlclNlcnZlclN1cHBvcnRzRWxldmF0aW9uICYmXG4gICAgICAgICAgc3RhYy5yYXN0ZXJUaWxlU2VydmVyVXJscz8ubGVuZ3RoICYmIChcbiAgICAgICAgICAgIDxMYXllckNvbmZpZ0dyb3VwXG4gICAgICAgICAgICAgIHsuLi4obGF5ZXIudmlzQ29uZmlnU2V0dGluZ3MuZW5hYmxlVGVycmFpbiB8fCB7bGFiZWw6ICdsYXllci5jb2xvcid9KX1cbiAgICAgICAgICAgICAgey4uLnZpc0NvbmZpZ3VyYXRvclByb3BzfVxuICAgICAgICAgICAgICBjb2xsYXBzaWJsZVxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICA8Q29uZmlnR3JvdXBDb2xsYXBzaWJsZUNvbnRlbnQ+XG4gICAgICAgICAgICAgICAgPFZpc0NvbmZpZ1N3aXRjaFxuICAgICAgICAgICAgICAgICAgey4uLnZpc0NvbmZpZ3VyYXRvclByb3BzfVxuICAgICAgICAgICAgICAgICAgey4uLmxheWVyLnZpc0NvbmZpZ1NldHRpbmdzLmVuYWJsZVRlcnJhaW5Ub3BWaWV3fVxuICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgIDwvQ29uZmlnR3JvdXBDb2xsYXBzaWJsZUNvbnRlbnQ+XG4gICAgICAgICAgICA8L0xheWVyQ29uZmlnR3JvdXA+XG4gICAgICAgICAgKX1cbiAgICAgIDwvPlxuICAgICk7XG5cbiAgICAvLyBGb3IgUE1UaWxlcyBpbiByYXN0ZXIgZm9ybWF0LCBvbmx5IHNob3cgb3BhY2l0eSBhbmQgdGVycmFpbiBvcHRpb25zIGZvciBub3dcbiAgICBpZiAoc3RhYy5wbXRpbGVzVHlwZSA9PT0gUE1UaWxlc1R5cGUuUkFTVEVSKSB7XG4gICAgICByZXR1cm4gKFxuICAgICAgICA8U3R5bGVkTGF5ZXJDb25maWd1cmF0b3I+XG4gICAgICAgICAgPExheWVyQ29uZmlnR3JvdXAgey4uLnZpc0NvbmZpZ3VyYXRvclByb3BzfSBsYWJlbD1cIlZpc3VhbCBTZXR0aW5nc1wiIGNvbGxhcHNpYmxlPXtmYWxzZX0+XG4gICAgICAgICAgICA8VmlzQ29uZmlnU2xpZGVyIHsuLi5sYXllci52aXNDb25maWdTZXR0aW5ncy5vcGFjaXR5fSB7Li4udmlzQ29uZmlndXJhdG9yUHJvcHN9IC8+XG4gICAgICAgICAgPC9MYXllckNvbmZpZ0dyb3VwPlxuICAgICAgICAgIHtlbGV2YXRpb25VSX1cbiAgICAgICAgPC9TdHlsZWRMYXllckNvbmZpZ3VyYXRvcj5cbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIChcbiAgICAgIDxTdHlsZWRMYXllckNvbmZpZ3VyYXRvcj5cbiAgICAgICAge2F2YWlsYWJsZVByZXNldHMgJiYgKFxuICAgICAgICAgIDxMYXllckNvbmZpZ0dyb3VwIHsuLi52aXNDb25maWd1cmF0b3JQcm9wc30gbGFiZWw9XCJJbWFnZSBTZWxlY3Rpb25cIiBjb2xsYXBzaWJsZT17ZmFsc2V9PlxuICAgICAgICAgICAgPFNpZGVQYW5lbFNlY3Rpb24+XG4gICAgICAgICAgICAgIDxQYW5lbExhYmVsV3JhcHBlcj5cbiAgICAgICAgICAgICAgICA8UGFuZWxMYWJlbD5QcmVzZXQ8L1BhbmVsTGFiZWw+XG4gICAgICAgICAgICAgICAgPEluZm9IZWxwZXJcbiAgICAgICAgICAgICAgICAgIGlkPVwicHJlc2V0XCJcbiAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uPVwiU2VsZWN0IGEgcHJlc2V0IHRvIGRlc2NyaWJlIGhvdyB0byBjb21iaW5lIHNwZWN0cmFsIGJhbmRzLlwiXG4gICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgPC9QYW5lbExhYmVsV3JhcHBlcj5cbiAgICAgICAgICAgICAgPEl0ZW1TZWxlY3RvclxuICAgICAgICAgICAgICAgIHNlbGVjdGVkSXRlbXM9e3NlbGVjdGVkUHJlc2V0fVxuICAgICAgICAgICAgICAgIG9wdGlvbnM9e3ByZXNldE9wdGlvbnN9XG4gICAgICAgICAgICAgICAgbXVsdGlTZWxlY3Q9e2ZhbHNlfVxuICAgICAgICAgICAgICAgIHNlYXJjaGFibGU9e2ZhbHNlfVxuICAgICAgICAgICAgICAgIGRpc3BsYXlPcHRpb249XCJsYWJlbFwiXG4gICAgICAgICAgICAgICAgZ2V0T3B0aW9uVmFsdWU9XCJpZFwiXG4gICAgICAgICAgICAgICAgb25DaGFuZ2U9e25ld1ByZXNldCA9PiB7XG4gICAgICAgICAgICAgICAgICBjb25zdCBvdmVycmlkZXMgPSB1cGRhdGVDb2xvclBhcmFtc09uUHJlc2V0Q2hhbmdlKFxuICAgICAgICAgICAgICAgICAgICBzdGFjLFxuICAgICAgICAgICAgICAgICAgICB2aXNDb25maWd1cmF0b3JQcm9wcy5sYXllci5jb25maWcudmlzQ29uZmlnLnByZXNldCxcbiAgICAgICAgICAgICAgICAgICAgbmV3UHJlc2V0IGFzIHN0cmluZ1xuICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgIHZpc0NvbmZpZ3VyYXRvclByb3BzLm9uQ2hhbmdlKHsuLi5vdmVycmlkZXMsIHByZXNldDogbmV3UHJlc2V0fSk7XG4gICAgICAgICAgICAgICAgfX1cbiAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAge3NlbGVjdGVkUHJlc2V0Py5kZXNjcmlwdGlvbiA/IChcbiAgICAgICAgICAgICAgICA8RGVzY3JpcHRpb25UZXh0PlxuICAgICAgICAgICAgICAgICAge3NlbGVjdGVkUHJlc2V0Py5kZXNjcmlwdGlvbn1cbiAgICAgICAgICAgICAgICAgIHtzZWxlY3RlZFByZXNldD8uaW5mb1VybCA/IChcbiAgICAgICAgICAgICAgICAgICAgPGEgdGFyZ2V0PVwiX2JsYW5rXCIgcmVsPVwibm9vcGVuZXIgbm9yZWZlcnJlclwiIGhyZWY9e3NlbGVjdGVkUHJlc2V0Py5pbmZvVXJsfT5cbiAgICAgICAgICAgICAgICAgICAgICBNb3JlIEluZm9cbiAgICAgICAgICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgICAgICAgKSA6IG51bGx9XG4gICAgICAgICAgICAgICAgPC9EZXNjcmlwdGlvblRleHQ+XG4gICAgICAgICAgICAgICkgOiBudWxsfVxuICAgICAgICAgICAgPC9TaWRlUGFuZWxTZWN0aW9uPlxuXG4gICAgICAgICAgICB7c2VsZWN0ZWRQcmVzZXQuaWQgPT09ICdzaW5nbGVCYW5kJyAmJiAoXG4gICAgICAgICAgICAgIDxTaWRlUGFuZWxTZWN0aW9uPlxuICAgICAgICAgICAgICAgIDxQYW5lbExhYmVsV3JhcHBlcj5cbiAgICAgICAgICAgICAgICAgIDxQYW5lbExhYmVsPlNpbmdsZSBCYW5kIE5hbWU8L1BhbmVsTGFiZWw+XG4gICAgICAgICAgICAgICAgICA8SW5mb0hlbHBlclxuICAgICAgICAgICAgICAgICAgICBpZD17YCR7bGF5ZXIuaWR9LXNpbmdsZS1iYW5kLW5hbWVgfVxuICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbj1cIlNlbGVjdCBhIHNpbmdsZSBiYW5kLlwiXG4gICAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgIDwvUGFuZWxMYWJlbFdyYXBwZXI+XG4gICAgICAgICAgICAgICAgPEl0ZW1TZWxlY3RvclxuICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRJdGVtcz17c2VsZWN0ZWRTaW5nbGVCYW5kTmFtZX1cbiAgICAgICAgICAgICAgICAgIG9wdGlvbnM9e3NpbmdsZUJhbmRPcHRpb25zfVxuICAgICAgICAgICAgICAgICAgbXVsdGlTZWxlY3Q9e2ZhbHNlfVxuICAgICAgICAgICAgICAgICAgc2VhcmNoYWJsZT17ZmFsc2V9XG4gICAgICAgICAgICAgICAgICBkaXNwbGF5T3B0aW9uPVwibGFiZWxcIlxuICAgICAgICAgICAgICAgICAgZ2V0T3B0aW9uVmFsdWU9XCJpZFwiXG4gICAgICAgICAgICAgICAgICBvbkNoYW5nZT17dmFsID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdmlzQ29uZmlndXJhdG9yUHJvcHMub25DaGFuZ2Uoe3NpbmdsZUJhbmROYW1lOiB2YWx9KTtcbiAgICAgICAgICAgICAgICAgIH19XG4gICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgPC9TaWRlUGFuZWxTZWN0aW9uPlxuICAgICAgICAgICAgKX1cblxuICAgICAgICAgICAge1NUQUNfU0VBUkNIX1VJX0VOQUJMRUQgJiYgc3RhY1NlYXJjaEFsbG93ZWQgJiYgKFxuICAgICAgICAgICAgICA8Q3VzdG9tVmlzQ29uZmlnU3dpdGNoXG4gICAgICAgICAgICAgICAgey4uLmxheWVyLnZpc0NvbmZpZ1NldHRpbmdzLnVzZVNUQUNTZWFyY2hpbmd9XG4gICAgICAgICAgICAgICAgey4uLnZpc0NvbmZpZ3VyYXRvclByb3BzfVxuICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgKX1cblxuICAgICAgICAgICAge1NUQUNfU0VBUkNIX1VJX0VOQUJMRUQgJiYgKFxuICAgICAgICAgICAgICA8PlxuICAgICAgICAgICAgICAgIHtzdGFjU2VhcmNoQWxsb3dlZCAmJiB1c2VTVEFDU2VhcmNoaW5nID8gKFxuICAgICAgICAgICAgICAgICAgPFNpZGVQYW5lbFNlY3Rpb24+XG4gICAgICAgICAgICAgICAgICAgIDxQYW5lbExhYmVsV3JhcHBlcj5cbiAgICAgICAgICAgICAgICAgICAgICA8UGFuZWxMYWJlbD5TVEFDIFNlYXJjaCBQcm92aWRlcjwvUGFuZWxMYWJlbD5cbiAgICAgICAgICAgICAgICAgICAgPC9QYW5lbExhYmVsV3JhcHBlcj5cbiAgICAgICAgICAgICAgICAgICAgPEl0ZW1TZWxlY3RvclxuICAgICAgICAgICAgICAgICAgICAgIHsuLi5sYXllci52aXNDb25maWdTZXR0aW5ncy5zdGFjU2VhcmNoUHJvdmlkZXJ9XG4gICAgICAgICAgICAgICAgICAgICAgc2VsZWN0ZWRJdGVtcz17ZmluZFZpc0NvbmZpZ0l0ZW1CeUlkKGxheWVyLCAnc3RhY1NlYXJjaFByb3ZpZGVyJyl9XG4gICAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJDaG9vc2Ugc2VhcmNoIHByb3ZpZGVyXCJcbiAgICAgICAgICAgICAgICAgICAgICBtdWx0aVNlbGVjdD17ZmFsc2V9XG4gICAgICAgICAgICAgICAgICAgICAgc2VhcmNoYWJsZT17ZmFsc2V9XG4gICAgICAgICAgICAgICAgICAgICAgZGlzcGxheU9wdGlvbj1cImxhYmVsXCJcbiAgICAgICAgICAgICAgICAgICAgICBnZXRPcHRpb25WYWx1ZT1cImlkXCJcbiAgICAgICAgICAgICAgICAgICAgICBvbkNoYW5nZT17dmFsID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFRPRE86IGNoZWNrIHdoZW4gc3dpdGNoaW5nIGxheWVycyBzbyB0aGF0IHlvdSBkb24ndCBtaXNtYXRjaCBhbGxvd2VkIG1vc2FpY3Mgd2l0aCBsYXllcnNcbiAgICAgICAgICAgICAgICAgICAgICAgIHZpc0NvbmZpZ3VyYXRvclByb3BzLm9uQ2hhbmdlKHtzdGFjU2VhcmNoUHJvdmlkZXI6IHZhbH0pO1xuICAgICAgICAgICAgICAgICAgICAgIH19XG4gICAgICAgICAgICAgICAgICAgIC8+XG5cbiAgICAgICAgICAgICAgICAgICAgPFBhbmVsTGFiZWxXcmFwcGVyPlxuICAgICAgICAgICAgICAgICAgICAgIDxQYW5lbExhYmVsPkRhdGUgUmFuZ2U8L1BhbmVsTGFiZWw+XG4gICAgIC