kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
420 lines (411 loc) • 58.6 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.pointVisConfigs = exports.iconRequiredColumns = exports.iconPosAccessor = exports.iconOptionalColumns = exports.iconAccessor = exports["default"] = 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 _window = _interopRequireDefault(require("global/window"));
var _extensions = require("@deck.gl/extensions");
var _deckglLayers = require("@kepler.gl/deckgl-layers");
var _iconLayerIcon = _interopRequireDefault(require("./icon-layer-icon"));
var _constants = require("@kepler.gl/constants");
var _iconInfoModal = _interopRequireDefault(require("./icon-info-modal"));
var _baseLayer = _interopRequireDefault(require("../base-layer"));
var _layerUtils = require("../layer-utils");
var _utils = require("@kepler.gl/utils");
var _layerTextLabel = require("../layer-text-label");
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 brushingExtension = new _extensions.BrushingExtension();
var iconPosAccessor = exports.iconPosAccessor = function iconPosAccessor(_ref) {
var lat = _ref.lat,
lng = _ref.lng,
altitude = _ref.altitude;
return function (dc) {
return function (d) {
return [dc.valueAt(d.index, lng.fieldIdx), dc.valueAt(d.index, lat.fieldIdx), (altitude === null || altitude === void 0 ? void 0 : altitude.fieldIdx) > -1 ? dc.valueAt(d.index, altitude.fieldIdx) : 0];
};
};
};
var iconAccessor = exports.iconAccessor = function iconAccessor(_ref2) {
var icon = _ref2.icon;
return function (dc) {
return function (d) {
return dc.valueAt(d.index, icon.fieldIdx);
};
};
};
var iconRequiredColumns = exports.iconRequiredColumns = ['lat', 'lng', 'icon'];
var iconOptionalColumns = exports.iconOptionalColumns = ['altitude'];
var pointVisConfigs = exports.pointVisConfigs = {
radius: 'radius',
fixedRadius: 'fixedRadius',
opacity: 'opacity',
colorRange: 'colorRange',
radiusRange: 'radiusRange',
billboard: 'billboard'
};
function flatterIconPositions(icon) {
// had to flip y, since @luma modal has changed
return icon.mesh.cells.reduce(function (prev, cell) {
cell.forEach(function (p) {
prev.push.apply(prev, [icon.mesh.positions[p][0], -icon.mesh.positions[p][1], icon.mesh.positions[p][2]]);
});
return prev;
}, []);
}
var IconLayer = exports["default"] = /*#__PURE__*/function (_Layer) {
function IconLayer(props) {
var _this;
(0, _classCallCheck2["default"])(this, IconLayer);
_this = _callSuper(this, IconLayer, [props]);
(0, _defineProperty2["default"])(_this, "getIconAccessor", void 0);
(0, _defineProperty2["default"])(_this, "_layerInfoModal", void 0);
(0, _defineProperty2["default"])(_this, "iconGeometry", void 0);
(0, _defineProperty2["default"])(_this, "iconGeometryVersion", void 0);
(0, _defineProperty2["default"])(_this, "onRedrawNeeded", void 0);
_this.registerVisConfig(pointVisConfigs);
_this.getPositionAccessor = function (dataContainer) {
return iconPosAccessor(_this.config.columns)(dataContainer);
};
_this.getIconAccessor = function (dataContainer) {
return iconAccessor(_this.config.columns)(dataContainer);
};
_this._layerInfoModal = (0, _iconInfoModal["default"])(props.svgIcons);
_this.iconGeometry = props.iconGeometry || null;
_this.iconGeometryVersion = 0;
if ((0, _utils.isTest)()) {
return (0, _possibleConstructorReturn2["default"])(_this);
}
if (props.svgIcons) {
// if svg icons are passed in then bypass fetching of remote svg icons
_this.setSvgIcons(props.svgIcons);
} else {
// prepare layer info modal and fetch remote svg icons
_this.getSvgIcons();
}
return _this;
}
(0, _inherits2["default"])(IconLayer, _Layer);
return (0, _createClass2["default"])(IconLayer, [{
key: "svgIconUrl",
get: function get() {
return "".concat((0, _utils.getApplicationConfig)().cdnUrl, "/icons/svg-icons.json");
}
}, {
key: "type",
get: function get() {
return 'icon';
}
}, {
key: "requiredLayerColumns",
get: function get() {
return iconRequiredColumns;
}
}, {
key: "optionalColumns",
get: function get() {
return iconOptionalColumns;
}
}, {
key: "columnPairs",
get: function get() {
return this.defaultPointColumnPairs;
}
}, {
key: "layerIcon",
get: function get() {
return _iconLayerIcon["default"];
}
}, {
key: "visualChannels",
get: function get() {
return {
color: _objectSpread(_objectSpread({}, _superPropGet(IconLayer, "visualChannels", this, 1).color), {}, {
accessor: 'getFillColor',
defaultValue: function defaultValue(config) {
return config.color;
}
}),
size: _objectSpread(_objectSpread({}, _superPropGet(IconLayer, "visualChannels", this, 1).size), {}, {
property: 'radius',
range: 'radiusRange',
channelScaleType: 'radius',
accessor: 'getRadius',
defaultValue: 1
})
};
}
}, {
key: "layerInfoModal",
get: function get() {
return {
id: 'iconInfo',
template: this._layerInfoModal,
modalProps: {
title: 'modal.iconInfo.title'
}
};
}
}, {
key: "getZoomFactor",
value: function getZoomFactor(_ref3) {
var zoom = _ref3.zoom,
_ref3$zoomOffset = _ref3.zoomOffset,
zoomOffset = _ref3$zoomOffset === void 0 ? 0 : _ref3$zoomOffset;
return Math.pow(2, 14 - zoom + zoomOffset);
}
}, {
key: "getSvgIcons",
value: function getSvgIcons() {
var _this2 = this;
var fetchConfig = {
method: 'GET',
mode: 'cors',
cache: 'no-cache'
};
if (_window["default"].fetch && this.svgIconUrl) {
_window["default"].fetch(this.svgIconUrl, fetchConfig).then(function (response) {
if (!response.ok) {
throw new Error("Failed to load svg-icons.json: ".concat(response.status));
}
return response.json();
}).then(function () {
var parsed = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_this2.setSvgIcons(parsed.svgIcons);
})["catch"](function (err) {
console.error('Error fetching or parsing svg-icons.json:', err);
// Fallback to empty geometry to allow default icon rendering
_this2.iconGeometry = {};
_this2.iconGeometryVersion += 1;
});
} else {
// No fetch available; set empty geometry so layer can render default icons
this.iconGeometry = {};
this.iconGeometryVersion += 1;
}
}
}, {
key: "setSvgIcons",
value: function setSvgIcons() {
var _this$onRedrawNeeded;
var svgIcons = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
this.iconGeometry = svgIcons.reduce(function (accu, curr) {
return _objectSpread(_objectSpread({}, accu), {}, (0, _defineProperty2["default"])({}, curr.id, flatterIconPositions(curr)));
}, {});
// Increment version when SVG icons are loaded to trigger layer re-render
this.iconGeometryVersion += 1;
this._layerInfoModal = (0, _iconInfoModal["default"])(svgIcons);
// Trigger a map redraw so deck.gl picks up the new geometry
(_this$onRedrawNeeded = this.onRedrawNeeded) === null || _this$onRedrawNeeded === void 0 || _this$onRedrawNeeded.call(this);
}
}, {
key: "getFilteredItemCount",
value: function getFilteredItemCount() {
// use total
if (Object.keys(this.filteredItemCount).length) {
return Object.values(this.filteredItemCount).reduce(function (total, curr) {
return Number.isFinite(curr) ? total + curr : total;
}, 0);
}
return null;
}
}, {
key: "calculateDataAttribute",
value: function calculateDataAttribute(_ref4, getPosition) {
var dataContainer = _ref4.dataContainer,
filteredIndex = _ref4.filteredIndex;
var getIcon = this.getIconAccessor(dataContainer);
var data = [];
for (var i = 0; i < filteredIndex.length; i++) {
var index = filteredIndex[i];
var rowIndex = {
index: index
};
var pos = getPosition(rowIndex);
var icon = getIcon(rowIndex);
// 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) && typeof icon === 'string') {
data.push({
index: index,
icon: icon
});
}
}
return data;
}
}, {
key: "formatLayerData",
value: function formatLayerData(datasets, oldLayerData) {
if (this.config.dataId === null) {
return {};
}
var textLabel = this.config.textLabel;
var _datasets$this$config = datasets[this.config.dataId],
gpuFilter = _datasets$this$config.gpuFilter,
dataContainer = _datasets$this$config.dataContainer;
var getPosition = this.getPositionAccessor(dataContainer);
var _this$updateData = this.updateData(datasets, oldLayerData),
data = _this$updateData.data,
triggerChanged = _this$updateData.triggerChanged;
// get all distinct characters in the text labels
var textLabels = (0, _layerTextLabel.formatTextLabelData)({
textLabel: textLabel,
triggerChanged: triggerChanged,
oldLayerData: oldLayerData,
data: data,
dataContainer: dataContainer
});
var accessors = this.getAttributeAccessors({
dataContainer: dataContainer
});
return _objectSpread({
data: data,
getPosition: getPosition,
getFilterValue: gpuFilter.filterValueAccessor(dataContainer)(),
textLabels: textLabels
}, accessors);
}
}, {
key: "updateLayerMeta",
value: function updateLayerMeta(dataset, getPosition) {
var dataContainer = dataset.dataContainer;
var bounds = this.getPointsBounds(dataContainer, getPosition);
this.updateMeta({
bounds: bounds
});
}
}, {
key: "renderLayer",
value: function renderLayer(opts) {
var _this$config$columns$,
_this3 = this;
var data = opts.data,
gpuFilter = opts.gpuFilter,
objectHovered = opts.objectHovered,
mapState = opts.mapState,
interactionConfig = opts.interactionConfig,
layerCallbacks = opts.layerCallbacks;
// Store callback to trigger map redraw when icon geometry loads asynchronously
this.onRedrawNeeded = layerCallbacks === null || layerCallbacks === void 0 ? void 0 : layerCallbacks.onRedrawNeeded;
var radiusScale = this.getRadiusScaleByZoom(mapState);
var layerProps = _objectSpread({
radiusScale: radiusScale,
billboard: this.config.visConfig.billboard
}, this.config.visConfig.fixedRadius ? {} : {
radiusMaxPixels: 500
});
var updateTriggers = _objectSpread({
getPosition: this.config.columns,
getFilterValue: gpuFilter.filterValueUpdateTriggers
}, this.getVisualChannelUpdateTriggers());
var defaultLayerProps = this.getDefaultDeckLayerProps(opts);
var brushingProps = this.getBrushingExtensionProps(interactionConfig);
var getPixelOffset = (0, _layerTextLabel.getTextOffsetByRadius)(radiusScale, data.getRadius, mapState);
var extensions = [].concat((0, _toConsumableArray2["default"])(defaultLayerProps.extensions), [brushingExtension]);
// shared Props between layer and label layer
var sharedProps = _objectSpread({
getFilterValue: data.getFilterValue,
extensions: extensions,
filterRange: defaultLayerProps.filterRange
}, brushingProps);
var labelLayers = (0, _toConsumableArray2["default"])(this.renderTextLabelLayer({
getPosition: data.getPosition,
sharedProps: sharedProps,
getPixelOffset: getPixelOffset,
updateTriggers: updateTriggers
}, opts));
var hoveredObject = this.hasHoveredObject(objectHovered);
var parameters = {
// icons will be flat on the map when the altitude column is not used
depthTest: ((_this$config$columns$ = this.config.columns.altitude) === null || _this$config$columns$ === void 0 ? void 0 : _this$config$columns$.fieldIdx) > -1,
cullMode: _constants.CULL_MODE.FRONT
};
// Append geometry version to layer id so deck.gl treats it as new layer when geometry changes
var baseLayerId = defaultLayerProps.id || this.id;
var layerIdWithVersion = "".concat(baseLayerId, "_").concat(this.iconGeometryVersion);
return [new _deckglLayers.SvgIconLayer(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({}, defaultLayerProps), {}, {
id: layerIdWithVersion
}, brushingProps), layerProps), data), {}, {
parameters: parameters,
getIconGeometry: function getIconGeometry(id) {
var _this3$iconGeometry;
return (_this3$iconGeometry = _this3.iconGeometry) === null || _this3$iconGeometry === void 0 ? void 0 : _this3$iconGeometry[id];
},
// update triggers
updateTriggers: updateTriggers,
extensions: extensions
}))].concat((0, _toConsumableArray2["default"])(hoveredObject ? [new _deckglLayers.SvgIconLayer(_objectSpread(_objectSpread(_objectSpread({}, this.getDefaultHoverLayerProps()), {}, {
id: "".concat(layerIdWithVersion, "-hover")
}, layerProps), {}, {
visible: defaultLayerProps.visible,
data: [hoveredObject],
parameters: parameters,
getPosition: data.getPosition,
getRadius: data.getRadius,
getFillColor: this.config.highlightColor,
getIconGeometry: function getIconGeometry(id) {
var _this3$iconGeometry2;
return (_this3$iconGeometry2 = _this3.iconGeometry) === null || _this3$iconGeometry2 === void 0 ? void 0 : _this3$iconGeometry2[id];
}
}))] : []), (0, _toConsumableArray2["default"])(labelLayers));
}
}], [{
key: "findDefaultLayerProps",
value: function findDefaultLayerProps(_ref5) {
var _ref5$fieldPairs = _ref5.fieldPairs,
fieldPairs = _ref5$fieldPairs === void 0 ? [] : _ref5$fieldPairs,
_ref5$fields = _ref5.fields,
fields = _ref5$fields === void 0 ? [] : _ref5$fields;
var notFound = {
props: []
};
if (!fieldPairs.length || !fields.length) {
return notFound;
}
var iconFields = fields.filter(function (_ref6) {
var name = _ref6.name;
return name.replace(/[_,.]+/g, ' ').trim().split(' ').some(function (seg) {
return _constants.ICON_FIELDS.icon.some(function (t) {
return t.includes(seg);
});
});
});
if (!iconFields.length) {
return notFound;
}
// create icon layers for first point pair
var ptPair = fieldPairs[0];
var columns = (0, _layerUtils.assignPointPairToLayerColumn)(ptPair, true);
var props = iconFields.map(function (iconField) {
return {
label: iconField.name.replace(/[_,.]+/g, ' ').trim(),
columns: _objectSpread(_objectSpread({}, columns), {}, {
icon: {
value: iconField.name,
fieldIdx: iconField.fieldIdx
}
}),
isVisible: true
};
});
return {
props: props
};
}
}]);
}(_baseLayer["default"]);
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfd2luZG93IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfZXh0ZW5zaW9ucyIsIl9kZWNrZ2xMYXllcnMiLCJfaWNvbkxheWVySWNvbiIsIl9jb25zdGFudHMiLCJfaWNvbkluZm9Nb2RhbCIsIl9iYXNlTGF5ZXIiLCJfbGF5ZXJVdGlscyIsIl91dGlscyIsIl9sYXllclRleHRMYWJlbCIsIm93bktleXMiLCJlIiwiciIsInQiLCJPYmplY3QiLCJrZXlzIiwiZ2V0T3duUHJvcGVydHlTeW1ib2xzIiwibyIsImZpbHRlciIsImdldE93blByb3BlcnR5RGVzY3JpcHRvciIsImVudW1lcmFibGUiLCJwdXNoIiwiYXBwbHkiLCJfb2JqZWN0U3ByZWFkIiwiYXJndW1lbnRzIiwibGVuZ3RoIiwiZm9yRWFjaCIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzIiwiZGVmaW5lUHJvcGVydGllcyIsImRlZmluZVByb3BlcnR5IiwiX2NhbGxTdXBlciIsIl9nZXRQcm90b3R5cGVPZjIiLCJfcG9zc2libGVDb25zdHJ1Y3RvclJldHVybjIiLCJfaXNOYXRpdmVSZWZsZWN0Q29uc3RydWN0IiwiUmVmbGVjdCIsImNvbnN0cnVjdCIsImNvbnN0cnVjdG9yIiwiQm9vbGVhbiIsInByb3RvdHlwZSIsInZhbHVlT2YiLCJjYWxsIiwiX3N1cGVyUHJvcEdldCIsInAiLCJfZ2V0MiIsImJydXNoaW5nRXh0ZW5zaW9uIiwiQnJ1c2hpbmdFeHRlbnNpb24iLCJpY29uUG9zQWNjZXNzb3IiLCJleHBvcnRzIiwiX3JlZiIsImxhdCIsImxuZyIsImFsdGl0dWRlIiwiZGMiLCJkIiwidmFsdWVBdCIsImluZGV4IiwiZmllbGRJZHgiLCJpY29uQWNjZXNzb3IiLCJfcmVmMiIsImljb24iLCJpY29uUmVxdWlyZWRDb2x1bW5zIiwiaWNvbk9wdGlvbmFsQ29sdW1ucyIsInBvaW50VmlzQ29uZmlncyIsInJhZGl1cyIsImZpeGVkUmFkaXVzIiwib3BhY2l0eSIsImNvbG9yUmFuZ2UiLCJyYWRpdXNSYW5nZSIsImJpbGxib2FyZCIsImZsYXR0ZXJJY29uUG9zaXRpb25zIiwibWVzaCIsImNlbGxzIiwicmVkdWNlIiwicHJldiIsImNlbGwiLCJwb3NpdGlvbnMiLCJJY29uTGF5ZXIiLCJfTGF5ZXIiLCJwcm9wcyIsIl90aGlzIiwiX2NsYXNzQ2FsbENoZWNrMiIsInJlZ2lzdGVyVmlzQ29uZmlnIiwiZ2V0UG9zaXRpb25BY2Nlc3NvciIsImRhdGFDb250YWluZXIiLCJjb25maWciLCJjb2x1bW5zIiwiZ2V0SWNvbkFjY2Vzc29yIiwiX2xheWVySW5mb01vZGFsIiwiSWNvbkluZm9Nb2RhbEZhY3RvcnkiLCJzdmdJY29ucyIsImljb25HZW9tZXRyeSIsImljb25HZW9tZXRyeVZlcnNpb24iLCJpc1Rlc3QiLCJzZXRTdmdJY29ucyIsImdldFN2Z0ljb25zIiwiX2luaGVyaXRzMiIsIl9jcmVhdGVDbGFzczIiLCJrZXkiLCJnZXQiLCJjb25jYXQiLCJnZXRBcHBsaWNhdGlvbkNvbmZpZyIsImNkblVybCIsImRlZmF1bHRQb2ludENvbHVtblBhaXJzIiwiSWNvbkxheWVySWNvbiIsImNvbG9yIiwiYWNjZXNzb3IiLCJkZWZhdWx0VmFsdWUiLCJzaXplIiwicHJvcGVydHkiLCJyYW5nZSIsImNoYW5uZWxTY2FsZVR5cGUiLCJpZCIsInRlbXBsYXRlIiwibW9kYWxQcm9wcyIsInRpdGxlIiwidmFsdWUiLCJnZXRab29tRmFjdG9yIiwiX3JlZjMiLCJ6b29tIiwiX3JlZjMkem9vbU9mZnNldCIsInpvb21PZmZzZXQiLCJNYXRoIiwicG93IiwiX3RoaXMyIiwiZmV0Y2hDb25maWciLCJtZXRob2QiLCJtb2RlIiwiY2FjaGUiLCJXaW5kb3ciLCJmZXRjaCIsInN2Z0ljb25VcmwiLCJ0aGVuIiwicmVzcG9uc2UiLCJvayIsIkVycm9yIiwic3RhdHVzIiwianNvbiIsInBhcnNlZCIsInVuZGVmaW5lZCIsImVyciIsImNvbnNvbGUiLCJlcnJvciIsIl90aGlzJG9uUmVkcmF3TmVlZGVkIiwiYWNjdSIsImN1cnIiLCJvblJlZHJhd05lZWRlZCIsImdldEZpbHRlcmVkSXRlbUNvdW50IiwiZmlsdGVyZWRJdGVtQ291bnQiLCJ2YWx1ZXMiLCJ0b3RhbCIsIk51bWJlciIsImlzRmluaXRlIiwiY2FsY3VsYXRlRGF0YUF0dHJpYnV0ZSIsIl9yZWY0IiwiZ2V0UG9zaXRpb24iLCJmaWx0ZXJlZEluZGV4IiwiZ2V0SWNvbiIsImRhdGEiLCJpIiwicm93SW5kZXgiLCJwb3MiLCJldmVyeSIsImZvcm1hdExheWVyRGF0YSIsImRhdGFzZXRzIiwib2xkTGF5ZXJEYXRhIiwiZGF0YUlkIiwidGV4dExhYmVsIiwiX2RhdGFzZXRzJHRoaXMkY29uZmlnIiwiZ3B1RmlsdGVyIiwiX3RoaXMkdXBkYXRlRGF0YSIsInVwZGF0ZURhdGEiLCJ0cmlnZ2VyQ2hhbmdlZCIsInRleHRMYWJlbHMiLCJmb3JtYXRUZXh0TGFiZWxEYXRhIiwiYWNjZXNzb3JzIiwiZ2V0QXR0cmlidXRlQWNjZXNzb3JzIiwiZ2V0RmlsdGVyVmFsdWUiLCJmaWx0ZXJWYWx1ZUFjY2Vzc29yIiwidXBkYXRlTGF5ZXJNZXRhIiwiZGF0YXNldCIsImJvdW5kcyIsImdldFBvaW50c0JvdW5kcyIsInVwZGF0ZU1ldGEiLCJyZW5kZXJMYXllciIsIm9wdHMiLCJfdGhpcyRjb25maWckY29sdW1ucyQiLCJfdGhpczMiLCJvYmplY3RIb3ZlcmVkIiwibWFwU3RhdGUiLCJpbnRlcmFjdGlvbkNvbmZpZyIsImxheWVyQ2FsbGJhY2tzIiwicmFkaXVzU2NhbGUiLCJnZXRSYWRpdXNTY2FsZUJ5Wm9vbSIsImxheWVyUHJvcHMiLCJ2aXNDb25maWciLCJyYWRpdXNNYXhQaXhlbHMiLCJ1cGRhdGVUcmlnZ2VycyIsImZpbHRlclZhbHVlVXBkYXRlVHJpZ2dlcnMiLCJnZXRWaXN1YWxDaGFubmVsVXBkYXRlVHJpZ2dlcnMiLCJkZWZhdWx0TGF5ZXJQcm9wcyIsImdldERlZmF1bHREZWNrTGF5ZXJQcm9wcyIsImJydXNoaW5nUHJvcHMiLCJnZXRCcnVzaGluZ0V4dGVuc2lvblByb3BzIiwiZ2V0UGl4ZWxPZmZzZXQiLCJnZXRUZXh0T2Zmc2V0QnlSYWRpdXMiLCJnZXRSYWRpdXMiLCJleHRlbnNpb25zIiwiX3RvQ29uc3VtYWJsZUFycmF5MiIsInNoYXJlZFByb3BzIiwiZmlsdGVyUmFuZ2UiLCJsYWJlbExheWVycyIsInJlbmRlclRleHRMYWJlbExheWVyIiwiaG92ZXJlZE9iamVjdCIsImhhc0hvdmVyZWRPYmplY3QiLCJwYXJhbWV0ZXJzIiwiZGVwdGhUZXN0IiwiY3VsbE1vZGUiLCJDVUxMX01PREUiLCJGUk9OVCIsImJhc2VMYXllcklkIiwibGF5ZXJJZFdpdGhWZXJzaW9uIiwiU3ZnSWNvbkxheWVyIiwiZ2V0SWNvbkdlb21ldHJ5IiwiX3RoaXMzJGljb25HZW9tZXRyeSIsImdldERlZmF1bHRIb3ZlckxheWVyUHJvcHMiLCJ2aXNpYmxlIiwiZ2V0RmlsbENvbG9yIiwiaGlnaGxpZ2h0Q29sb3IiLCJfdGhpczMkaWNvbkdlb21ldHJ5MiIsImZpbmREZWZhdWx0TGF5ZXJQcm9wcyIsIl9yZWY1IiwiX3JlZjUkZmllbGRQYWlycyIsImZpZWxkUGFpcnMiLCJfcmVmNSRmaWVsZHMiLCJmaWVsZHMiLCJub3RGb3VuZCIsImljb25GaWVsZHMiLCJfcmVmNiIsIm5hbWUiLCJyZXBsYWNlIiwidHJpbSIsInNwbGl0Iiwic29tZSIsInNlZyIsIklDT05fRklFTERTIiwiaW5jbHVkZXMiLCJwdFBhaXIiLCJhc3NpZ25Qb2ludFBhaXJUb0xheWVyQ29sdW1uIiwibWFwIiwiaWNvbkZpZWxkIiwibGFiZWwiLCJpc1Zpc2libGUiLCJMYXllciJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9pY29uLWxheWVyL2ljb24tbGF5ZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVFxuLy8gQ29weXJpZ2h0IGNvbnRyaWJ1dG9ycyB0byB0aGUga2VwbGVyLmdsIHByb2plY3RcblxuaW1wb3J0IFdpbmRvdyBmcm9tICdnbG9iYWwvd2luZG93JztcbmltcG9ydCB7QnJ1c2hpbmdFeHRlbnNpb259IGZyb20gJ0BkZWNrLmdsL2V4dGVuc2lvbnMnO1xuXG5pbXBvcnQge1N2Z0ljb25MYXllcn0gZnJvbSAnQGtlcGxlci5nbC9kZWNrZ2wtbGF5ZXJzJztcbmltcG9ydCBJY29uTGF5ZXJJY29uIGZyb20gJy4vaWNvbi1sYXllci1pY29uJztcbmltcG9ydCB7SUNPTl9GSUVMRFMsIENVTExfTU9ERX0gZnJvbSAnQGtlcGxlci5nbC9jb25zdGFudHMnO1xuaW1wb3J0IEljb25JbmZvTW9kYWxGYWN0b3J5IGZyb20gJy4vaWNvbi1pbmZvLW1vZGFsJztcbmltcG9ydCBMYXllciwge0xheWVyQmFzZUNvbmZpZywgTGF5ZXJCYXNlQ29uZmlnUGFydGlhbH0gZnJvbSAnLi4vYmFzZS1sYXllcic7XG5pbXBvcnQge2Fzc2lnblBvaW50UGFpclRvTGF5ZXJDb2x1bW4sIEZpbmREZWZhdWx0TGF5ZXJQcm9wc1JldHVyblZhbHVlfSBmcm9tICcuLi9sYXllci11dGlscyc7XG5pbXBvcnQge2lzVGVzdH0gZnJvbSAnQGtlcGxlci5nbC91dGlscyc7XG5pbXBvcnQge2dldFRleHRPZmZzZXRCeVJhZGl1cywgZm9ybWF0VGV4dExhYmVsRGF0YX0gZnJvbSAnLi4vbGF5ZXItdGV4dC1sYWJlbCc7XG5pbXBvcnQge2RlZmF1bHQgYXMgS2VwbGVyVGFibGV9IGZyb20gJ0BrZXBsZXIuZ2wvdGFibGUnO1xuaW1wb3J0IHtnZXRBcHBsaWNhdGlvbkNvbmZpZywgRGF0YUNvbnRhaW5lckludGVyZmFjZX0gZnJvbSAnQGtlcGxlci5nbC91dGlscyc7XG5pbXBvcnQge1xuICBDb2xvclJhbmdlLFxuICBWaXNDb25maWdCb29sZWFuLFxuICBWaXNDb25maWdDb2xvclJhbmdlLFxuICBWaXNDb25maWdOdW1iZXIsXG4gIFZpc0NvbmZpZ1JhbmdlLFxuICBNZXJnZSxcbiAgTGF5ZXJDb2x1bW4sXG4gIEJpbmRlZExheWVyQ2FsbGJhY2tzXG59IGZyb20gJ0BrZXBsZXIuZ2wvdHlwZXMnO1xuXG5leHBvcnQgdHlwZSBJY29uTGF5ZXJDb2x1bW5zQ29uZmlnID0ge1xuICBsYXQ6IExheWVyQ29sdW1uO1xuICBsbmc6IExheWVyQ29sdW1uO1xuICBhbHRpdHVkZTogTGF5ZXJDb2x1bW47XG4gIGljb246IExheWVyQ29sdW1uO1xufTtcblxudHlwZSBJY29uR2VvbWV0cnkgPSBvYmplY3QgfCBudWxsO1xuXG5leHBvcnQgdHlwZSBJY29uTGF5ZXJWaXNDb25maWdTZXR0aW5ncyA9IHtcbiAgcmFkaXVzOiBWaXNDb25maWdOdW1iZXI7XG4gIGZpeGVkUmFkaXVzOiBWaXNDb25maWdCb29sZWFuO1xuICBvcGFjaXR5OiBWaXNDb25maWdOdW1iZXI7XG4gIGNvbG9yUmFuZ2U6IFZpc0NvbmZpZ0NvbG9yUmFuZ2U7XG4gIHJhZGl1c1JhbmdlOiBWaXNDb25maWdSYW5nZTtcbn07XG5cbmV4cG9ydCB0eXBlIEljb25MYXllclZpc0NvbmZpZyA9IHtcbiAgcmFkaXVzOiBudW1iZXI7XG4gIGZpeGVkUmFkaXVzOiBib29sZWFuO1xuICBvcGFjaXR5OiBudW1iZXI7XG4gIGNvbG9yUmFuZ2U6IENvbG9yUmFuZ2U7XG4gIHJhZGl1c1JhbmdlOiBbbnVtYmVyLCBudW1iZXJdO1xuICBiaWxsYm9hcmQ6IGJvb2xlYW47XG59O1xuXG5leHBvcnQgdHlwZSBJY29uTGF5ZXJDb25maWcgPSBNZXJnZTxcbiAgTGF5ZXJCYXNlQ29uZmlnLFxuICB7Y29sdW1uczogSWNvbkxheWVyQ29sdW1uc0NvbmZpZzsgdmlzQ29uZmlnOiBJY29uTGF5ZXJWaXNDb25maWd9XG4+O1xuXG5leHBvcnQgdHlwZSBJY29uTGF5ZXJEYXRhID0ge2luZGV4OiBudW1iZXI7IGljb246IHN0cmluZ307XG5cbmNvbnN0IGJydXNoaW5nRXh0ZW5zaW9uID0gbmV3IEJydXNoaW5nRXh0ZW5zaW9uKCk7XG5cbmV4cG9ydCBjb25zdCBpY29uUG9zQWNjZXNzb3IgPVxuICAoe2xhdCwgbG5nLCBhbHRpdHVkZX06IEljb25MYXllckNvbHVtbnNDb25maWcpID0+XG4gIChkYzogRGF0YUNvbnRhaW5lckludGVyZmFjZSkgPT5cbiAgZCA9PlxuICAgIFtcbiAgICAgIGRjLnZhbHVlQXQoZC5pbmRleCwgbG5nLmZpZWxkSWR4KSxcbiAgICAgIGRjLnZhbHVlQXQoZC5pbmRleCwgbGF0LmZpZWxkSWR4KSxcbiAgICAgIGFsdGl0dWRlPy5maWVsZElkeCA+IC0xID8gZGMudmFsdWVBdChkLmluZGV4LCBhbHRpdHVkZS5maWVsZElkeCkgOiAwXG4gICAgXTtcblxuZXhwb3J0IGNvbnN0IGljb25BY2Nlc3NvciA9XG4gICh7aWNvbn06IEljb25MYXllckNvbHVtbnNDb25maWcpID0+XG4gIChkYzogRGF0YUNvbnRhaW5lckludGVyZmFjZSkgPT5cbiAgZCA9PlxuICAgIGRjLnZhbHVlQXQoZC5pbmRleCwgaWNvbi5maWVsZElkeCk7XG5cbmV4cG9ydCBjb25zdCBpY29uUmVxdWlyZWRDb2x1bW5zOiBbJ2xhdCcsICdsbmcnLCAnaWNvbiddID0gWydsYXQnLCAnbG5nJywgJ2ljb24nXTtcbmV4cG9ydCBjb25zdCBpY29uT3B0aW9uYWxDb2x1bW5zOiBbJ2FsdGl0dWRlJ10gPSBbJ2FsdGl0dWRlJ107XG5cbmV4cG9ydCBjb25zdCBwb2ludFZpc0NvbmZpZ3M6IHtcbiAgcmFkaXVzOiAncmFkaXVzJztcbiAgZml4ZWRSYWRpdXM6ICdmaXhlZFJhZGl1cyc7XG4gIG9wYWNpdHk6ICdvcGFjaXR5JztcbiAgY29sb3JSYW5nZTogJ2NvbG9yUmFuZ2UnO1xuICByYWRpdXNSYW5nZTogJ3JhZGl1c1JhbmdlJztcbiAgYmlsbGJvYXJkOiAnYmlsbGJvYXJkJztcbn0gPSB7XG4gIHJhZGl1czogJ3JhZGl1cycsXG4gIGZpeGVkUmFkaXVzOiAnZml4ZWRSYWRpdXMnLFxuICBvcGFjaXR5OiAnb3BhY2l0eScsXG4gIGNvbG9yUmFuZ2U6ICdjb2xvclJhbmdlJyxcbiAgcmFkaXVzUmFuZ2U6ICdyYWRpdXNSYW5nZScsXG4gIGJpbGxib2FyZDogJ2JpbGxib2FyZCdcbn07XG5cbmZ1bmN0aW9uIGZsYXR0ZXJJY29uUG9zaXRpb25zKGljb24pIHtcbiAgLy8gaGFkIHRvIGZsaXAgeSwgc2luY2UgQGx1bWEgbW9kYWwgaGFzIGNoYW5nZWRcbiAgcmV0dXJuIGljb24ubWVzaC5jZWxscy5yZWR1Y2UoKHByZXYsIGNlbGwpID0+IHtcbiAgICBjZWxsLmZvckVhY2gocCA9PiB7XG4gICAgICBwcmV2LnB1c2goXG4gICAgICAgIC4uLltpY29uLm1lc2gucG9zaXRpb25zW3BdWzBdLCAtaWNvbi5tZXNoLnBvc2l0aW9uc1twXVsxXSwgaWNvbi5tZXNoLnBvc2l0aW9uc1twXVsyXV1cbiAgICAgICk7XG4gICAgfSk7XG4gICAgcmV0dXJuIHByZXY7XG4gIH0sIFtdKTtcbn1cblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgSWNvbkxheWVyIGV4dGVuZHMgTGF5ZXIge1xuICBnZXRJY29uQWNjZXNzb3I6IChkYXRhQ29udGFpbmVyOiBEYXRhQ29udGFpbmVySW50ZXJmYWNlKSA9PiAoZDogYW55KSA9PiBhbnk7XG4gIF9sYXllckluZm9Nb2RhbDogKCkgPT4gSlNYLkVsZW1lbnQ7XG4gIGljb25HZW9tZXRyeTogSWNvbkdlb21ldHJ5O1xuICBpY29uR2VvbWV0cnlWZXJzaW9uOiBudW1iZXI7XG5cbiAgb25SZWRyYXdOZWVkZWQ6IEJpbmRlZExheWVyQ2FsbGJhY2tzWydvblJlZHJhd05lZWRlZCddO1xuXG4gIGRlY2xhcmUgdmlzQ29uZmlnU2V0dGluZ3M6IEljb25MYXllclZpc0NvbmZpZ1NldHRpbmdzO1xuICBkZWNsYXJlIGNvbmZpZzogSWNvbkxheWVyQ29uZmlnO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByb3BzOiB7XG4gICAgICBpZD86IHN0cmluZztcbiAgICAgIGljb25HZW9tZXRyeT86IEljb25HZW9tZXRyeTtcbiAgICAgIHN2Z0ljb25zPzogYW55W107XG4gICAgfSAmIExheWVyQmFzZUNvbmZpZ1BhcnRpYWxcbiAgKSB7XG4gICAgc3VwZXIocHJvcHMpO1xuXG4gICAgdGhpcy5yZWdpc3RlclZpc0NvbmZpZyhwb2ludFZpc0NvbmZpZ3MpO1xuICAgIHRoaXMuZ2V0UG9zaXRpb25BY2Nlc3NvciA9IChkYXRhQ29udGFpbmVyOiBEYXRhQ29udGFpbmVySW50ZXJmYWNlKSA9PlxuICAgICAgaWNvblBvc0FjY2Vzc29yKHRoaXMuY29uZmlnLmNvbHVtbnMpKGRhdGFDb250YWluZXIpO1xuICAgIHRoaXMuZ2V0SWNvbkFjY2Vzc29yID0gZGF0YUNvbnRhaW5lciA9PiBpY29uQWNjZXNzb3IodGhpcy5jb25maWcuY29sdW1ucykoZGF0YUNvbnRhaW5lcik7XG5cbiAgICB0aGlzLl9sYXllckluZm9Nb2RhbCA9IEljb25JbmZvTW9kYWxGYWN0b3J5KHByb3BzLnN2Z0ljb25zKTtcbiAgICB0aGlzLmljb25HZW9tZXRyeSA9IHByb3BzLmljb25HZW9tZXRyeSB8fCBudWxsO1xuICAgIHRoaXMuaWNvbkdlb21ldHJ5VmVyc2lvbiA9IDA7XG5cbiAgICBpZiAoaXNUZXN0KCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKHByb3BzLnN2Z0ljb25zKSB7XG4gICAgICAvLyBpZiBzdmcgaWNvbnMgYXJlIHBhc3NlZCBpbiB0aGVuIGJ5cGFzcyBmZXRjaGluZyBvZiByZW1vdGUgc3ZnIGljb25zXG4gICAgICB0aGlzLnNldFN2Z0ljb25zKHByb3BzLnN2Z0ljb25zKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gcHJlcGFyZSBsYXllciBpbmZvIG1vZGFsIGFuZCBmZXRjaCByZW1vdGUgc3ZnIGljb25zXG4gICAgICB0aGlzLmdldFN2Z0ljb25zKCk7XG4gICAgfVxuICB9XG5cbiAgZ2V0IHN2Z0ljb25VcmwoKSB7XG4gICAgcmV0dXJuIGAke2dldEFwcGxpY2F0aW9uQ29uZmlnKCkuY2RuVXJsfS9pY29ucy9zdmctaWNvbnMuanNvbmA7XG4gIH1cblxuICBnZXQgdHlwZSgpOiAnaWNvbicge1xuICAgIHJldHVybiAnaWNvbic7XG4gIH1cblxuICBnZXQgcmVxdWlyZWRMYXllckNvbHVtbnMoKSB7XG4gICAgcmV0dXJuIGljb25SZXF1aXJlZENvbHVtbnM7XG4gIH1cblxuICBnZXQgb3B0aW9uYWxDb2x1bW5zKCkge1xuICAgIHJldHVybiBpY29uT3B0aW9uYWxDb2x1bW5zO1xuICB9XG5cbiAgZ2V0IGNvbHVtblBhaXJzKCkge1xuICAgIHJldHVybiB0aGlzLmRlZmF1bHRQb2ludENvbHVtblBhaXJzO1xuICB9XG5cbiAgZ2V0IGxheWVySWNvbigpIHtcbiAgICByZXR1cm4gSWNvbkxheWVySWNvbjtcbiAgfVxuXG4gIGdldCB2aXN1YWxDaGFubmVscygpIHtcbiAgICByZXR1cm4ge1xuICAgICAgY29sb3I6IHtcbiAgICAgICAgLi4uc3VwZXIudmlzdWFsQ2hhbm5lbHMuY29sb3IsXG4gICAgICAgIGFjY2Vzc29yOiAnZ2V0RmlsbENvbG9yJyxcbiAgICAgICAgZGVmYXVsdFZhbHVlOiBjb25maWcgPT4gY29uZmlnLmNvbG9yXG4gICAgICB9LFxuICAgICAgc2l6ZToge1xuICAgICAgICAuLi5zdXBlci52aXN1YWxDaGFubmVscy5zaXplLFxuICAgICAgICBwcm9wZXJ0eTogJ3JhZGl1cycsXG4gICAgICAgIHJhbmdlOiAncmFkaXVzUmFuZ2UnLFxuICAgICAgICBjaGFubmVsU2NhbGVUeXBlOiAncmFkaXVzJyxcbiAgICAgICAgYWNjZXNzb3I6ICdnZXRSYWRpdXMnLFxuICAgICAgICBkZWZhdWx0VmFsdWU6IDFcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgZ2V0IGxheWVySW5mb01vZGFsKCkge1xuICAgIHJldHVybiB7XG4gICAgICBpZDogJ2ljb25JbmZvJyxcbiAgICAgIHRlbXBsYXRlOiB0aGlzLl9sYXllckluZm9Nb2RhbCxcbiAgICAgIG1vZGFsUHJvcHM6IHtcbiAgICAgICAgdGl0bGU6ICdtb2RhbC5pY29uSW5mby50aXRsZSdcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgZ2V0Wm9vbUZhY3Rvcih7em9vbSwgem9vbU9mZnNldCA9IDB9OiB7em9vbTogbnVtYmVyOyB6b29tT2Zmc2V0PzogbnVtYmVyfSkge1xuICAgIHJldHVybiBNYXRoLnBvdygyLCAxNCAtIHpvb20gKyB6b29tT2Zmc2V0KTtcbiAgfVxuXG4gIGdldFN2Z0ljb25zKCkge1xuICAgIGNvbnN0IGZldGNoQ29uZmlnID0ge1xuICAgICAgbWV0aG9kOiAnR0VUJyxcbiAgICAgIG1vZGU6ICdjb3JzJyxcbiAgICAgIGNhY2hlOiAnbm8tY2FjaGUnXG4gICAgfTtcblxuICAgIGlmIChXaW5kb3cuZmV0Y2ggJiYgdGhpcy5zdmdJY29uVXJsKSB7XG4gICAgICBXaW5kb3cuZmV0Y2godGhpcy5zdmdJY29uVXJsLCBmZXRjaENvbmZpZylcbiAgICAgICAgLnRoZW4ocmVzcG9uc2UgPT4ge1xuICAgICAgICAgIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgRmFpbGVkIHRvIGxvYWQgc3ZnLWljb25zLmpzb246ICR7cmVzcG9uc2Uuc3RhdHVzfWApO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gcmVzcG9uc2UuanNvbigpO1xuICAgICAgICB9KVxuICAgICAgICAudGhlbigocGFyc2VkOiB7c3ZnSWNvbnM/OiBhbnlbXX0gPSB7fSkgPT4ge1xuICAgICAgICAgIHRoaXMuc2V0U3ZnSWNvbnMocGFyc2VkLnN2Z0ljb25zKTtcbiAgICAgICAgfSlcbiAgICAgICAgLmNhdGNoKGVyciA9PiB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgZmV0Y2hpbmcgb3IgcGFyc2luZyBzdmctaWNvbnMuanNvbjonLCBlcnIpO1xuICAgICAgICAgIC8vIEZhbGxiYWNrIHRvIGVtcHR5IGdlb21ldHJ5IHRvIGFsbG93IGRlZmF1bHQgaWNvbiByZW5kZXJpbmdcbiAgICAgICAgICB0aGlzLmljb25HZW9tZXRyeSA9IHt9O1xuICAgICAgICAgIHRoaXMuaWNvbkdlb21ldHJ5VmVyc2lvbiArPSAxO1xuICAgICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gTm8gZmV0Y2ggYXZhaWxhYmxlOyBzZXQgZW1wdHkgZ2VvbWV0cnkgc28gbGF5ZXIgY2FuIHJlbmRlciBkZWZhdWx0IGljb25zXG4gICAgICB0aGlzLmljb25HZW9tZXRyeSA9IHt9O1xuICAgICAgdGhpcy5pY29uR2VvbWV0cnlWZXJzaW9uICs9IDE7XG4gICAgfVxuICB9XG5cbiAgc2V0U3ZnSWNvbnMoc3ZnSWNvbnM6IGFueVtdID0gW10pIHtcbiAgICB0aGlzLmljb25HZW9tZXRyeSA9IHN2Z0ljb25zLnJlZHVjZShcbiAgICAgIChhY2N1LCBjdXJyKSA9PiAoe1xuICAgICAgICAuLi5hY2N1LFxuICAgICAgICBbY3Vyci5pZF06IGZsYXR0ZXJJY29uUG9zaXRpb25zKGN1cnIpXG4gICAgICB9KSxcbiAgICAgIHt9XG4gICAgKTtcblxuICAgIC8vIEluY3JlbWVudCB2ZXJzaW9uIHdoZW4gU1ZHIGljb25zIGFyZSBsb2FkZWQgdG8gdHJpZ2dlciBsYXllciByZS1yZW5kZXJcbiAgICB0aGlzLmljb25HZW9tZXRyeVZlcnNpb24gKz0gMTtcblxuICAgIHRoaXMuX2xheWVySW5mb01vZGFsID0gSWNvbkluZm9Nb2RhbEZhY3Rvcnkoc3ZnSWNvbnMpO1xuXG4gICAgLy8gVHJpZ2dlciBhIG1hcCByZWRyYXcgc28gZGVjay5nbCBwaWNrcyB1cCB0aGUgbmV3IGdlb21ldHJ5XG4gICAgdGhpcy5vblJlZHJhd05lZWRlZD8uKCk7XG4gIH1cblxuICBzdGF0aWMgZmluZERlZmF1bHRMYXllclByb3BzKHtcbiAgICBmaWVsZFBhaXJzID0gW10sXG4gICAgZmllbGRzID0gW11cbiAgfTogS2VwbGVyVGFibGUpOiBGaW5kRGVmYXVsdExheWVyUHJvcHNSZXR1cm5WYWx1ZSB7XG4gICAgY29uc3Qgbm90Rm91bmQ6IEZpbmREZWZhdWx0TGF5ZXJQcm9wc1JldHVyblZhbHVlID0ge3Byb3BzOiBbXX07XG4gICAgaWYgKCFmaWVsZFBhaXJzLmxlbmd0aCB8fCAhZmllbGRzLmxlbmd0aCkge1xuICAgICAgcmV0dXJuIG5vdEZvdW5kO1xuICAgIH1cblxuICAgIGNvbnN0IGljb25GaWVsZHMgPSBmaWVsZHMuZmlsdGVyKCh7bmFtZX0pID0+XG4gICAgICBuYW1lXG4gICAgICAgIC5yZXBsYWNlKC9bXywuXSsvZywgJyAnKVxuICAgICAgICAudHJpbSgpXG4gICAgICAgIC5zcGxpdCgnICcpXG4gICAgICAgIC5zb21lKHNlZyA9PiBJQ09OX0ZJRUxEUy5pY29uLnNvbWUodCA9PiB0LmluY2x1ZGVzKHNlZykpKVxuICAgICk7XG5cbiAgICBpZiAoIWljb25GaWVsZHMubGVuZ3RoKSB7XG4gICAgICByZXR1cm4gbm90Rm91bmQ7XG4gICAgfVxuXG4gICAgLy8gY3JlYXRlIGljb24gbGF5ZXJzIGZvciBmaXJzdCBwb2ludCBwYWlyXG4gICAgY29uc3QgcHRQYWlyID0gZmllbGRQYWlyc1swXTtcbiAgICBjb25zdCBjb2x1bW5zID0gYXNzaWduUG9pbnRQYWlyVG9MYXllckNvbHVtbihwdFBhaXIsIHRydWUpO1xuXG4gICAgY29uc3QgcHJvcHMgPSBpY29uRmllbGRzLm1hcChpY29uRmllbGQgPT4gKHtcbiAgICAgIGxhYmVsOiBpY29uRmllbGQubmFtZS5yZXBsYWNlKC9bXywuXSsvZywgJyAnKS50cmltKCksXG4gICAgICBjb2x1bW5zOiB7XG4gICAgICAgIC4uLmNvbHVtbnMsXG4gICAgICAgIGljb246IHtcbiAgICAgICAgICB2YWx1ZTogaWNvbkZpZWxkLm5hbWUsXG4gICAgICAgICAgZmllbGRJZHg6IGljb25GaWVsZC5maWVsZElkeFxuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgaXNWaXNpYmxlOiB0cnVlXG4gICAgfSkpO1xuXG4gICAgcmV0dXJuIHtwcm9wc307XG4gIH1cblxuICBnZXRGaWx0ZXJlZEl0ZW1Db3VudCgpIHtcbiAgICAvLyB1c2UgdG90YWxcbiAgICBpZiAoT2JqZWN0LmtleXModGhpcy5maWx0ZXJlZEl0ZW1Db3VudCkubGVuZ3RoKSB7XG4gICAgICByZXR1cm4gT2JqZWN0LnZhbHVlcyh0aGlzLmZpbHRlcmVkSXRlbUNvdW50KS5yZWR1Y2UoXG4gICAgICAgICh0b3RhbCwgY3VycikgPT4gKE51bWJlci5pc0Zpbml0ZShjdXJyKSA/IHRvdGFsICsgY3VyciA6IHRvdGFsKSxcbiAgICAgICAgMFxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGNhbGN1bGF0ZURhdGFBdHRyaWJ1dGUoe2RhdGFDb250YWluZXIsIGZpbHRlcmVkSW5kZXh9OiBLZXBsZXJUYWJsZSwgZ2V0UG9zaXRpb24pIHtcbiAgICBjb25zdCBnZXRJY29uID0gdGhpcy5nZXRJY29uQWNjZXNzb3IoZGF0YUNvbnRhaW5lcik7XG4gICAgY29uc3QgZGF0YTogSWNvbkxheWVyRGF0YVtdID0gW107XG5cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGZpbHRlcmVkSW5kZXgubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IGluZGV4ID0gZmlsdGVyZWRJbmRleFtpXTtcbiAgICAgIGNvbnN0IHJvd0luZGV4ID0ge2luZGV4fTtcbiAgICAgIGNvbnN0IHBvcyA9IGdldFBvc2l0aW9uKHJvd0luZGV4KTtcbiAgICAgIGNvbnN0IGljb24gPSBnZXRJY29uKHJvd0luZGV4KTtcblxuICAgICAgLy8gaWYgZG9lc24ndCBoYXZlIHBvaW50IGxhdCBvciBsbmcsIGRvIG5vdCBhZGQgdGhlIHBvaW50XG4gICAgICAvLyBkZWNrLmdsIGNhbid0IGhhbmRsZSBwb3NpdGlvbiA9IG51bGxcbiAgICAgIGlmIChwb3MuZXZlcnkoTnVtYmVyLmlzRmluaXRlKSAmJiB0eXBlb2YgaWNvbiA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgZGF0YS5wdXNoKHtcbiAgICAgICAgICBpbmRleCxcbiAgICAgICAgICBpY29uXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBkYXRhO1xuICB9XG5cbiAgZm9ybWF0TGF5ZXJEYXRhKGRhdGFzZXRzLCBvbGRMYXllckRhdGEpIHtcbiAgICBpZiAodGhpcy5jb25maWcuZGF0YUlkID09PSBudWxsKSB7XG4gICAgICByZXR1cm4ge307XG4gICAgfVxuICAgIGNvbnN0IHt0ZXh0TGFiZWx9ID0gdGhpcy5jb25maWc7XG4gICAgY29uc3Qge2dwdUZpbHRlciwgZGF0YUNvbnRhaW5lcn0gPSBkYXRhc2V0c1t0aGlzLmNvbmZpZy5kYXRhSWRdO1xuXG4gICAgY29uc3QgZ2V0UG9zaXRpb24gPSB0aGlzLmdldFBvc2l0aW9uQWNjZXNzb3IoZGF0YUNvbnRhaW5lcik7XG5cbiAgICBjb25zdCB7ZGF0YSwgdHJpZ2dlckNoYW5nZWR9ID0gdGhpcy51cGRhdGVEYXRhKGRhdGFzZXRzLCBvbGRMYXllckRhdGEpO1xuXG4gICAgLy8gZ2V0IGFsbCBkaXN0aW5jdCBjaGFyYWN0ZXJzIGluIHRoZSB0ZXh0IGxhYmVsc1xuICAgIGNvbnN0IHRleHRMYWJlbHMgPSBmb3JtYXRUZXh0TGFiZWxEYXRhKHtcbiAgICAgIHRleHRMYWJlbCxcbiAgICAgIHRyaWdnZXJDaGFuZ2VkLFxuICAgICAgb2xkTGF5ZXJEYXRhLFxuICAgICAgZGF0YSxcbiAgICAgIGRhdGFDb250YWluZXJcbiAgICB9KTtcblxuICAgIGNvbnN0IGFjY2Vzc29ycyA9IHRoaXMuZ2V0QXR0cmlidXRlQWNjZXNzb3JzKHtkYXRhQ29udGFpbmVyfSk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgZGF0YSxcbiAgICAgIGdldFBvc2l0aW9uLFxuICAgICAgZ2V0RmlsdGVyVmFsdWU6IGdwdUZpbHRlci5maWx0ZXJWYWx1ZUFjY2Vzc29yKGRhdGFDb250YWluZXIpKCksXG4gICAgICB0ZXh0TGFiZWxzLFxuICAgICAgLi4uYWNjZXNzb3JzXG4gICAgfTtcbiAgfVxuXG4gIHVwZGF0ZUxheWVyTWV0YShkYXRhc2V0OiBLZXBsZXJUYWJsZSwgZ2V0UG9zaXRpb24pIHtcbiAgICBjb25zdCB7ZGF0YUNvbnRhaW5lcn0gPSBkYXRhc2V0O1xuICAgIGNvbnN0IGJvdW5kcyA9IHRoaXMuZ2V0UG9pbnRzQm91bmRzKGRhdGFDb250YWluZXIsIGdldFBvc2l0aW9uKTtcbiAgICB0aGlzLnVwZGF0ZU1ldGEoe2JvdW5kc30pO1xuICB9XG5cbiAgcmVuZGVyTGF5ZXIob3B0cykge1xuICAgIGNvbnN0IHtkYXRhLCBncHVGaWx0ZXIsIG9iamVjdEhvdmVyZWQsIG1hcFN0YXRlLCBpbnRlcmFjdGlvbkNvbmZpZywgbGF5ZXJDYWxsYmFja3N9ID0gb3B0cztcblxuICAgIC8vIFN0b3JlIGNhbGxiYWNrIHRvIHRyaWdnZXIgbWFwIHJlZHJhdyB3aGVuIGljb24gZ2VvbWV0cnkgbG9hZHMgYXN5bmNocm9ub3VzbHlcbiAgICB0aGlzLm9uUmVkcmF3TmVlZGVkID0gbGF5ZXJDYWxsYmFja3M/Lm9uUmVkcmF3TmVlZGVkO1xuXG4gICAgY29uc3QgcmFkaXVzU2NhbGUgPSB0aGlzLmdldFJhZGl1c1NjYWxlQnlab29tKG1hcFN0YXRlKTtcblxuICAgIGNvbnN0IGxheWVyUHJvcHMgPSB7XG4gICAgICByYWRpdXNTY2FsZSxcbiAgICAgIGJpbGxib2FyZDogdGhpcy5jb25maWcudmlzQ29uZmlnLmJpbGxib2FyZCxcbiAgICAgIC4uLih0aGlzLmNvbmZpZy52aXNDb25maWcuZml4ZWRSYWRpdXMgPyB7fSA6IHtyYWRpdXNNYXhQaXhlbHM6IDUwMH0pXG4gICAgfTtcblxuICAgIGNvbnN0IHVwZGF0ZVRyaWdnZXJzID0ge1xuICAgICAgZ2V0UG9zaXRpb246IHRoaXMuY29uZmlnLmNvbHVtbnMsXG4gICAgICBnZXRGaWx0ZXJWYWx1ZTogZ3B1RmlsdGVyLmZpbHRlclZhbHVlVXBkYXRlVHJpZ2dlcnMsXG4gICAgICAuLi50aGlzLmdldFZpc3VhbENoYW5uZWxVcGRhdGVUcmlnZ2VycygpXG4gICAgfTtcblxuICAgIGNvbnN0IGRlZmF1bHRMYXllclByb3BzID0gdGhpcy5nZXREZWZhdWx0RGVja0xheWVyUHJvcHMob3B0cyk7XG4gICAgY29uc3QgYnJ1c2hpbmdQcm9wcyA9IHRoaXMuZ2V0QnJ1c2hpbmdFeHRlbnNpb25Qcm9wcyhpbnRlcmFjdGlvbkNvbmZpZyk7XG4gICAgY29uc3QgZ2V0UGl4ZWxPZmZzZXQgPSBnZXRUZXh0T2Zmc2V0QnlSYWRpdXMocmFkaXVzU2NhbGUsIGRhdGEuZ2V0UmFkaXVzLCBtYXBTdGF0ZSk7XG4gICAgY29uc3QgZXh0ZW5zaW9ucyA9IFsuLi5kZWZhdWx0TGF5ZXJQcm9wcy5leHRlbnNpb25zLCBicnVzaGluZ0V4dGVuc2lvbl07XG5cbiAgICAvLyBzaGFyZWQgUHJvcHMgYmV0d2VlbiBsYXllciBhbmQgbGFiZWwgbGF5ZXJcbiAgICBjb25zdCBzaGFyZWRQcm9wcyA9IHtcbiAgICAgIGdldEZpbHRlclZhbHVlOiBkYXRhLmdldEZpbHRlclZhbHVlLFxuICAgICAgZXh0ZW5zaW9ucyxcbiAgICAgIGZpbHRlclJhbmdlOiBkZWZhdWx0TGF5ZXJQcm9wcy5maWx0ZXJSYW5nZSxcbiAgICAgIC4uLmJydXNoaW5nUHJvcHNcbiAgICB9O1xuXG4gICAgY29uc3QgbGFiZWxMYXllcnMgPSBbXG4gICAgICAuLi50aGlzLnJlbmRlclRleHRMYWJlbExheWVyKFxuICAgICAgICB7XG4gICAgICAgICAgZ2V0UG9zaXRpb246IGRhdGEuZ2V0UG9zaXRpb24sXG4gICAgICAgICAgc2hhcmVkUHJvcHMsXG4gICAgICAgICAgZ2V0UGl4ZWxPZmZzZXQsXG4gICAgICAgICAgdXBkYXRlVHJpZ2dlcnNcbiAgICAgICAgfSxcbiAgICAgICAgb3B0c1xuICAgICAgKVxuICAgIF07XG4gICAgY29uc3QgaG92ZXJlZE9iamVjdCA9IHRoaXMuaGFzSG92ZXJlZE9iamVjdChvYmplY3RIb3ZlcmVkKTtcblxuICAgIGNvbnN0IHBhcmFtZXRlcnMgPSB7XG4gICAgICAvLyBpY29ucyB3aWxsIGJlIGZsYXQgb24gdGhlIG1hcCB3aGVuIHRoZSBhbHRpdHVkZSBjb2x1bW4gaXMgbm90IHVzZWRcbiAgICAgIGRlcHRoVGVzdDogdGhpcy5jb25maWcuY29sdW1ucy5hbHRpdHVkZT8uZmllbGRJZHggPiAtMSxcbiAgICAgIGN1bGxNb2RlOiBDVUxMX01PREUuRlJPTlRcbiAgICB9O1xuXG4gICAgLy8gQXBwZW5kIGdlb21ldHJ5IHZlcnNpb24gdG8gbGF5ZXIgaWQgc28gZGVjay5nbCB0cmVhdHMgaXQgYXMgbmV3IGxheWVyIHdoZW4gZ2VvbWV0cnkgY2hhbmdlc1xuICAgIGNvbnN0IGJhc2VMYXllcklkID0gZGVmYXVsdExheWVyUHJvcHMuaWQgfHwgdGhpcy5pZDtcbiAgICBjb25zdCBsYXllcklkV2l0aFZlcnNpb24gPSBgJHtiYXNlTGF5ZXJJZH1fJHt0aGlzLmljb25HZW9tZXRyeVZlcnNpb259YDtcblxuICAgIHJldHVybiBbXG4gICAgICBuZXcgU3ZnSWNvbkxheWVyKHtcbiAgICAgICAgLi4uZGVmYXVsdExheWVyUHJvcHMsXG4gICAgICAgIGlkOiBsYXllcklkV2l0aFZlcnNpb24sXG4gICAgICAgIC4uLmJydXNoaW5nUHJvcHMsXG4gICAgICAgIC4uLmxheWVyUHJvcHMsXG4gICAgICAgIC4uLmRhdGEsXG4gICAgICAgIHBhcmFtZXRlcnMsXG4gICAgICAgIGdldEljb25HZW9tZXRyeTogaWQgPT4gdGhpcy5pY29uR2VvbWV0cnk/LltpZF0sXG5cbiAgICAgICAgLy8gdXBkYXRlIHRyaWdnZXJzXG4gICAgICAgIHVwZGF0ZVRyaWdnZXJzLFxuICAgICAgICBleHRlbnNpb25zXG4gICAgICB9KSxcblxuICAgICAgLy8gaG92ZXIgbGF5ZXJcbiAgICAgIC4uLihob3ZlcmVkT2JqZWN0XG4gICAgICAgID8gW1xuICAgICAgICAgICAgbmV3IFN2Z0ljb25MYXllcih7XG4gICAgICAgICAgICAgIC4uLnRoaXMuZ2V0RGVmYXVsdEhvdmVyTGF5ZXJQcm9wcygpLFxuICAgICAgICAgICAgICBpZDogYCR7bGF5ZXJJZFdpdGhWZXJzaW9ufS1ob3ZlcmAsXG4gICAgICAgICAgICAgIC4uLmxheWVyUHJvcHMsXG4gICAgICAgICAgICAgIHZpc2libGU6IGRlZmF1bHRMYXllclByb3BzLnZpc2libGUsXG4gICAgICAgICAgICAgIGRhdGE6IFtob3ZlcmVkT2JqZWN0XSxcbiAgICAgICAgICAgICAgcGFyYW1ldGVycyxcbiAgICAgICAgICAgICAgZ2V0UG9zaXRpb246IGRhdGEuZ2V0UG9zaXRpb24sXG4gICAgICAgICAgICAgIGdldFJhZGl1czogZGF0YS5nZXRSYWRpdXMsXG4gICAgICAgICAgICAgIGdldEZpbGxDb2xvcjogdGhpcy5jb25maWcuaGlnaGxpZ2h0Q29sb3IsXG4gICAgICAgICAgICAgIGdldEljb25HZW9tZXRyeTogaWQgPT4gdGhpcy5pY29uR2VvbWV0cnk/LltpZF1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgXVxuICAgICAgICA6IFtdKSxcblxuICAgICAgLy8gdGV4dCBsYWJlbCBsYXllclxuICAgICAgLi4ubGFiZWxMYXllcnNcbiAgICBdO1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7OztBQUdBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLFdBQUEsR0FBQUQsT0FBQTtBQUVBLElBQUFFLGFBQUEsR0FBQUYsT0FBQTtBQUNBLElBQUFHLGNBQUEsR0FBQUosc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFJLFVBQUEsR0FBQUosT0FBQTtBQUNBLElBQUFLLGNBQUEsR0FBQU4sc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFNLFVBQUEsR0FBQVAsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFPLFdBQUEsR0FBQVAsT0FBQTtBQUNBLElBQUFRLE1BQUEsR0FBQVIsT0FBQTtBQUNBLElBQUFTLGVBQUEsR0FBQVQsT0FBQTtBQUErRSxTQUFBVSxRQUFBQyxDQUFBLEVBQUFDLENBQUEsUUFBQUMsQ0FBQSxHQUFBQyxNQUFBLENBQUFDLElBQUEsQ0FBQUosQ0FBQSxPQUFBRyxNQUFBLENBQUFFLHFCQUFBLFFBQUFDLENBQUEsR0FBQUgsTUFBQSxDQUFBRSxxQkFBQSxDQUFBTCxDQUFBLEdBQUFD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