UNPKG

kepler.gl

Version:

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

456 lines (443 loc) 65.5 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.pointPosResolver = exports.pointPosAccessor = exports.getValueAggrFunc = exports.getFilterDataFunc = exports["default"] = exports.aggregateRequiredColumns = void 0; var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _get2 = _interopRequireDefault(require("@babel/runtime/helpers/get")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _memoize = _interopRequireDefault(require("lodash/memoize")); var _baseLayer = _interopRequireDefault(require("./base-layer")); var _utils = require("@kepler.gl/utils"); var _constants = require("@kepler.gl/constants"); 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; } function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2["default"])(o), (0, _possibleConstructorReturn2["default"])(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2["default"])(t).constructor) : o.apply(t, e)); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } function _superPropGet(t, e, r, o) { var p = (0, _get2["default"])((0, _getPrototypeOf2["default"])(1 & o ? t.prototype : t), e, r); return 2 & o ? function (t) { return p.apply(r, t); } : p; } // SPDX-License-Identifier: MIT // Copyright contributors to the kepler.gl project var pointPosAccessor = exports.pointPosAccessor = function pointPosAccessor(_ref) { var lat = _ref.lat, lng = _ref.lng; return function (dc) { return function (d) { return [dc.valueAt(d.index, lng.fieldIdx), dc.valueAt(d.index, lat.fieldIdx)]; }; }; }; var pointPosResolver = exports.pointPosResolver = function pointPosResolver(_ref2) { var lat = _ref2.lat, lng = _ref2.lng; return "".concat(lat.fieldIdx, "-").concat(lng.fieldIdx); }; var getValueAggrFunc = exports.getValueAggrFunc = function getValueAggrFunc(getPointData) { return function (field, aggregation) { return function (points) { return field ? (0, _utils.aggregate)(points.map(function (p) { return field.valueAccessor(getPointData(p)); }), aggregation) : points.length; }; }; }; var getFilterDataFunc = exports.getFilterDataFunc = function getFilterDataFunc(filterRange, getFilterValue) { return function (pt) { return getFilterValue(pt).every(function (val, i) { return typeof val === 'number' ? val >= filterRange[i][0] && val <= filterRange[i][1] : false; }); }; }; var NON_NUMERIC_FIELD_TYPES = new Set([_constants.ALL_FIELD_TYPES.string, _constants.ALL_FIELD_TYPES["boolean"], _constants.ALL_FIELD_TYPES.date]); /** * Wrap a per-bin accessor that may return a non-numeric value (e.g. a string * from "mode" aggregation) so that it returns a stable numeric index instead. * deck.gl 9's native CPU aggregation stores results in a Float32Array which * silently converts strings to NaN — this wrapper prevents that. */ function wrapOrdinalAccessor(accessor) { var valueToIndex = new Map(); return function (points) { var value = accessor(points); if (value == null) return NaN; var key = String(value); var idx = valueToIndex.get(key); if (idx === undefined) { idx = valueToIndex.size; valueToIndex.set(key, idx); } return idx; }; } var getLayerColorRange = function getLayerColorRange(colorRange) { return colorRange.colors.map(_utils.hexToRgb); }; var aggregateRequiredColumns = exports.aggregateRequiredColumns = ['lat', 'lng']; var AggregationLayer = exports["default"] = /*#__PURE__*/function (_Layer) { function AggregationLayer(props) { var _this; (0, _classCallCheck2["default"])(this, AggregationLayer); _this = _callSuper(this, AggregationLayer, [props]); (0, _defineProperty2["default"])(_this, "getColorRange", void 0); _this.getPositionAccessor = function (dataContainer) { return pointPosAccessor(_this.config.columns)(dataContainer); }; _this.getColorRange = (0, _memoize["default"])(getLayerColorRange); // Access data of a point from aggregated bins // In deck.gl 9, aggregation layers pass original data items directly to getColorValue/getElevationValue _this.getPointData = function (pt) { return pt; }; _this.gpuFilterGetIndex = function (pt) { return _this.getPointData(pt).index; }; _this.gpuFilterGetData = function (dataContainer, data, fieldIndex) { return dataContainer.valueAt(data.index, fieldIndex); }; return _this; } (0, _inherits2["default"])(AggregationLayer, _Layer); return (0, _createClass2["default"])(AggregationLayer, [{ key: "isAggregated", get: function get() { return true; } }, { key: "requiredLayerColumns", get: function get() { return aggregateRequiredColumns; } }, { key: "columnPairs", get: function get() { return this.defaultPointColumnPairs; } }, { key: "noneLayerDataAffectingProps", get: function get() { return [].concat((0, _toConsumableArray2["default"])(_superPropGet(AggregationLayer, "noneLayerDataAffectingProps", this, 1)), ['enable3d', 'colorRange', 'colorDomain', 'sizeRange', 'sizeScale', 'sizeDomain', 'percentile', 'coverage', 'elevationPercentile', 'elevationScale', 'enableElevationZoomFactor', 'fixedHeight']); } }, { key: "visualChannels", get: function get() { return { color: { aggregation: 'colorAggregation', channelScaleType: _constants.CHANNEL_SCALES.colorAggr, defaultMeasure: 'property.pointCount', domain: 'colorDomain', field: 'colorField', key: 'color', property: 'color', range: 'colorRange', scale: 'colorScale' }, size: { aggregation: 'sizeAggregation', channelScaleType: _constants.CHANNEL_SCALES.sizeAggr, condition: function condition(config) { return config.visConfig.enable3d; }, defaultMeasure: 'property.pointCount', domain: 'sizeDomain', field: 'sizeField', key: 'size', property: 'height', range: 'sizeRange', scale: 'sizeScale' } }; } /** * Get the description of a visualChannel config * @param key * @returns */ }, { key: "getVisualChannelDescription", value: function getVisualChannelDescription(key) { var _this$visConfigSettin; var channel = this.visualChannels[key]; if (!channel) return { label: '', measure: undefined }; // e.g. label: Color, measure: Average of ETA var range = channel.range, field = channel.field, defaultMeasure = channel.defaultMeasure, aggregation = channel.aggregation; var fieldConfig = this.config[field]; var label = (_this$visConfigSettin = this.visConfigSettings[range]) === null || _this$visConfigSettin === void 0 ? void 0 : _this$visConfigSettin.label; return { label: typeof label === 'function' ? label(this.config) : label || '', measure: fieldConfig && aggregation ? "".concat(this.config.visConfig[aggregation], " of ").concat(fieldConfig.displayName || fieldConfig.name) : defaultMeasure }; } }, { key: "getHoverData", value: function getHoverData(object, dataContainer, fields) { if (!object) return object; var measure = this.config.visConfig.colorAggregation; // aggregate all fields for the hovered group var aggregatedData = fields.reduce(function (accu, field) { accu[field.name] = { measure: measure, value: (0, _utils.aggregate)(object.points, measure, function (d) { return dataContainer.valueAt(d.index, field.fieldIdx); }) }; return accu; }, {}); // return aggregated object return _objectSpread({ aggregatedData: aggregatedData }, object); } }, { key: "getFilteredItemCount", value: function getFilteredItemCount() { // gpu filter not supported return null; } /** * Aggregation layer handles visual channel aggregation inside deck.gl layer */ // eslint-disable-next-line @typescript-eslint/no-unused-vars }, { key: "updateLayerVisualChannel", value: function updateLayerVisualChannel(_ref3, channel) { var dataContainer = _ref3.dataContainer; this.validateVisualChannel(channel); } /** * Validate aggregation type on top of basic layer visual channel validation * @param channel */ }, { key: "validateVisualChannel", value: function validateVisualChannel(channel) { // field type decides aggregation type decides scale type this.validateFieldType(channel); this.validateAggregationType(channel); this.validateScale(channel); } /** * Validate aggregation type based on selected field */ }, { key: "validateAggregationType", value: function validateAggregationType(channel) { var visualChannel = this.visualChannels[channel]; var field = visualChannel.field, aggregation = visualChannel.aggregation; var aggregationOptions = this.getAggregationOptions(channel); if (!aggregation) { return; } if (!aggregationOptions.length) { // if field cannot be aggregated, set field to null this.updateLayerConfig((0, _defineProperty2["default"])({}, field, null)); } else if (!aggregationOptions.includes(this.config.visConfig[aggregation])) { // current aggregation type is not supported by this field // set aggregation to the first supported option this.updateLayerVisConfig((0, _defineProperty2["default"])({}, aggregation, aggregationOptions[0])); } else if (this.config[field] && this.config.visConfig[aggregation] === _constants.AGGREGATION_TYPES.count) { // When a field is selected but aggregation is still 'count' (carried over // from the no-field / "Count Points" state), switch to a meaningful default. // 'count' ignores the field values entirely, so keeping it would make the // field selection appear to have no effect. var meaningful = aggregationOptions.find(function (opt) { return opt !== _constants.AGGREGATION_TYPES.count; }); if (meaningful) { this.updateLayerVisConfig((0, _defineProperty2["default"])({}, aggregation, meaningful)); } } } }, { key: "getAggregationOptions", value: function getAggregationOptions(channel) { var visualChannel = this.visualChannels[channel]; var field = visualChannel.field, channelScaleType = visualChannel.channelScaleType; return Object.keys(this.config[field] ? _constants.FIELD_OPTS[this.config[field].type].scale[channelScaleType] : _constants.DEFAULT_AGGREGATION[channelScaleType]); } /** * Get scale options based on current field and aggregation type * @param channel * @returns */ }, { key: "getScaleOptions", value: function getScaleOptions(channel) { var visualChannel = this.visualChannels[channel]; var field = visualChannel.field, aggregation = visualChannel.aggregation, channelScaleType = visualChannel.channelScaleType; var aggregationType = aggregation ? this.config.visConfig[aggregation] : null; if (!aggregationType) { return []; } return this.config[field] ? // scale options based on aggregation _constants.FIELD_OPTS[this.config[field].type].scale[channelScaleType][aggregationType] : // default scale options for point count: aggregationType should be count since // LAYER_VIS_CONFIGS.aggregation.defaultValue is AGGREGATION_TYPES.average, _constants.DEFAULT_AGGREGATION[channelScaleType][_constants.AGGREGATION_TYPES.count]; } /** * Aggregation layer handles visual channel aggregation inside deck.gl layer */ }, { key: "updateLayerDomain", value: function updateLayerDomain() { return this; } }, { key: "updateLayerMeta", value: function updateLayerMeta(dataset, getPosition) { var dataContainer = dataset.dataContainer; // get bounds from points var bounds = this.getPointsBounds(dataContainer, getPosition); this.updateMeta({ bounds: bounds }); } }, { key: "calculateDataAttribute", value: function calculateDataAttribute(_ref4, getPosition) { var filteredIndex = _ref4.filteredIndex; var data = []; for (var i = 0; i < filteredIndex.length; i++) { var index = filteredIndex[i]; var pos = getPosition({ index: index }); // if doesn't have point lat or lng, do not add the point // deck.gl can't handle position = null if (pos.every(Number.isFinite)) { data.push({ index: index }); } } return data; } }, { key: "formatLayerData", value: function formatLayerData(datasets, oldLayerData) { if (this.config.dataId === null) { return {}; } var _datasets$this$config = datasets[this.config.dataId], gpuFilter = _datasets$this$config.gpuFilter, dataContainer = _datasets$this$config.dataContainer; var getPosition = this.getPositionAccessor(dataContainer); var hasFilter = Object.values(gpuFilter.filterRange).some(function (arr) { return arr.some(function (v) { return v !== 0; }); }); var getFilterValue = gpuFilter.filterValueAccessor(dataContainer)(this.gpuFilterGetIndex, this.gpuFilterGetData); var filterData = hasFilter ? getFilterDataFunc(gpuFilter.filterRange, getFilterValue) : undefined; var aggregatePoints = getValueAggrFunc(this.getPointData); var getColorValue = aggregatePoints(this.config.colorField, this.config.visConfig.colorAggregation); var getElevationValue = aggregatePoints(this.config.sizeField, this.config.visConfig.sizeAggregation); // deck.gl 9's native CPU aggregation stores getColorValue/getElevationValue // results in a Float32Array. "mode" aggregation on non-numeric fields returns // a string, which becomes NaN in Float32Array. Wrap with ordinal mapping to // convert strings to stable numeric indices. if (this.config.colorField && this.config.visConfig.colorAggregation === _constants.AGGREGATION_TYPES.mode && NON_NUMERIC_FIELD_TYPES.has(this.config.colorField.type)) { getColorValue = wrapOrdinalAccessor(getColorValue); } if (this.config.sizeField && this.config.visConfig.sizeAggregation === _constants.AGGREGATION_TYPES.mode && NON_NUMERIC_FIELD_TYPES.has(this.config.sizeField.type)) { getElevationValue = wrapOrdinalAccessor(getElevationValue); } // Wrap accessors to filter points within each bin before aggregating. // deck.gl 9's native aggregation doesn't support per-bin filtering, so we // apply gpuFilter at the accessor level to keep bin values in sync with // active cross-filters / time-filters. var getFilteredColorValue = filterData && getColorValue ? function (points) { return getColorValue(points.filter(filterData)); } : getColorValue; var getFilteredElevationValue = filterData && getElevationValue ? function (points) { return getElevationValue(points.filter(filterData)); } : getElevationValue; var _this$updateData = this.updateData(datasets, oldLayerData), data = _this$updateData.data; var result = _objectSpread(_objectSpread({ data: data, getPosition: getPosition, _filterData: filterData }, getFilteredColorValue ? { getColorValue: getFilteredColorValue } : {}), getFilteredElevationValue ? { getElevationValue: getFilteredElevationValue } : {}); return result; } }, { key: "getDefaultDeckLayerProps", value: function getDefaultDeckLayerProps(opts) { var baseProp = _superPropGet(AggregationLayer, "getDefaultDeckLayerProps", this, 3)([opts]); return _objectSpread(_objectSpread({}, baseProp), {}, { highlightColor: _constants.HIGHLIGH_COLOR_3D, // gpu data filtering is not supported in aggregation layer extensions: [], autoHighlight: this.config.visConfig.enable3d }); } }, { key: "getDefaultAggregationLayerProp", value: function getDefaultAggregationLayerProp(opts) { var gpuFilter = opts.gpuFilter, mapState = opts.mapState, _opts$layerCallbacks = opts.layerCallbacks, layerCallbacks = _opts$layerCallbacks === void 0 ? {} : _opts$layerCallbacks; var visConfig = this.config.visConfig; var eleZoomFactor = this.getElevationZoomFactor(mapState); var updateTriggers = { getColorValue: _objectSpread({ colorField: this.config.colorField, colorAggregation: this.config.visConfig.colorAggregation, colorRange: visConfig.colorRange, colorMap: visConfig.colorRange.colorMap, filterRange: gpuFilter.filterRange }, gpuFilter.filterValueUpdateTriggers), getElevationValue: _objectSpread({ sizeField: this.config.sizeField, sizeAggregation: this.config.visConfig.sizeAggregation, filterRange: gpuFilter.filterRange }, gpuFilter.filterValueUpdateTriggers) }; return _objectSpread(_objectSpread({}, this.getDefaultDeckLayerProps(opts)), {}, { coverage: visConfig.coverage, // color colorRange: this.getColorRange(visConfig.colorRange), colorMap: visConfig.colorRange.colorMap, colorScaleType: this.config.colorScale, upperPercentile: visConfig.percentile[1], lowerPercentile: visConfig.percentile[0], colorAggregation: visConfig.colorAggregation, // elevation extruded: visConfig.enable3d, elevationScale: visConfig.elevationScale * eleZoomFactor, elevationScaleType: this.config.sizeScale, elevationRange: visConfig.sizeRange, elevationFixed: visConfig.fixedHeight, elevationLowerPercentile: visConfig.elevationPercentile[0], elevationUpperPercentile: visConfig.elevationPercentile[1], // updateTriggers updateTriggers: updateTriggers, // callbacks onSetColorDomain: layerCallbacks.onSetLayerDomain }); } }]); }(_baseLayer["default"]); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbWVtb2l6ZSIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJyZXF1aXJlIiwiX2Jhc2VMYXllciIsIl91dGlscyIsIl9jb25zdGFudHMiLCJvd25LZXlzIiwiZSIsInIiLCJ0IiwiT2JqZWN0Iiwia2V5cyIsImdldE93blByb3BlcnR5U3ltYm9scyIsIm8iLCJmaWx0ZXIiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJlbnVtZXJhYmxlIiwicHVzaCIsImFwcGx5IiwiX29iamVjdFNwcmVhZCIsImFyZ3VtZW50cyIsImxlbmd0aCIsImZvckVhY2giLCJfZGVmaW5lUHJvcGVydHkyIiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9ycyIsImRlZmluZVByb3BlcnRpZXMiLCJkZWZpbmVQcm9wZXJ0eSIsIl9jYWxsU3VwZXIiLCJfZ2V0UHJvdG90eXBlT2YyIiwiX3Bvc3NpYmxlQ29uc3RydWN0b3JSZXR1cm4yIiwiX2lzTmF0aXZlUmVmbGVjdENvbnN0cnVjdCIsIlJlZmxlY3QiLCJjb25zdHJ1Y3QiLCJjb25zdHJ1Y3RvciIsIkJvb2xlYW4iLCJwcm90b3R5cGUiLCJ2YWx1ZU9mIiwiY2FsbCIsIl9zdXBlclByb3BHZXQiLCJwIiwiX2dldDIiLCJwb2ludFBvc0FjY2Vzc29yIiwiZXhwb3J0cyIsIl9yZWYiLCJsYXQiLCJsbmciLCJkYyIsImQiLCJ2YWx1ZUF0IiwiaW5kZXgiLCJmaWVsZElkeCIsInBvaW50UG9zUmVzb2x2ZXIiLCJfcmVmMiIsImNvbmNhdCIsImdldFZhbHVlQWdnckZ1bmMiLCJnZXRQb2ludERhdGEiLCJmaWVsZCIsImFnZ3JlZ2F0aW9uIiwicG9pbnRzIiwiYWdncmVnYXRlIiwibWFwIiwidmFsdWVBY2Nlc3NvciIsImdldEZpbHRlckRhdGFGdW5jIiwiZmlsdGVyUmFuZ2UiLCJnZXRGaWx0ZXJWYWx1ZSIsInB0IiwiZXZlcnkiLCJ2YWwiLCJpIiwiTk9OX05VTUVSSUNfRklFTERfVFlQRVMiLCJTZXQiLCJBTExfRklFTERfVFlQRVMiLCJzdHJpbmciLCJkYXRlIiwid3JhcE9yZGluYWxBY2Nlc3NvciIsImFjY2Vzc29yIiwidmFsdWVUb0luZGV4IiwiTWFwIiwidmFsdWUiLCJOYU4iLCJrZXkiLCJTdHJpbmciLCJpZHgiLCJnZXQiLCJ1bmRlZmluZWQiLCJzaXplIiwic2V0IiwiZ2V0TGF5ZXJDb2xvclJhbmdlIiwiY29sb3JSYW5nZSIsImNvbG9ycyIsImhleFRvUmdiIiwiYWdncmVnYXRlUmVxdWlyZWRDb2x1bW5zIiwiQWdncmVnYXRpb25MYXllciIsIl9MYXllciIsInByb3BzIiwiX3RoaXMiLCJfY2xhc3NDYWxsQ2hlY2syIiwiZ2V0UG9zaXRpb25BY2Nlc3NvciIsImRhdGFDb250YWluZXIiLCJjb25maWciLCJjb2x1bW5zIiwiZ2V0Q29sb3JSYW5nZSIsIm1lbW9pemUiLCJncHVGaWx0ZXJHZXRJbmRleCIsImdwdUZpbHRlckdldERhdGEiLCJkYXRhIiwiZmllbGRJbmRleCIsIl9pbmhlcml0czIiLCJfY3JlYXRlQ2xhc3MyIiwiZGVmYXVsdFBvaW50Q29sdW1uUGFpcnMiLCJfdG9Db25zdW1hYmxlQXJyYXkyIiwiY29sb3IiLCJjaGFubmVsU2NhbGVUeXBlIiwiQ0hBTk5FTF9TQ0FMRVMiLCJjb2xvckFnZ3IiLCJkZWZhdWx0TWVhc3VyZSIsImRvbWFpbiIsInByb3BlcnR5IiwicmFuZ2UiLCJzY2FsZSIsInNpemVBZ2dyIiwiY29uZGl0aW9uIiwidmlzQ29uZmlnIiwiZW5hYmxlM2QiLCJnZXRWaXN1YWxDaGFubmVsRGVzY3JpcHRpb24iLCJfdGhpcyR2aXNDb25maWdTZXR0aW4iLCJjaGFubmVsIiwidmlzdWFsQ2hhbm5lbHMiLCJsYWJlbCIsIm1lYXN1cmUiLCJmaWVsZENvbmZpZyIsInZpc0NvbmZpZ1NldHRpbmdzIiwiZGlzcGxheU5hbWUiLCJuYW1lIiwiZ2V0SG92ZXJEYXRhIiwib2JqZWN0IiwiZmllbGRzIiwiY29sb3JBZ2dyZWdhdGlvbiIsImFnZ3JlZ2F0ZWREYXRhIiwicmVkdWNlIiwiYWNjdSIsImdldEZpbHRlcmVkSXRlbUNvdW50IiwidXBkYXRlTGF5ZXJWaXN1YWxDaGFubmVsIiwiX3JlZjMiLCJ2YWxpZGF0ZVZpc3VhbENoYW5uZWwiLCJ2YWxpZGF0ZUZpZWxkVHlwZSIsInZhbGlkYXRlQWdncmVnYXRpb25UeXBlIiwidmFsaWRhdGVTY2FsZSIsInZpc3VhbENoYW5uZWwiLCJhZ2dyZWdhdGlvbk9wdGlvbnMiLCJnZXRBZ2dyZWdhdGlvbk9wdGlvbnMiLCJ1cGRhdGVMYXllckNvbmZpZyIsImluY2x1ZGVzIiwidXBkYXRlTGF5ZXJWaXNDb25maWciLCJBR0dSRUdBVElPTl9UWVBFUyIsImNvdW50IiwibWVhbmluZ2Z1bCIsImZpbmQiLCJvcHQiLCJGSUVMRF9PUFRTIiwidHlwZSIsIkRFRkFVTFRfQUdHUkVHQVRJT04iLCJnZXRTY2FsZU9wdGlvbnMiLCJhZ2dyZWdhdGlvblR5cGUiLCJ1cGRhdGVMYXllckRvbWFpbiIsInVwZGF0ZUxheWVyTWV0YSIsImRhdGFzZXQiLCJnZXRQb3NpdGlvbiIsImJvdW5kcyIsImdldFBvaW50c0JvdW5kcyIsInVwZGF0ZU1ldGEiLCJjYWxjdWxhdGVEYXRhQXR0cmlidXRlIiwiX3JlZjQiLCJmaWx0ZXJlZEluZGV4IiwicG9zIiwiTnVtYmVyIiwiaXNGaW5pdGUiLCJmb3JtYXRMYXllckRhdGEiLCJkYXRhc2V0cyIsIm9sZExheWVyRGF0YSIsImRhdGFJZCIsIl9kYXRhc2V0cyR0aGlzJGNvbmZpZyIsImdwdUZpbHRlciIsImhhc0ZpbHRlciIsInZhbHVlcyIsInNvbWUiLCJhcnIiLCJ2IiwiZmlsdGVyVmFsdWVBY2Nlc3NvciIsImZpbHRlckRhdGEiLCJhZ2dyZWdhdGVQb2ludHMiLCJnZXRDb2xvclZhbHVlIiwiY29sb3JGaWVsZCIsImdldEVsZXZhdGlvblZhbHVlIiwic2l6ZUZpZWxkIiwic2l6ZUFnZ3JlZ2F0aW9uIiwibW9kZSIsImhhcyIsImdldEZpbHRlcmVkQ29sb3JWYWx1ZSIsImdldEZpbHRlcmVkRWxldmF0aW9uVmFsdWUiLCJfdGhpcyR1cGRhdGVEYXRhIiwidXBkYXRlRGF0YSIsInJlc3VsdCIsIl9maWx0ZXJEYXRhIiwiZ2V0RGVmYXVsdERlY2tMYXllclByb3BzIiwib3B0cyIsImJhc2VQcm9wIiwiaGlnaGxpZ2h0Q29sb3IiLCJISUdITElHSF9DT0xPUl8zRCIsImV4dGVuc2lvbnMiLCJhdXRvSGlnaGxpZ2h0IiwiZ2V0RGVmYXVsdEFnZ3JlZ2F0aW9uTGF5ZXJQcm9wIiwibWFwU3RhdGUiLCJfb3B0cyRsYXllckNhbGxiYWNrcyIsImxheWVyQ2FsbGJhY2tzIiwiZWxlWm9vbUZhY3RvciIsImdldEVsZXZhdGlvblpvb21GYWN0b3IiLCJ1cGRhdGVUcmlnZ2VycyIsImNvbG9yTWFwIiwiZmlsdGVyVmFsdWVVcGRhdGVUcmlnZ2VycyIsImNvdmVyYWdlIiwiY29sb3JTY2FsZVR5cGUiLCJjb2xvclNjYWxlIiwidXBwZXJQZXJjZW50aWxlIiwicGVyY2VudGlsZSIsImxvd2VyUGVyY2VudGlsZSIsImV4dHJ1ZGVkIiwiZWxldmF0aW9uU2NhbGUiLCJlbGV2YXRpb25TY2FsZVR5cGUiLCJzaXplU2NhbGUiLCJlbGV2YXRpb25SYW5nZSIsInNpemVSYW5nZSIsImVsZXZhdGlvbkZpeGVkIiwiZml4ZWRIZWlnaHQiLCJlbGV2YXRpb25Mb3dlclBlcmNlbnRpbGUiLCJlbGV2YXRpb25QZXJjZW50aWxlIiwiZWxldmF0aW9uVXBwZXJQZXJjZW50aWxlIiwib25TZXRDb2xvckRvbWFpbiIsIm9uU2V0TGF5ZXJEb21haW4iLCJMYXllciJdLCJzb3VyY2VzIjpbIi4uL3NyYy9hZ2dyZWdhdGlvbi1sYXllci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogTUlUXG4vLyBDb3B5cmlnaHQgY29udHJpYnV0b3JzIHRvIHRoZSBrZXBsZXIuZ2wgcHJvamVjdFxuXG5pbXBvcnQgbWVtb2l6ZSBmcm9tICdsb2Rhc2gvbWVtb2l6ZSc7XG5pbXBvcnQgTGF5ZXIsIHtcbiAgTGF5ZXJCYXNlQ29uZmlnLFxuICBMYXllckJhc2VDb25maWdQYXJ0aWFsLFxuICBMYXllckNvbG9yQ29uZmlnLFxuICBMYXllclNpemVDb25maWcsXG4gIFZpc3VhbENoYW5uZWxEZXNjcmlwdGlvbixcbiAgVmlzdWFsQ2hhbm5lbHNcbn0gZnJvbSAnLi9iYXNlLWxheWVyJztcbmltcG9ydCB7aGV4VG9SZ2IsIGFnZ3JlZ2F0ZSwgRGF0YUNvbnRhaW5lckludGVyZmFjZX0gZnJvbSAnQGtlcGxlci5nbC91dGlscyc7XG5pbXBvcnQge1xuICBISUdITElHSF9DT0xPUl8zRCxcbiAgQ0hBTk5FTF9TQ0FMRVMsXG4gIEZJRUxEX09QVFMsXG4gIERFRkFVTFRfQUdHUkVHQVRJT04sXG4gIEFHR1JFR0FUSU9OX1RZUEVTLFxuICBBTExfRklFTERfVFlQRVNcbn0gZnJvbSAnQGtlcGxlci5nbC9jb25zdGFudHMnO1xuaW1wb3J0IHtDb2xvclJhbmdlLCBGaWVsZCwgTGF5ZXJDb2x1bW4sIE1lcmdlfSBmcm9tICdAa2VwbGVyLmdsL3R5cGVzJztcbmltcG9ydCB7S2VwbGVyVGFibGUsIERhdGFzZXRzfSBmcm9tICdAa2VwbGVyLmdsL3RhYmxlJztcblxudHlwZSBBZ2dyZWdhdGlvbkxheWVyQ29sdW1ucyA9IHtcbiAgbGF0OiBMYXllckNvbHVtbjtcbiAgbG5nOiBMYXllckNvbHVtbjtcbn07XG5cbmV4cG9ydCB0eXBlIEFnZ3JlZ2F0aW9uTGF5ZXJEYXRhID0ge1xuICBpbmRleDogbnVtYmVyO1xufTtcblxuZXhwb3J0IGNvbnN0IHBvaW50UG9zQWNjZXNzb3IgPVxuICAoe2xhdCwgbG5nfTogQWdncmVnYXRpb25MYXllckNvbHVtbnMpID0+XG4gIGRjID0+XG4gIGQgPT5cbiAgICBbZGMudmFsdWVBdChkLmluZGV4LCBsbmcuZmllbGRJZHgpLCBkYy52YWx1ZUF0KGQuaW5kZXgsIGxhdC5maWVsZElkeCldO1xuXG5leHBvcnQgY29uc3QgcG9pbnRQb3NSZXNvbHZlciA9ICh7bGF0LCBsbmd9OiBBZ2dyZWdhdGlvbkxheWVyQ29sdW1ucykgPT5cbiAgYCR7bGF0LmZpZWxkSWR4fS0ke2xuZy5maWVsZElkeH1gO1xuXG5leHBvcnQgY29uc3QgZ2V0VmFsdWVBZ2dyRnVuYyA9IGdldFBvaW50RGF0YSA9PiAoZmllbGQsIGFnZ3JlZ2F0aW9uKSA9PiBwb2ludHMgPT5cbiAgZmllbGRcbiAgICA/IGFnZ3JlZ2F0ZShcbiAgICAgICAgcG9pbnRzLm1hcChwID0+IGZpZWxkLnZhbHVlQWNjZXNzb3IoZ2V0UG9pbnREYXRhKHApKSksXG4gICAgICAgIGFnZ3JlZ2F0aW9uXG4gICAgICApXG4gICAgOiBwb2ludHMubGVuZ3RoO1xuXG5leHBvcnQgY29uc3QgZ2V0RmlsdGVyRGF0YUZ1bmMgPVxuICAoXG4gICAgZmlsdGVyUmFuZ2U6IG51bWJlcltdW10sXG4gICAgZ2V0RmlsdGVyVmFsdWU6IChkOiB1bmtub3duKSA9PiAobnVtYmVyIHwgbnVtYmVyW10pW11cbiAgKTogKChkOiB1bmtub3duKSA9PiBib29sZWFuKSA9PlxuICBwdCA9PlxuICAgIGdldEZpbHRlclZhbHVlKHB0KS5ldmVyeSgodmFsLCBpKSA9PiB7XG4gICAgICByZXR1cm4gdHlwZW9mIHZhbCA9PT0gJ251bWJlcicgPyB2YWwgPj0gZmlsdGVyUmFuZ2VbaV1bMF0gJiYgdmFsIDw9IGZpbHRlclJhbmdlW2ldWzFdIDogZmFsc2U7XG4gICAgfSk7XG5cbmNvbnN0IE5PTl9OVU1FUklDX0ZJRUxEX1RZUEVTOiBTZXQ8c3RyaW5nPiA9IG5ldyBTZXQoW1xuICBBTExfRklFTERfVFlQRVMuc3RyaW5nLFxuICBBTExfRklFTERfVFlQRVMuYm9vbGVhbixcbiAgQUxMX0ZJRUxEX1RZUEVTLmRhdGVcbl0pO1xuXG4vKipcbiAqIFdyYXAgYSBwZXItYmluIGFjY2Vzc29yIHRoYXQgbWF5IHJldHVybiBhIG5vbi1udW1lcmljIHZhbHVlIChlLmcuIGEgc3RyaW5nXG4gKiBmcm9tIFwibW9kZVwiIGFnZ3JlZ2F0aW9uKSBzbyB0aGF0IGl0IHJldHVybnMgYSBzdGFibGUgbnVtZXJpYyBpbmRleCBpbnN0ZWFkLlxuICogZGVjay5nbCA5J3MgbmF0aXZlIENQVSBhZ2dyZWdhdGlvbiBzdG9yZXMgcmVzdWx0cyBpbiBhIEZsb2F0MzJBcnJheSB3aGljaFxuICogc2lsZW50bHkgY29udmVydHMgc3RyaW5ncyB0byBOYU4g4oCUIHRoaXMgd3JhcHBlciBwcmV2ZW50cyB0aGF0LlxuICovXG5mdW5jdGlvbiB3cmFwT3JkaW5hbEFjY2Vzc29yKFxuICBhY2Nlc3NvcjogKHBvaW50czogdW5rbm93bltdKSA9PiB1bmtub3duXG4pOiAocG9pbnRzOiB1bmtub3duW10pID0+IG51bWJlciB7XG4gIGNvbnN0IHZhbHVlVG9JbmRleCA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCk7XG4gIHJldHVybiAocG9pbnRzOiB1bmtub3duW10pID0+IHtcbiAgICBjb25zdCB2YWx1ZSA9IGFjY2Vzc29yKHBvaW50cyk7XG4gICAgaWYgKHZhbHVlID09IG51bGwpIHJldHVybiBOYU47XG4gICAgY29uc3Qga2V5ID0gU3RyaW5nKHZhbHVlKTtcbiAgICBsZXQgaWR4ID0gdmFsdWVUb0luZGV4LmdldChrZXkpO1xuICAgIGlmIChpZHggPT09IHVuZGVmaW5lZCkge1xuICAgICAgaWR4ID0gdmFsdWVUb0luZGV4LnNpemU7XG4gICAgICB2YWx1ZVRvSW5kZXguc2V0KGtleSwgaWR4KTtcbiAgICB9XG4gICAgcmV0dXJuIGlkeDtcbiAgfTtcbn1cblxuY29uc3QgZ2V0TGF5ZXJDb2xvclJhbmdlID0gKGNvbG9yUmFuZ2U6IENvbG9yUmFuZ2UpID0+IGNvbG9yUmFuZ2UuY29sb3JzLm1hcChoZXhUb1JnYik7XG5cbmV4cG9ydCBjb25zdCBhZ2dyZWdhdGVSZXF1aXJlZENvbHVtbnM6IFsnbGF0JywgJ2xuZyddID0gWydsYXQnLCAnbG5nJ107XG5cbmV4cG9ydCB0eXBlIEFnZ3JlZ2F0aW9uTGF5ZXJWaXN1YWxDaGFubmVsQ29uZmlnID0gTGF5ZXJDb2xvckNvbmZpZyAmIExheWVyU2l6ZUNvbmZpZztcbmV4cG9ydCB0eXBlIEFnZ3JlZ2F0aW9uTGF5ZXJDb25maWcgPSBNZXJnZTxMYXllckJhc2VDb25maWcsIHtjb2x1bW5zOiBBZ2dyZWdhdGlvbkxheWVyQ29sdW1uc30+ICZcbiAgQWdncmVnYXRpb25MYXllclZpc3VhbENoYW5uZWxDb25maWc7XG5leHBvcnQgZGVmYXVsdCBjbGFzcyBBZ2dyZWdhdGlvbkxheWVyIGV4dGVuZHMgTGF5ZXIge1xuICBnZXRDb2xvclJhbmdlOiBhbnk7XG4gIGRlY2xhcmUgY29uZmlnOiBBZ2dyZWdhdGlvbkxheWVyQ29uZmlnO1xuICBkZWNsYXJlIGdldFBvaW50RGF0YTogKGFueSkgPT4gYW55O1xuICBkZWNsYXJlIGdwdUZpbHRlckdldEluZGV4OiAoYW55KSA9PiBudW1iZXI7XG4gIGRlY2xhcmUgZ3B1RmlsdGVyR2V0RGF0YTogKGRhdGFDb250YWluZXIsIGRhdGEsIGZpZWxkSW5kZXgpID0+IGFueTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcm9wczoge1xuICAgICAgaWQ/OiBzdHJpbmc7XG4gICAgfSAmIExheWVyQmFzZUNvbmZpZ1BhcnRpYWxcbiAgKSB7XG4gICAgc3VwZXIocHJvcHMpO1xuXG4gICAgdGhpcy5nZXRQb3NpdGlvbkFjY2Vzc29yID0gZGF0YUNvbnRhaW5lciA9PlxuICAgICAgcG9pbnRQb3NBY2Nlc3Nvcih0aGlzLmNvbmZpZy5jb2x1bW5zKShkYXRhQ29udGFpbmVyKTtcbiAgICB0aGlzLmdldENvbG9yUmFuZ2UgPSBtZW1vaXplKGdldExheWVyQ29sb3JSYW5nZSk7XG5cbiAgICAvLyBBY2Nlc3MgZGF0YSBvZiBhIHBvaW50IGZyb20gYWdncmVnYXRlZCBiaW5zXG4gICAgLy8gSW4gZGVjay5nbCA5LCBhZ2dyZWdhdGlvbiBsYXllcnMgcGFzcyBvcmlnaW5hbCBkYXRhIGl0ZW1zIGRpcmVjdGx5IHRvIGdldENvbG9yVmFsdWUvZ2V0RWxldmF0aW9uVmFsdWVcbiAgICB0aGlzLmdldFBvaW50RGF0YSA9IHB0ID0+IHB0O1xuXG4gICAgdGhpcy5ncHVGaWx0ZXJHZXRJbmRleCA9IHB0ID0+IHRoaXMuZ2V0UG9pbnREYXRhKHB0KS5pbmRleDtcbiAgICB0aGlzLmdwdUZpbHRlckdldERhdGEgPSAoZGF0YUNvbnRhaW5lciwgZGF0YSwgZmllbGRJbmRleCkgPT5cbiAgICAgIGRhdGFDb250YWluZXIudmFsdWVBdChkYXRhLmluZGV4LCBmaWVsZEluZGV4KTtcbiAgfVxuXG4gIGdldCBpc0FnZ3JlZ2F0ZWQoKTogdHJ1ZSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBnZXQgcmVxdWlyZWRMYXllckNvbHVtbnMoKSB7XG4gICAgcmV0dXJuIGFnZ3JlZ2F0ZVJlcXVpcmVkQ29sdW1ucztcbiAgfVxuXG4gIGdldCBjb2x1bW5QYWlycygpIHtcbiAgICByZXR1cm4gdGhpcy5kZWZhdWx0UG9pbnRDb2x1bW5QYWlycztcbiAgfVxuXG4gIGdldCBub25lTGF5ZXJEYXRhQWZmZWN0aW5nUHJvcHMoKSB7XG4gICAgcmV0dXJuIFtcbiAgICAgIC4uLnN1cGVyLm5vbmVMYXllckRhdGFBZmZlY3RpbmdQcm9wcyxcbiAgICAgICdlbmFibGUzZCcsXG4gICAgICAnY29sb3JSYW5nZScsXG4gICAgICAnY29sb3JEb21haW4nLFxuICAgICAgJ3NpemVSYW5nZScsXG4gICAgICAnc2l6ZVNjYWxlJyxcbiAgICAgICdzaXplRG9tYWluJyxcbiAgICAgICdwZXJjZW50aWxlJyxcbiAgICAgICdjb3ZlcmFnZScsXG4gICAgICAnZWxldmF0aW9uUGVyY2VudGlsZScsXG4gICAgICAnZWxldmF0aW9uU2NhbGUnLFxuICAgICAgJ2VuYWJsZUVsZXZhdGlvblpvb21GYWN0b3InLFxuICAgICAgJ2ZpeGVkSGVpZ2h0J1xuICAgIF07XG4gIH1cblxuICBnZXQgdmlzdWFsQ2hhbm5lbHMoKTogVmlzdWFsQ2hhbm5lbHMge1xuICAgIHJldHVybiB7XG4gICAgICBjb2xvcjoge1xuICAgICAgICBhZ2dyZWdhdGlvbjogJ2NvbG9yQWdncmVnYXRpb24nLFxuICAgICAgICBjaGFubmVsU2NhbGVUeXBlOiBDSEFOTkVMX1NDQUxFUy5jb2xvckFnZ3IsXG4gICAgICAgIGRlZmF1bHRNZWFzdXJlOiAncHJvcGVydHkucG9pbnRDb3VudCcsXG4gICAgICAgIGRvbWFpbjogJ2NvbG9yRG9tYWluJyxcbiAgICAgICAgZmllbGQ6ICdjb2xvckZpZWxkJyxcbiAgICAgICAga2V5OiAnY29sb3InLFxuICAgICAgICBwcm9wZXJ0eTogJ2NvbG9yJyxcbiAgICAgICAgcmFuZ2U6ICdjb2xvclJhbmdlJyxcbiAgICAgICAgc2NhbGU6ICdjb2xvclNjYWxlJ1xuICAgICAgfSxcbiAgICAgIHNpemU6IHtcbiAgICAgICAgYWdncmVnYXRpb246ICdzaXplQWdncmVnYXRpb24nLFxuICAgICAgICBjaGFubmVsU2NhbGVUeXBlOiBDSEFOTkVMX1NDQUxFUy5zaXplQWdncixcbiAgICAgICAgY29uZGl0aW9uOiBjb25maWcgPT4gY29uZmlnLnZpc0NvbmZpZy5lbmFibGUzZCxcbiAgICAgICAgZGVmYXVsdE1lYXN1cmU6ICdwcm9wZXJ0eS5wb2ludENvdW50JyxcbiAgICAgICAgZG9tYWluOiAnc2l6ZURvbWFpbicsXG4gICAgICAgIGZpZWxkOiAnc2l6ZUZpZWxkJyxcbiAgICAgICAga2V5OiAnc2l6ZScsXG4gICAgICAgIHByb3BlcnR5OiAnaGVpZ2h0JyxcbiAgICAgICAgcmFuZ2U6ICdzaXplUmFuZ2UnLFxuICAgICAgICBzY2FsZTogJ3NpemVTY2FsZSdcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgZGVzY3JpcHRpb24gb2YgYSB2aXN1YWxDaGFubmVsIGNvbmZpZ1xuICAgKiBAcGFyYW0ga2V5XG4gICAqIEByZXR1cm5zXG4gICAqL1xuICBnZXRWaXN1YWxDaGFubmVsRGVzY3JpcHRpb24oa2V5OiBzdHJpbmcpOiBWaXN1YWxDaGFubmVsRGVzY3JpcHRpb24ge1xuICAgIGNvbnN0IGNoYW5uZWwgPSB0aGlzLnZpc3VhbENoYW5uZWxzW2tleV07XG4gICAgaWYgKCFjaGFubmVsKSByZXR1cm4ge2xhYmVsOiAnJywgbWVhc3VyZTogdW5kZWZpbmVkfTtcbiAgICAvLyBlLmcuIGxhYmVsOiBDb2xvciwgbWVhc3VyZTogQXZlcmFnZSBvZiBFVEFcbiAgICBjb25zdCB7cmFuZ2UsIGZpZWxkLCBkZWZhdWx0TWVhc3VyZSwgYWdncmVnYXRpb259ID0gY2hhbm5lbDtcbiAgICBjb25zdCBmaWVsZENvbmZpZyA9IHRoaXMuY29uZmlnW2ZpZWxkXTtcbiAgICBjb25zdCBsYWJlbCA9IHRoaXMudmlzQ29uZmlnU2V0dGluZ3NbcmFuZ2VdPy5sYWJlbDtcblxuICAgIHJldHVybiB7XG4gICAgICBsYWJlbDogdHlwZW9mIGxhYmVsID09PSAnZnVuY3Rpb24nID8gbGFiZWwodGhpcy5jb25maWcpIDogbGFiZWwgfHwgJycsXG4gICAgICBtZWFzdXJlOlxuICAgICAgICBmaWVsZENvbmZpZyAmJiBhZ2dyZWdhdGlvblxuICAgICAgICAgID8gYCR7dGhpcy5jb25maWcudmlzQ29uZmlnW2FnZ3JlZ2F0aW9uXX0gb2YgJHtcbiAgICAgICAgICAgICAgZmllbGRDb25maWcuZGlzcGxheU5hbWUgfHwgZmllbGRDb25maWcubmFtZVxuICAgICAgICAgICAgfWBcbiAgICAgICAgICA6IGRlZmF1bHRNZWFzdXJlXG4gICAgfTtcbiAgfVxuXG4gIGdldEhvdmVyRGF0YShvYmplY3Q6IGFueSwgZGF0YUNvbnRhaW5lcjogRGF0YUNvbnRhaW5lckludGVyZmFjZSwgZmllbGRzOiBGaWVsZFtdKTogYW55IHtcbiAgICBpZiAoIW9iamVjdCkgcmV0dXJuIG9iamVjdDtcbiAgICBjb25zdCBtZWFzdXJlID0gdGhpcy5jb25maWcudmlzQ29uZmlnLmNvbG9yQWdncmVnYXRpb247XG4gICAgLy8gYWdncmVnYXRlIGFsbCBmaWVsZHMgZm9yIHRoZSBob3ZlcmVkIGdyb3VwXG4gICAgY29uc3QgYWdncmVnYXRlZERhdGEgPSBmaWVsZHMucmVkdWNlKChhY2N1LCBmaWVsZCkgPT4ge1xuICAgICAgYWNjdVtmaWVsZC5uYW1lXSA9IHtcbiAgICAgICAgbWVhc3VyZSxcbiAgICAgICAgdmFsdWU6IGFnZ3JlZ2F0ZShvYmplY3QucG9pbnRzLCBtZWFzdXJlLCAoZDoge2luZGV4OiBudW1iZXJ9KSA9PiB7XG4gICAgICAgICAgcmV0dXJuIGRhdGFDb250YWluZXIudmFsdWVBdChkLmluZGV4LCBmaWVsZC5maWVsZElkeCk7XG4gICAgICAgIH0pXG4gICAgICB9O1xuICAgICAgcmV0dXJuIGFjY3U7XG4gICAgfSwge30pO1xuXG4gICAgLy8gcmV0dXJuIGFnZ3JlZ2F0ZWQgb2JqZWN0XG4gICAgcmV0dXJuIHthZ2dyZWdhdGVkRGF0YSwgLi4ub2JqZWN0fTtcbiAgfVxuXG4gIGdldEZpbHRlcmVkSXRlbUNvdW50KCkge1xuICAgIC8vIGdwdSBmaWx0ZXIgbm90IHN1cHBvcnRlZFxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIEFnZ3JlZ2F0aW9uIGxheWVyIGhhbmRsZXMgdmlzdWFsIGNoYW5uZWwgYWdncmVnYXRpb24gaW5zaWRlIGRlY2suZ2wgbGF5ZXJcbiAgICovXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgdXBkYXRlTGF5ZXJWaXN1YWxDaGFubmVsKHtkYXRhQ29udGFpbmVyfSwgY2hhbm5lbCkge1xuICAgIHRoaXMudmFsaWRhdGVWaXN1YWxDaGFubmVsKGNoYW5uZWwpO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGFnZ3JlZ2F0aW9uIHR5cGUgb24gdG9wIG9mIGJhc2ljIGxheWVyIHZpc3VhbCBjaGFubmVsIHZhbGlkYXRpb25cbiAgICogQHBhcmFtIGNoYW5uZWxcbiAgICovXG4gIHZhbGlkYXRlVmlzdWFsQ2hhbm5lbChjaGFubmVsKSB7XG4gICAgLy8gZmllbGQgdHlwZSBkZWNpZGVzIGFnZ3JlZ2F0aW9uIHR5cGUgZGVjaWRlcyBzY2FsZSB0eXBlXG4gICAgdGhpcy52YWxpZGF0ZUZpZWxkVHlwZShjaGFubmVsKTtcbiAgICB0aGlzLnZhbGlkYXRlQWdncmVnYXRpb25UeXBlKGNoYW5uZWwpO1xuICAgIHRoaXMudmFsaWRhdGVTY2FsZShjaGFubmVsKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBhZ2dyZWdhdGlvbiB0eXBlIGJhc2VkIG9uIHNlbGVjdGVkIGZpZWxkXG4gICAqL1xuICB2YWxpZGF0ZUFnZ3JlZ2F0aW9uVHlwZShjaGFubmVsKSB7XG4gICAgY29uc3QgdmlzdWFsQ2hhbm5lbCA9IHRoaXMudmlzdWFsQ2hhbm5lbHNbY2hhbm5lbF07XG4gICAgY29uc3Qge2ZpZWxkLCBhZ2dyZWdhdGlvbn0gPSB2aXN1YWxDaGFubmVsO1xuICAgIGNvbnN0IGFnZ3JlZ2F0aW9uT3B0aW9ucyA9IHRoaXMuZ2V0QWdncmVnYXRpb25PcHRpb25zKGNoYW5uZWwpO1xuXG4gICAgaWYgKCFhZ2dyZWdhdGlvbikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICghYWdncmVnYXRpb25PcHRpb25zLmxlbmd0aCkge1xuICAgICAgLy8gaWYgZmllbGQgY2Fubm90IGJlIGFnZ3JlZ2F0ZWQsIHNldCBmaWVsZCB0byBudWxsXG4gICAgICB0aGlzLnVwZGF0ZUxheWVyQ29uZmlnKHtbZmllbGRdOiBudWxsfSk7XG4gICAgfSBlbHNlIGlmICghYWdncmVnYXRpb25PcHRpb25zLmluY2x1ZGVzKHRoaXMuY29uZmlnLnZpc0NvbmZpZ1thZ2dyZWdhdGlvbl0pKSB7XG4gICAgICAvLyBjdXJyZW50IGFnZ3JlZ2F0aW9uIHR5cGUgaXMgbm90IHN1cHBvcnRlZCBieSB0aGlzIGZpZWxkXG4gICAgICAvLyBzZXQgYWdncmVnYXRpb24gdG8gdGhlIGZpcnN0IHN1cHBvcnRlZCBvcHRpb25cbiAgICAgIHRoaXMudXBkYXRlTGF5ZXJWaXNDb25maWcoe1thZ2dyZWdhdGlvbl06IGFnZ3JlZ2F0aW9uT3B0aW9uc1swXX0pO1xuICAgIH0gZWxzZSBpZiAoXG4gICAgICB0aGlzLmNvbmZpZ1tmaWVsZF0gJiZcbiAgICAgIHRoaXMuY29uZmlnLnZpc0NvbmZpZ1thZ2dyZWdhdGlvbl0gPT09IEFHR1JFR0FUSU9OX1RZUEVTLmNvdW50XG4gICAgKSB7XG4gICAgICAvLyBXaGVuIGEgZmllbGQgaXMgc2VsZWN0ZWQgYnV0IGFnZ3JlZ2F0aW9uIGlzIHN0aWxsICdjb3VudCcgKGNhcnJpZWQgb3ZlclxuICAgICAgLy8gZnJvbSB0aGUgbm8tZmllbGQgLyBcIkNvdW50IFBvaW50c1wiIHN0YXRlKSwgc3dpdGNoIHRvIGEgbWVhbmluZ2Z1bCBkZWZhdWx0LlxuICAgICAgLy8gJ2NvdW50JyBpZ25vcmVzIHRoZSBmaWVsZCB2YWx1ZXMgZW50aXJlbHksIHNvIGtlZXBpbmcgaXQgd291bGQgbWFrZSB0aGVcbiAgICAgIC8vIGZpZWxkIHNlbGVjdGlvbiBhcHBlYXIgdG8gaGF2ZSBubyBlZmZlY3QuXG4gICAgICBjb25zdCBtZWFuaW5nZnVsID0gYWdncmVnYXRpb25PcHRpb25zLmZpbmQob3B0ID0+IG9wdCAhPT0gQUdHUkVHQVRJT05fVFlQRVMuY291bnQpO1xuICAgICAgaWYgKG1lYW5pbmdmdWwpIHtcbiAgICAgICAgdGhpcy51cGRhdGVMYXllclZpc0NvbmZpZyh7W2FnZ3JlZ2F0aW9uXTogbWVhbmluZ2Z1bH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGdldEFnZ3JlZ2F0aW9uT3B0aW9ucyhjaGFubmVsKSB7XG4gICAgY29uc3QgdmlzdWFsQ2hhbm5lbCA9IHRoaXMudmlzdWFsQ2hhbm5lbHNbY2hhbm5lbF07XG4gICAgY29uc3Qge2ZpZWxkLCBjaGFubmVsU2NhbGVUeXBlfSA9IHZpc3VhbENoYW5uZWw7XG5cbiAgICByZXR1cm4gT2JqZWN0LmtleXMoXG4gICAgICB0aGlzLmNvbmZpZ1tmaWVsZF1cbiAgICAgICAgPyBGSUVMRF9PUFRTW3RoaXMuY29uZmlnW2ZpZWxkXS50eXBlXS5zY2FsZVtjaGFubmVsU2NhbGVUeXBlXVxuICAgICAgICA6IERFRkFVTFRfQUdHUkVHQVRJT05bY2hhbm5lbFNjYWxlVHlwZV1cbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBzY2FsZSBvcHRpb25zIGJhc2VkIG9uIGN1cnJlbnQgZmllbGQgYW5kIGFnZ3JlZ2F0aW9uIHR5cGVcbiAgICogQHBhcmFtIGNoYW5uZWxcbiAgICogQHJldHVybnNcbiAgICovXG4gIGdldFNjYWxlT3B0aW9ucyhjaGFubmVsOiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gICAgY29uc3QgdmlzdWFsQ2hhbm5lbCA9IHRoaXMudmlzdWFsQ2hhbm5lbHNbY2hhbm5lbF07XG4gICAgY29uc3Qge2ZpZWxkLCBhZ2dyZWdhdGlvbiwgY2hhbm5lbFNjYWxlVHlwZX0gPSB2aXN1YWxDaGFubmVsO1xuICAgIGNvbnN0IGFnZ3JlZ2F0aW9uVHlwZSA9IGFnZ3JlZ2F0aW9uID8gdGhpcy5jb25maWcudmlzQ29uZmlnW2FnZ3JlZ2F0aW9uXSA6IG51bGw7XG5cbiAgICBpZiAoIWFnZ3JlZ2F0aW9uVHlwZSkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLmNvbmZpZ1tmaWVsZF1cbiAgICAgID8gLy8gc2NhbGUgb3B0aW9ucyBiYXNlZCBvbiBhZ2dyZWdhdGlvblxuICAgICAgICBGSUVMRF9PUFRTW3RoaXMuY29uZmlnW2ZpZWxkXS50eXBlXS5zY2FsZVtjaGFubmVsU2NhbGVUeXBlXVthZ2dyZWdhdGlvblR5cGVdXG4gICAgICA6IC8vIGRlZmF1bHQgc2NhbGUgb3B0aW9ucyBmb3IgcG9pbnQgY291bnQ6IGFnZ3JlZ2F0aW9uVHlwZSBzaG91bGQgYmUgY291bnQgc2luY2VcbiAgICAgICAgLy8gTEFZRVJfVklTX0NPTkZJR1MuYWdncmVnYXRpb24uZGVmYXVsdFZhbHVlIGlzIEFHR1JFR0FUSU9OX1RZUEVTLmF2ZXJhZ2UsXG4gICAgICAgIERFRkFVTFRfQUdHUkVHQVRJT05bY2hhbm5lbFNjYWxlVHlwZV1bQUdHUkVHQVRJT05fVFlQRVMuY291bnRdO1xuICB9XG5cbiAgLyoqXG4gICAqIEFnZ3JlZ2F0aW9uIGxheWVyIGhhbmRsZXMgdmlzdWFsIGNoYW5uZWwgYWdncmVnYXRpb24gaW5zaWRlIGRlY2suZ2wgbGF5ZXJcbiAgICovXG4gIHVwZGF0ZUxheWVyRG9tYWluKCk6IEFnZ3JlZ2F0aW9uTGF5ZXIge1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgdXBkYXRlTGF5ZXJNZXRhKGRhdGFzZXQ6IEtlcGxlclRhYmxlLCBnZXRQb3NpdGlvbikge1xuICAgIGNvbnN0IHtkYXRhQ29udGFpbmVyfSA9IGRhdGFzZXQ7XG4gICAgLy8gZ2V0IGJvdW5kcyBmcm9tIHBvaW50c1xuICAgIGNvbnN0IGJvdW5kcyA9IHRoaXMuZ2V0UG9pbnRzQm91bmRzKGRhdGFDb250YWluZXIsIGdldFBvc2l0aW9uKTtcblxuICAgIHRoaXMudXBkYXRlTWV0YSh7Ym91bmRzfSk7XG4gIH1cblxuICBjYWxjdWxhdGVEYXRhQXR0cmlidXRlKHtmaWx0ZXJlZEluZGV4fTogS2VwbGVyVGFibGUsIGdldFBvc2l0aW9uKSB7XG4gICAgY29uc3QgZGF0YTogQWdncmVnYXRpb25MYXllckRhdGFbXSA9IFtdO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBmaWx0ZXJlZEluZGV4Lmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBpbmRleCA9IGZpbHRlcmVkSW5kZXhbaV07XG4gICAgICBjb25zdCBwb3MgPSBnZXRQb3NpdGlvbih7aW5kZXh9KTtcblxuICAgICAgLy8gaWYgZG9lc24ndCBoYXZlIHBvaW50IGxhdCBvciBsbmcsIGRvIG5vdCBhZGQgdGhlIHBvaW50XG4gICAgICAvLyBkZWNrLmdsIGNhbid0IGhhbmRsZSBwb3NpdGlvbiA9IG51bGxcbiAgICAgIGlmIChwb3MuZXZlcnkoTnVtYmVyLmlzRmluaXRlKSkge1xuICAgICAgICBkYXRhLnB1c2goe1xuICAgICAgICAgIGluZGV4XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBkYXRhO1xuICB9XG5cbiAgZm9ybWF0TGF5ZXJEYXRhKGRhdGFzZXRzOiBEYXRhc2V0cywgb2xkTGF5ZXJEYXRhKSB7XG4gICAgaWYgKHRoaXMuY29uZmlnLmRhdGFJZCA9PT0gbnVsbCkge1xuICAgICAgcmV0dXJuIHt9O1xuICAgIH1cbiAgICBjb25zdCB7Z3B1RmlsdGVyLCBkYXRhQ29udGFpbmVyfSA9IGRhdGFzZXRzW3RoaXMuY29uZmlnLmRhdGFJZF07XG4gICAgY29uc3QgZ2V0UG9zaXRpb24gPSB0aGlzLmdldFBvc2l0aW9uQWNjZXNzb3IoZGF0YUNvbnRhaW5lcik7XG5cbiAgICBjb25zdCBoYXNGaWx0ZXIgPSBPYmplY3QudmFsdWVzKGdwdUZpbHRlci5maWx0ZXJSYW5nZSkuc29tZSgoYXJyOiBhbnkpID0+XG4gICAgICBhcnIuc29tZSh2ID0+IHYgIT09IDApXG4gICAgKTtcblxuICAgIGNvbnN0IGdldEZpbHRlclZhbHVlID0gZ3B1RmlsdGVyLmZpbHRlclZhbHVlQWNjZXNzb3IoZGF0YUNvbnRhaW5lcikoXG4gICAgICB0aGlzLmdwdUZpbHRlckdldEluZGV4LFxuICAgICAgdGhpcy5ncHVGaWx0ZXJHZXREYXRhXG4gICAgKTtcbiAgICBjb25zdCBmaWx0ZXJEYXRhID0gaGFzRmlsdGVyXG4gICAgICA/IGdldEZpbHRlckRhdGFGdW5jKGdwdUZpbHRlci5maWx0ZXJSYW5nZSwgZ2V0RmlsdGVyVmFsdWUpXG4gICAgICA6IHVuZGVmaW5lZDtcblxuICAgIGNvbnN0IGFnZ3JlZ2F0ZVBvaW50cyA9IGdldFZhbHVlQWdnckZ1bmModGhpcy5nZXRQb2ludERhdGEpO1xuICAgIGxldCBnZXRDb2xvclZhbHVlID0gYWdncmVnYXRlUG9pbnRzKFxuICAgICAgdGhpcy5jb25maWcuY29sb3JGaWVsZCxcbiAgICAgIHRoaXMuY29uZmlnLnZpc0NvbmZpZy5jb2xvckFnZ3JlZ2F0aW9uXG4gICAgKTtcblxuICAgIGxldCBnZXRFbGV2YXRpb25WYWx1ZSA9IGFnZ3JlZ2F0ZVBvaW50cyhcbiAgICAgIHRoaXMuY29uZmlnLnNpemVGaWVsZCxcbiAgICAgIHRoaXMuY29uZmlnLnZpc0NvbmZpZy5zaXplQWdncmVnYXRpb25cbiAgICApO1xuXG4gICAgLy8gZGVjay5nbCA5J3MgbmF0aXZlIENQVSBhZ2dyZWdhdGlvbiBzdG9yZXMgZ2V0Q29sb3JWYWx1ZS9nZXRFbGV2YXRpb25WYWx1ZVxuICAgIC8vIHJlc3VsdHMgaW4gYSBGbG9hdDMyQXJyYXkuIFwibW9kZVwiIGFnZ3JlZ2F0aW9uIG9uIG5vbi1udW1lcmljIGZpZWxkcyByZXR1cm5zXG4gICAgLy8gYSBzdHJpbmcsIHdoaWNoIGJlY29tZXMgTmFOIGluIEZsb2F0MzJBcnJheS4gV3JhcCB3aXRoIG9yZGluYWwgbWFwcGluZyB0b1xuICAgIC8vIGNvbnZlcnQgc3RyaW5ncyB0byBzdGFibGUgbnVtZXJpYyBpbmRpY2VzLlxuICAgIGlmIChcbiAgICAgIHRoaXMuY29uZmlnLmNvbG9yRmllbGQgJiZcbiAgICAgIHRoaXMuY29uZmlnLnZpc0NvbmZpZy5jb2xvckFnZ3JlZ2F0aW9uID09PSBBR0dSRUdBVElPTl9UWVBFUy5tb2RlICYmXG4gICAgICBOT05fTlVNRVJJQ19GSUVMRF9UWVBFUy5oYXModGhpcy5jb25maWcuY29sb3JGaWVsZC50eXBlKVxuICAgICkge1xuICAgICAgZ2V0Q29sb3JWYWx1ZSA9IHdyYXBPcmRpbmFsQWNjZXNzb3IoZ2V0Q29sb3JWYWx1ZSk7XG4gICAgfVxuICAgIGlmIChcbiAgICAgIHRoaXMuY29uZmlnLnNpemVGaWVsZCAmJlxuICAgICAgdGhpcy5jb25maWcudmlzQ29uZmlnLnNpemVBZ2dyZWdhdGlvbiA9PT0gQUdHUkVHQVRJT05fVFlQRVMubW9kZSAmJlxuICAgICAgTk9OX05VTUVSSUNfRklFTERfVFlQRVMuaGFzKHRoaXMuY29uZmlnLnNpemVGaWVsZC50eXBlKVxuICAgICkge1xuICAgICAgZ2V0RWxldmF0aW9uVmFsdWUgPSB3cmFwT3JkaW5hbEFjY2Vzc29yKGdldEVsZXZhdGlvblZhbHVlKTtcbiAgICB9XG5cbiAgICAvLyBXcmFwIGFjY2Vzc29ycyB0byBmaWx0ZXIgcG9pbnRzIHdpdGhpbiBlYWNoIGJpbiBiZWZvcmUgYWdncmVnYXRpbmcuXG4gICAgLy8gZGVjay5nbCA5J3MgbmF0aXZlIGFnZ3JlZ2F0aW9uIGRvZXNuJ3Qgc3VwcG9ydCBwZXItYmluIGZpbHRlcmluZywgc28gd2VcbiAgICAvLyBhcHBseSBncHVGaWx0ZXIgYXQgdGhlIGFjY2Vzc29yIGxldmVsIHRvIGtlZXAgYmluIHZhbHVlcyBpbiBzeW5jIHdpdGhcbiAgICAvLyBhY3RpdmUgY3Jvc3MtZmlsdGVycyAvIHRpbWUtZmlsdGVycy5cbiAgICBjb25zdCBnZXRGaWx0ZXJlZENvbG9yVmFsdWUgPVxuICAgICAgZmlsdGVyRGF0YSAmJiBnZXRDb2xvclZhbHVlXG4gICAgICAgID8gcG9pbnRzID0+IGdldENvbG9yVmFsdWUocG9pbnRzLmZpbHRlcihmaWx0ZXJEYXRhKSlcbiAgICAgICAgOiBnZXRDb2xvclZhbHVlO1xuICAgIGNvbnN0IGdldEZpbHRlcmVkRWxldmF0aW9uVmFsdWUgPVxuICAgICAgZmlsdGVyRGF0YSAmJiBnZXRFbGV2YXRpb25WYWx1ZVxuICAgICAgICA/IHBvaW50cyA9PiBnZXRFbGV2YXRpb25WYWx1ZShwb2ludHMuZmlsdGVyKGZpbHRlckRhdGEpKVxuICAgICAgICA6IGdldEVsZXZhdGlvblZhbHVlO1xuXG4gICAgY29uc3Qge2RhdGF9ID0gdGhpcy51cGRhdGVEYXRhKGRhdGFzZXRzLCBvbGRMYXllckRhdGEpO1xuXG4gICAgY29uc3QgcmVzdWx0ID0ge1xuICAgICAgZGF0YSxcbiAgICAgIGdldFBvc2l0aW9uLFxuICAgICAgX2ZpbHRlckRhdGE6IGZpbHRlckRhdGEsXG4gICAgICAuLi4oZ2V0RmlsdGVyZWRDb2xvclZhbHVlID8ge2dldENvbG9yVmFsdWU6IGdldEZpbHRlcmVkQ29sb3JWYWx1ZX0gOiB7fSksXG4gICAgICAuLi4oZ2V0RmlsdGVyZWRFbGV2YXRpb25WYWx1ZSA/IHtnZXRFbGV2YXRpb25WYWx1ZTogZ2V0RmlsdGVyZWRFbGV2YXRpb25WYWx1ZX0gOiB7fSlcbiAgICB9O1xuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIGdldERlZmF1bHREZWNrTGF5ZXJQcm9wcyhvcHRzKTogYW55IHtcbiAgICBjb25zdCBiYXNlUHJvcCA9IHN1cGVyLmdldERlZmF1bHREZWNrTGF5ZXJQcm9wcyhvcHRzKTtcbiAgICByZXR1cm4ge1xuICAgICAgLi4uYmFzZVByb3AsXG4gICAgICBoaWdobGlnaHRDb2xvcjogSElHSExJR0hfQ09MT1JfM0QsXG4gICAgICAvLyBncHUgZGF0YSBmaWx0ZXJpbmcgaXMgbm90IHN1cHBvcnRlZCBpbiBhZ2dyZWdhdGlvbiBsYXllclxuICAgICAgZXh0ZW5zaW9uczogW10sXG4gICAgICBhdXRvSGlnaGxpZ2h0OiB0aGlzLmNvbmZpZy52aXNDb25maWcuZW5hYmxlM2RcbiAgICB9O1xuICB9XG5cbiAgZ2V0RGVmYXVsdEFnZ3JlZ2F0aW9uTGF5ZXJQcm9wKG9wdHMpIHtcbiAgICBjb25zdCB7Z3B1RmlsdGVyLCBtYXBTdGF0ZSwgbGF5ZXJDYWxsYmFja3MgPSB7fX0gPSBvcHRzO1xuICAgIGNvbnN0IHt2aXNDb25maWd9ID0gdGhpcy5jb25maWc7XG4gICAgY29uc3QgZWxlWm9vbUZhY3RvciA9IHRoaXMuZ2V0RWxldmF0aW9uWm9vbUZhY3RvcihtYXBTdGF0ZSk7XG5cbiAgICBjb25zdCB1cGRhdGVUcmlnZ2VycyA9IHtcbiAgICAgIGdldENvbG9yVmFsdWU6IHtcbiAgICAgICAgY29sb3JGaWVsZDogdGhpcy5jb25maWcuY29sb3JGaWVsZCxcbiAgICAgICAgY29sb3JBZ2dyZWdhdGlvbjogdGhpcy5jb25maWcudmlzQ29uZmlnLmNvbG9yQWdncmVnYXRpb24sXG4gICAgICAgIGNvbG9yUmFuZ2U6IHZpc0NvbmZpZy5jb2xvclJhbmdlLFxuICAgICAgICBjb2xvck1hcDogdmlzQ29uZmlnLmNvbG9yUmFuZ2UuY29sb3JNYXAsXG4gICAgICAgIGZpbHRlclJhbmdlOiBncHVGaWx0ZXIuZmlsdGVyUmFuZ2UsXG4gICAgICAgIC4uLmdwdUZpbHRlci5maWx0ZXJWYWx1ZVVwZGF0ZVRyaWdnZXJzXG4gICAgICB9LFxuICAgICAgZ2V0RWxldmF0aW9uVmFsdWU6IHtcbiAgICAgICAgc2l6ZUZpZWxkOiB0aGlzLmNvbmZpZy5zaXplRmllbGQsXG4gICAgICAgIHNpemVBZ2dyZWdhdGlvbjogdGhpcy5jb25maWcudmlzQ29uZmlnLnNpemVBZ2dyZWdhdGlvbixcbiAgICAgICAgZmlsdGVyUmFuZ2U6IGdwdUZpbHRlci5maWx0ZXJSYW5nZSxcbiAgICAgICAgLi4uZ3B1RmlsdGVyLmZpbHRlclZhbHVlVXBkYXRlVHJpZ2dlcnNcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLnRoaXMuZ2V0RGVmYXVsdERlY2tMYXllclByb3BzKG9wdHMpLFxuICAgICAgY292ZXJhZ2U6IHZpc0NvbmZpZy5jb3ZlcmFnZSxcblxuICAgICAgLy8gY29sb3JcbiAgICAgIGNvbG9yUmFuZ2U6IHRoaXMuZ2V0Q29sb3JSYW5nZSh2aXNDb25maWcuY29sb3JSYW5nZSksXG4gICAgICBjb2xvck1hcDogdmlzQ29uZmlnLmNvbG9yUmFuZ2UuY29sb3JNYXAsXG4gICAgICBjb2xvclNjYWxlVHlwZTogdGhpcy5jb25maWcuY29sb3JTY2FsZSxcbiAgICAgIHVwcGVyUGVyY2VudGlsZTogdmlzQ29uZmlnLnBlcmNlbnRpbGVbMV0sXG4gICAgICBsb3dlclBlcmNlbnRpbGU6IHZpc0NvbmZpZy5wZXJjZW50aWxlWzBdLFxuICAgICAgY29sb3JBZ2dyZWdhdGlvbjogdmlzQ29uZmlnLmNvbG9yQWdncmVnYXRpb24sXG5cbiAgICAgIC8vIGVsZXZhdGlvblxuICAgICAgZXh0cnVkZWQ6IHZpc0NvbmZpZy5lbmFibGUzZCxcbiAgICAgIGVsZXZhdGlvblNjYWxlOiB2aXNDb25maWcuZWxldmF0aW9uU2NhbGUgKiBlbGVab29tRmFjdG9yLFxuICAgICAgZWxldmF0aW9uU2NhbGVUeXBlOiB0aGlzLmNvbmZpZy5zaXplU2NhbGUsXG4gICAgICBlbGV2YXRpb25SYW5nZTogdmlzQ29uZmlnLnNpemVSYW5nZSxcbiAgICAgIGVsZXZhdGlvbkZpeGVkOiB2aXNDb25maWcuZml4ZWRIZWlnaHQsXG5cbiAgICAgIGVsZXZhdGlvbkxvd2VyUGVyY2VudGlsZTogdmlzQ29uZmlnLmVsZXZhdGlvblBlcmNlbnRpbGVbMF0sXG4gICAgICBlbGV2YXRpb25VcHBlclBlcmNlbnRpbGU6IHZpc0NvbmZpZy5lbGV2YXRpb25QZXJjZW50aWxlWzFdLFxuXG4gICAgICAvLyB1cGRhdGVUcmlnZ2Vyc1xuICAgICAgdXBkYXRlVHJpZ2dlcnMsXG5cbiAgICAgIC8vIGNhbGxiYWNrc1xuICAgICAgb25TZXRDb2xvckRvbWFpbjogbGF5ZXJDYWxsYmFja3Mub25TZXRMYXllckRvbWFpblxuICAgIH07XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7O0FBR0EsSUFBQUEsUUFBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUMsVUFBQSxHQUFBRixzQkFBQSxDQUFBQyxPQUFBO0FBUUEsSUFBQUUsTUFBQSxHQUFBRixPQUFBO0FBQ0EsSUFBQUcsVUFBQSxHQUFBSCxPQUFBO0FBTzhCLFNBQUFJLFFBQUFDLENBQUEsRUFBQUMsQ0FBQSxRQUFBQyxDQUFBLEdBQUFDLE1BQUEsQ0FBQUMsSUFBQSxDQUFBSixDQUFBLE9BQUFHLE1BQUEsQ0FBQUUscUJBQUEsUUFBQUMsQ0FBQSxHQUFBSCxNQUFBLENBQUFFLHFCQUFBLENBQUFMLENBQUEsR0FBQUMsQ0FBQSxLQUFBSyxDQUFBLEdBQUFBLENBQUEsQ0FBQUMsTUFBQSxXQUFBTixDQUFBLFdBQUFFLE1BQUEsQ0FBQUssd0JBQUEsQ0FBQVIsQ0FBQSxFQUFBQyxDQUFBLEVBQUFRLFVBQUEsT0FBQVAsQ0FBQSxDQUFBUSxJQUFBLENBQUFDLEtBQUEsQ0FBQVQsQ0FBQSxFQUFBSSxDQUFBLFlBQUFKLENBQUE7QUFBQSxTQUFBVSxjQUFBWixDQUFBLGFBQUFDLENBQUEsTUFBQUEsQ0FBQSxHQUFBWSxTQUFBLENBQUFDLE1B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