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
JavaScript
"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/IHtnZXRFbGV2YXRpb25WYWx1ZTogZ2V0RmlsdGVyZWRFbGV2YXRpb25WYWx1ZX0gOiB7fSlcbiAgICB9O1xuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIGdldERlZmF1bHREZWNrTGF5ZXJQcm9wcyhvcHRzKTogYW55IHtcbiAgICBjb25zdCBiYXNlUHJvcCA9IHN1cGVyLmdldERlZmF1bHREZWNrTGF5ZXJQcm9wcyhvcHRzKTtcbiAgICByZXR1cm4ge1xuICAgICAgLi4uYmFzZVByb3AsXG4gICAgICBoaWdobGlnaHRDb2xvcjogSElHSExJR0hfQ09MT1JfM0QsXG4gICAgICAvLyBncHUgZGF0YSBmaWx0ZXJpbmcgaXMgbm90IHN1cHBvcnRlZCBpbiBhZ2dyZWdhdGlvbiBsYXllclxuICAgICAgZXh0ZW5zaW9uczogW10sXG4gICAgICBhdXRvSGlnaGxpZ2h0OiB0aGlzLmNvbmZpZy52aXNDb25maWcuZW5hYmxlM2RcbiAgICB9O1xuICB9XG5cbiAgZ2V0RGVmYXVsdEFnZ3JlZ2F0aW9uTGF5ZXJQcm9wKG9wdHMpIHtcbiAgICBjb25zdCB7Z3B1RmlsdGVyLCBtYXBTdGF0ZSwgbGF5ZXJDYWxsYmFja3MgPSB7fX0gPSBvcHRzO1xuICAgIGNvbnN0IHt2aXNDb25maWd9ID0gdGhpcy5jb25maWc7XG4gICAgY29uc3QgZWxlWm9vbUZhY3RvciA9IHRoaXMuZ2V0RWxldmF0aW9uWm9vbUZhY3RvcihtYXBTdGF0ZSk7XG5cbiAgICBjb25zdCB1cGRhdGVUcmlnZ2VycyA9IHtcbiAgICAgIGdldENvbG9yVmFsdWU6IHtcbiAgICAgICAgY29sb3JGaWVsZDogdGhpcy5jb25maWcuY29sb3JGaWVsZCxcbiAgICAgICAgY29sb3JBZ2dyZWdhdGlvbjogdGhpcy5jb25maWcudmlzQ29uZmlnLmNvbG9yQWdncmVnYXRpb24sXG4gICAgICAgIGNvbG9yUmFuZ2U6IHZpc0NvbmZpZy5jb2xvclJhbmdlLFxuICAgICAgICBjb2xvck1hcDogdmlzQ29uZmlnLmNvbG9yUmFuZ2UuY29sb3JNYXAsXG4gICAgICAgIGZpbHRlclJhbmdlOiBncHVGaWx0ZXIuZmlsdGVyUmFuZ2UsXG4gICAgICAgIC4uLmdwdUZpbHRlci5maWx0ZXJWYWx1ZVVwZGF0ZVRyaWdnZXJzXG4gICAgICB9LFxuICAgICAgZ2V0RWxldmF0aW9uVmFsdWU6IHtcbiAgICAgICAgc2l6ZUZpZWxkOiB0aGlzLmNvbmZpZy5zaXplRmllbGQsXG4gICAgICAgIHNpemVBZ2dyZWdhdGlvbjogdGhpcy5jb25maWcudmlzQ29uZmlnLnNpemVBZ2dyZWdhdGlvbixcbiAgICAgICAgZmlsdGVyUmFuZ2U6IGdwdUZpbHRlci5maWx0ZXJSYW5nZSxcbiAgICAgICAgLi4uZ3B1RmlsdGVyLmZpbHRlclZhbHVlVXBkYXRlVHJpZ2dlcnNcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLnRoaXMuZ2V0RGVmYXVsdERlY2tMYXllclByb3BzKG9wdHMpLFxuICAgICAgY292ZXJhZ2U6IHZpc0NvbmZpZy5jb3ZlcmFnZSxcblxuICAgICAgLy8gY29sb3JcbiAgICAgIGNvbG9yUmFuZ2U6IHRoaXMuZ2V0Q29sb3JSYW5nZSh2aXNDb25maWcuY29sb3JSYW5nZSksXG4gICAgICBjb2xvck1hcDogdmlzQ29uZmlnLmNvbG9yUmFuZ2UuY29sb3JNYXAsXG4gICAgICBjb2xvclNjYWxlVHlwZTogdGhpcy5jb25maWcuY29sb3JTY2FsZSxcbiAgICAgIHVwcGVyUGVyY2VudGlsZTogdmlzQ29uZmlnLnBlcmNlbnRpbGVbMV0sXG4gICAgICBsb3dlclBlcmNlbnRpbGU6IHZpc0NvbmZpZy5wZXJjZW50aWxlWzBdLFxuICAgICAgY29sb3JBZ2dyZWdhdGlvbjogdmlzQ29uZmlnLmNvbG9yQWdncmVnYXRpb24sXG5cbiAgICAgIC8vIGVsZXZhdGlvblxuICAgICAgZXh0cnVkZWQ6IHZpc0NvbmZpZy5lbmFibGUzZCxcbiAgICAgIGVsZXZhdGlvblNjYWxlOiB2aXNDb25maWcuZWxldmF0aW9uU2NhbGUgKiBlbGVab29tRmFjdG9yLFxuICAgICAgZWxldmF0aW9uU2NhbGVUeXBlOiB0aGlzLmNvbmZpZy5zaXplU2NhbGUsXG4gICAgICBlbGV2YXRpb25SYW5nZTogdmlzQ29uZmlnLnNpemVSYW5nZSxcbiAgICAgIGVsZXZhdGlvbkZpeGVkOiB2aXNDb25maWcuZml4ZWRIZWlnaHQsXG5cbiAgICAgIGVsZXZhdGlvbkxvd2VyUGVyY2VudGlsZTogdmlzQ29uZmlnLmVsZXZhdGlvblBlcmNlbnRpbGVbMF0sXG4gICAgICBlbGV2YXRpb25VcHBlclBlcmNlbnRpbGU6IHZpc0NvbmZpZy5lbGV2YXRpb25QZXJjZW50aWxlWzFdLFxuXG4gICAgICAvLyB1cGRhdGVUcmlnZ2Vyc1xuICAgICAgdXBkYXRlVHJpZ2dlcnMsXG5cbiAgICAgIC8vIGNhbGxiYWNrc1xuICAgICAgb25TZXRDb2xvckRvbWFpbjogbGF5ZXJDYWxsYmFja3Mub25TZXRMYXllckRvbWFpblxuICAgIH07XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7O0FBR0EsSUFBQUEsUUFBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUMsVUFBQSxHQUFBRixzQkFBQSxDQUFBQyxPQUFBO0FBUUEsSUFBQUUsTUFBQSxHQUFBRixPQUFBO0FBQ0EsSUFBQUcsVUFBQSxHQUFBSCxPQUFBO0FBTzhCLFNBQUFJLFFBQUFDLENBQUEsRUFBQUMsQ0FBQSxRQUFBQyxDQUFBLEdBQUFDLE1BQUEsQ0FBQUMsSUFBQSxDQUFBSixDQUFBLE9BQUFHLE1BQUEsQ0FBQUUscUJBQUEsUUFBQUMsQ0FBQSxHQUFBSCxNQUFBLENBQUFFLHFCQUFBLENBQUFMLENBQUEsR0FBQUMsQ0FBQSxLQUFBSyxDQUFBLEdBQUFBLENBQUEsQ0FBQUMsTUFBQSxXQUFBTixDQUFBLFdBQUFFLE1BQUEsQ0FBQUssd0JBQUEsQ0FBQVIsQ0FBQSxFQUFBQyxDQUFBLEVBQUFRLFVBQUEsT0FBQVAsQ0FBQSxDQUFBUSxJQUFBLENBQUFDLEtBQUEsQ0FBQVQsQ0FBQSxFQUFBSSxDQUFBLFlBQUFKLENBQUE7QUFBQSxTQUFBVSxjQUFBWixDQUFBLGFBQUFDLENBQUEsTUFBQUEsQ0FBQSxHQUFBWSxTQUFBLENBQUFDLE1BQUEsRUFBQWIsQ0FBQSxVQUFBQyxDQUFBLFdBQUFXLFNBQUEsQ0FBQVosQ0FBQSxJQUFBWSxTQUFBLENBQUFaLENBQUEsUUFBQUEsQ0FBQSxPQUFBRixPQUFBLENBQUFJLE1BQUEsQ0FBQUQsQ0FBQSxPQUFBYSxPQUFBLFdBQUFkLENBQUEsUUFBQWUsZ0JBQUEsYUFBQWhCLENBQUEsRUFBQUMsQ0FBQSxFQUFBQyxDQUFBLENBQUFELENBQUEsU0FBQUUsTUFBQSxDQUFBYyx5QkFBQSxHQUFBZCxNQUFBLENBQUFlLGdCQUFBLENBQUFsQixDQUFBLEVBQUFHLE1BQUEsQ0FBQWMseUJBQUEsQ0FBQWYsQ0FBQSxLQUFBSCxPQUFBLENBQUFJLE1BQUEsQ0FBQUQsQ0FBQSxHQUFBYSxPQUFBLFdBQUFkLENBQUEsSUFBQUUsTUFBQSxDQUFBZ0IsY0FBQSxDQUFBbkIsQ0FBQSxFQUFBQyxDQUFBLEVBQUFFLE1BQUEsQ0FBQUssd0JBQUEsQ0FBQU4sQ0FBQSxFQUFBRCxDQUFBLGlCQUFBRCxDQUFBO0FBQUEsU0FBQW9CLFdBQUFsQixDQUFBLEVBQUFJLENBQUEsRUFBQU4sQ0FBQSxXQUFBTSxDQUFBLE9BQUFlLGdCQUFBLGFBQUFmLENBQUEsT0FBQWdCLDJCQUFBLGFBQUFwQixDQUFBLEVBQUFxQix5QkFBQSxLQUFBQyxPQUFBLENBQUFDLFNBQUEsQ0FBQW5CLENBQUEsRUFBQU4sQ0FBQSxZQUFBcUIsZ0JBQUEsYUFBQW5CLENBQUEsRUFBQXdCLFdBQUEsSUFBQXBCLENBQUEsQ0FBQUssS0FBQSxDQUFBVCxDQUFBLEVBQUFGLENBQUE7QUFBQSxTQUFBdUIsMEJBQUEsY0FBQXJCLENBQUEsSUFBQXlCLE9BQUEsQ0FBQUMsU0FBQSxDQUFBQyxPQUFBLENBQUFDLElBQUEsQ0FBQU4sT0FBQSxDQUFBQyxTQUFBLENBQUFFLE9BQUEsaUNBQUF6QixDQUFBLGFBQUFxQix5QkFBQSxZQUFBQSwwQkFBQSxhQUFBckIsQ0FBQTtBQUFBLFNBQUE2QixjQUFBN0IsQ0FBQSxFQUFBRixDQUFBLEVBQUFDLENBQUEsRUFBQUssQ0FBQSxRQUFBMEIsQ0FBQSxPQUFBQyxLQUFBLGlCQUFBWixnQkFBQSxpQkFBQWYsQ0FBQSxHQUFBSixDQUFBLENBQUEwQixTQUFBLEdBQUExQixDQUFBLEdBQUFGLENBQUEsRUFBQUMsQ0FBQSxjQUFBSyxDQUFBLGFBQUFKLENBQUEsV0FBQThCLENBQUEsQ0FBQXJCLEtBQUEsQ0FBQVYsQ0FBQSxFQUFBQyxDQUFBLE9BQUE4QixDQUFBLElBcEI5QjtBQUNBO0FBZ0NPLElBQU1FLGdCQUFnQixHQUFBQyxPQUFBLENBQUFELGdCQUFBLEdBQzNCLFNBRFdBLGdCQUFnQkEsQ0FBQUUsSUFBQTtFQUFBLElBQ3pCQyxHQUFHLEdBQUFELElBQUEsQ0FBSEMsR0FBRztJQUFFQyxHQUFHLEdBQUFGLElBQUEsQ0FBSEUsR0FBRztFQUFBLE9BQ1YsVUFBQUMsRUFBRTtJQUFBLE9BQ0YsVUFBQUMsQ0FBQztNQUFBLE9BQ0MsQ0FBQ0QsRUFBRSxDQUFDRSxPQUFPLENBQUNELENBQUMsQ0FBQ0UsS0FBSyxFQUFFSixHQUFHLENBQUNLLFFBQVEsQ0FBQyxFQUFFSixFQUFFLENBQUNFLE9BQU8sQ0FBQ0QsQ0FBQyxDQUFDRSxLQUFLLEVBQUVMLEdBQUcsQ0FBQ00sUUFBUSxDQUFDLENBQUM7SUFBQTtFQUFBO0FBQUE7QUFFbkUsSUFBTUMsZ0JBQWdCLEdBQUFULE9BQUEsQ0FBQVMsZ0JBQUEsR0FBRyxTQUFuQkEsZ0JBQWdCQSxDQUFBQyxLQUFBO0VBQUEsSUFBS1IsR0FBRyxHQUFBUSxLQUFBLENBQUhSLEdBQUc7SUFBRUMsR0FBRyxHQUFBTyxLQUFBLENBQUhQLEdBQUc7RUFBQSxVQUFBUSxNQUFBLENBQ3JDVCxHQUFHLENBQUNNLFFBQVEsT0FBQUcsTUFBQSxDQUFJUixHQUFHLENBQUNLLFFBQVE7QUFBQSxDQUFFO0FBRTVCLElBQU1JLGdCQUFnQixHQUFBWixPQUFBLENBQUFZLGdCQUFBLEdBQUcsU0FBbkJBLGdCQUFnQkEsQ0FBR0MsWUFBWTtFQUFBLE9BQUksVUFBQ0MsS0FBSyxFQUFFQyxXQUFXO0lBQUEsT0FBSyxVQUFBQyxNQUFNO01BQUEsT0FDNUVGLEtBQUssR0FDRCxJQUFBRyxnQkFBUyxFQUNQRCxNQUFNLENBQUNFLEdBQUcsQ0FBQyxVQUFBckIsQ0FBQztRQUFBLE9BQUlpQixLQUFLLENBQUNLLGFBQWEsQ0FBQ04sWUFBWSxDQUFDaEIsQ0FBQyxDQUFDLENBQUM7TUFBQSxFQUFDLEVBQ3JEa0IsV0FDRixDQUFDLEdBQ0RDLE1BQU0sQ0FBQ3JDLE1BQU07SUFBQTtFQUFBO0FBQUE7QUFFWixJQUFNeUMsaUJBQWlCLEdBQUFwQixPQUFBLENBQUFvQixpQkFBQSxHQUM1QixTQURXQSxpQkFBaUJBLENBRTFCQyxXQUF1QixFQUN2QkMsY0FBcUQ7RUFBQSxPQUV2RCxVQUFBQyxFQUFFO0lBQUEsT0FDQUQsY0FBYyxDQUFDQyxFQUFFLENBQUMsQ0FBQ0MsS0FBSyxDQUFDLFVBQUNDLEdBQUcsRUFBRUMsQ0FBQyxFQUFLO01BQ25DLE9BQU8sT0FBT0QsR0FBRyxLQUFLLFFBQVEsR0FBR0EsR0FBRyxJQUFJSixXQUFXLENBQUNLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJRCxHQUFHLElBQUlKLFdBQVcsQ0FBQ0ssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsS0FBSztJQUMvRixDQUFDLENBQUM7RUFBQTtBQUFBO0FBRU4sSUFBTUMsdUJBQW9DLEdBQUcsSUFBSUMsR0FBRyxDQUFDLENBQ25EQywwQkFBZSxDQUFDQyxNQUFNLEVBQ3RCRCwwQkFBZSxXQUFRLEVBQ3ZCQSwwQkFBZSxDQUFDRSxJQUFJLENBQ3JCLENBQUM7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBU0MsbUJBQW1CQSxDQUMxQkMsUUFBd0MsRUFDVDtFQUMvQixJQUFNQyxZQUFZLEdBQUcsSUFBSUMsR0FB