kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
400 lines (340 loc) • 41.8 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = exports.pointVisConfigs = exports.iconRequiredColumns = exports.iconAccessor = exports.iconPosAccessor = exports.SVG_ICON_URL = void 0;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
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 _window = _interopRequireDefault(require("global/window"));
var _extensions = require("@deck.gl/extensions");
var _colorUtils = require("../../utils/color-utils");
var _svgIconLayer = _interopRequireDefault(require("../../deckgl-layers/svg-icon-layer/svg-icon-layer"));
var _iconLayerIcon = _interopRequireDefault(require("./icon-layer-icon"));
var _defaultSettings = require("../../constants/default-settings");
var _iconInfoModal = _interopRequireDefault(require("./icon-info-modal"));
var _baseLayer = _interopRequireDefault(require("../base-layer"));
var _layerTextLabel = require("../layer-text-label");
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
var brushingExtension = new _extensions.BrushingExtension();
var SVG_ICON_URL = "".concat(_defaultSettings.CLOUDFRONT, "/icons/svg-icons.json");
exports.SVG_ICON_URL = SVG_ICON_URL;
var iconPosAccessor = function iconPosAccessor(_ref) {
var lat = _ref.lat,
lng = _ref.lng;
return function (d) {
return [d.data[lng.fieldIdx], d.data[lat.fieldIdx]];
};
};
exports.iconPosAccessor = iconPosAccessor;
var iconAccessor = function iconAccessor(_ref2) {
var icon = _ref2.icon;
return function (d) {
return d.data[icon.fieldIdx];
};
};
exports.iconAccessor = iconAccessor;
var iconRequiredColumns = ['lat', 'lng', 'icon'];
exports.iconRequiredColumns = iconRequiredColumns;
var pointVisConfigs = {
radius: 'radius',
fixedRadius: 'fixedRadius',
opacity: 'opacity',
colorRange: 'colorRange',
radiusRange: 'radiusRange'
};
exports.pointVisConfigs = pointVisConfigs;
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 =
/*#__PURE__*/
function (_Layer) {
(0, _inherits2["default"])(IconLayer, _Layer);
function IconLayer() {
var _this;
var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
(0, _classCallCheck2["default"])(this, IconLayer);
_this = (0, _possibleConstructorReturn2["default"])(this, (0, _getPrototypeOf2["default"])(IconLayer).call(this, props));
_this.registerVisConfig(pointVisConfigs);
_this.getPositionAccessor = function () {
return iconPosAccessor(_this.config.columns);
};
_this.getIconAccessor = function () {
return iconAccessor(_this.config.columns);
}; // prepare layer info modal
_this._layerInfoModal = (0, _iconInfoModal["default"])();
_this.iconGeometry = props.iconGeometry || null;
_this.getSvgIcons();
return _this;
}
(0, _createClass2["default"])(IconLayer, [{
key: "getSvgIcons",
value: function getSvgIcons() {
var _this2 = this;
var fetchConfig = {
method: 'GET',
mode: 'cors',
cache: 'no-cache'
};
if (_window["default"].fetch) {
_window["default"].fetch(SVG_ICON_URL, fetchConfig).then(function (response) {
return response.json();
}).then(function () {
var parsed = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var _parsed$svgIcons = parsed.svgIcons,
svgIcons = _parsed$svgIcons === void 0 ? [] : _parsed$svgIcons;
_this2.iconGeometry = svgIcons.reduce(function (accu, curr) {
return _objectSpread({}, accu, (0, _defineProperty2["default"])({}, curr.id, flatterIconPositions(curr)));
}, {});
_this2._layerInfoModal = (0, _iconInfoModal["default"])(svgIcons);
});
}
}
}, {
key: "calculateDataAttribute",
value: function calculateDataAttribute(_ref3, getPosition) {
var allData = _ref3.allData,
filteredIndex = _ref3.filteredIndex;
var getIcon = this.getIconAccessor();
var data = [];
for (var i = 0; i < filteredIndex.length; i++) {
var index = filteredIndex[i];
var pos = getPosition({
data: allData[index]
});
var icon = getIcon({
data: allData[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) && typeof icon === 'string') {
data.push({
index: index,
icon: icon,
data: allData[index]
});
}
}
return data;
}
}, {
key: "formatLayerData",
value: function formatLayerData(datasets, oldLayerData) {
var _this3 = this;
var opt = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var _this$config = this.config,
colorScale = _this$config.colorScale,
colorDomain = _this$config.colorDomain,
colorField = _this$config.colorField,
color = _this$config.color,
sizeField = _this$config.sizeField,
sizeScale = _this$config.sizeScale,
sizeDomain = _this$config.sizeDomain,
textLabel = _this$config.textLabel,
_this$config$visConfi = _this$config.visConfig,
radiusRange = _this$config$visConfi.radiusRange,
colorRange = _this$config$visConfi.colorRange;
var getPosition = this.getPositionAccessor();
var gpuFilter = datasets[this.config.dataId].gpuFilter;
var _this$updateData = this.updateData(datasets, oldLayerData),
data = _this$updateData.data,
triggerChanged = _this$updateData.triggerChanged; // point color
var cScale = colorField && this.getVisChannelScale(colorScale, colorDomain, colorRange.colors.map(_colorUtils.hexToRgb)); // point radius
var rScale = sizeField && this.getVisChannelScale(sizeScale, sizeDomain, radiusRange, 0);
var getRadius = rScale ? function (d) {
return _this3.getEncodedChannelValue(rScale, d.data, sizeField);
} : 1;
var getFillColor = cScale ? function (d) {
return _this3.getEncodedChannelValue(cScale, d.data, colorField);
} : color; // get all distinct characters in the text labels
var textLabels = (0, _layerTextLabel.formatTextLabelData)({
textLabel: textLabel,
triggerChanged: triggerChanged,
oldLayerData: oldLayerData,
data: data
});
return {
data: data,
getPosition: getPosition,
getFillColor: getFillColor,
getFilterValue: gpuFilter.filterValueAccessor(),
getRadius: getRadius,
textLabels: textLabels
};
}
}, {
key: "updateLayerMeta",
value: function updateLayerMeta(allData, getPosition) {
var bounds = this.getPointsBounds(allData, function (d) {
return getPosition({
data: d
});
});
this.updateMeta({
bounds: bounds
});
}
}, {
key: "renderLayer",
value: function renderLayer(opts) {
var _this4 = this;
var data = opts.data,
gpuFilter = opts.gpuFilter,
objectHovered = opts.objectHovered,
mapState = opts.mapState,
interactionConfig = opts.interactionConfig;
var radiusScale = this.getRadiusScaleByZoom(mapState);
var layerProps = _objectSpread({
radiusScale: radiusScale
}, this.config.visConfig.fixedRadius ? {} : {
radiusMaxPixels: 500
});
var updateTriggers = {
getFilterValue: gpuFilter.filterValueUpdateTriggers,
getRadius: {
sizeField: this.config.colorField,
radiusRange: this.config.visConfig.radiusRange,
sizeScale: this.config.sizeScale
},
getFillColor: {
color: this.config.color,
colorField: this.config.colorField,
colorRange: this.config.visConfig.colorRange,
colorScale: this.config.colorScale
}
};
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));
return !this.iconGeometry ? [] : [new _svgIconLayer["default"](_objectSpread({}, defaultLayerProps, {}, brushingProps, {}, layerProps, {}, data, {
getIconGeometry: function getIconGeometry(id) {
return _this4.iconGeometry[id];
},
// update triggers
updateTriggers: updateTriggers,
extensions: extensions
}))].concat((0, _toConsumableArray2["default"])(this.isLayerHovered(objectHovered) ? [new _svgIconLayer["default"](_objectSpread({}, this.getDefaultHoverLayerProps(), {}, layerProps, {
data: [objectHovered.object],
getPosition: data.getPosition,
getRadius: data.getRadius,
getFillColor: this.config.highlightColor,
getIconGeometry: function getIconGeometry(id) {
return _this4.iconGeometry[id];
}
}))] : []), (0, _toConsumableArray2["default"])(labelLayers));
}
}, {
key: "type",
get: function get() {
return 'icon';
}
}, {
key: "requiredLayerColumns",
get: function get() {
return iconRequiredColumns;
}
}, {
key: "columnPairs",
get: function get() {
return this.defaultPointColumnPairs;
}
}, {
key: "layerIcon",
get: function get() {
return _iconLayerIcon["default"];
}
}, {
key: "visualChannels",
get: function get() {
return _objectSpread({}, (0, _get2["default"])((0, _getPrototypeOf2["default"])(IconLayer.prototype), "visualChannels", this), {
size: _objectSpread({}, (0, _get2["default"])((0, _getPrototypeOf2["default"])(IconLayer.prototype), "visualChannels", this).size, {
range: 'radiusRange',
property: 'radius',
channelScaleType: 'radius'
})
});
}
}, {
key: "layerInfoModal",
get: function get() {
return {
id: 'iconInfo',
template: this._layerInfoModal,
modalProps: {
title: 'modal.iconInfo.title'
}
};
}
}], [{
key: "findDefaultLayerProps",
value: function findDefaultLayerProps(_ref4) {
var _ref4$fieldPairs = _ref4.fieldPairs,
fieldPairs = _ref4$fieldPairs === void 0 ? [] : _ref4$fieldPairs,
_ref4$fields = _ref4.fields,
fields = _ref4$fields === void 0 ? [] : _ref4$fields;
var notFound = {
props: []
};
if (!fieldPairs.length || !fields.length) {
return notFound;
}
var iconFields = fields.filter(function (_ref5) {
var name = _ref5.name;
return name.replace(/[_,.]+/g, ' ').trim().split(' ').some(function (seg) {
return _defaultSettings.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 props = iconFields.map(function (iconField) {
return {
label: iconField.name.replace(/[_,.]+/g, ' ').trim(),
columns: {
lat: ptPair.pair.lat,
lng: ptPair.pair.lng,
icon: {
value: iconField.name,
fieldIdx: iconField.tableFieldIndex - 1
}
},
isVisible: true
};
});
return {
props: props
};
}
}]);
return IconLayer;
}(_baseLayer["default"]);
exports["default"] = IconLayer;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9sYXllcnMvaWNvbi1sYXllci9pY29uLWxheWVyLmpzIl0sIm5hbWVzIjpbImJydXNoaW5nRXh0ZW5zaW9uIiwiQnJ1c2hpbmdFeHRlbnNpb24iLCJTVkdfSUNPTl9VUkwiLCJDTE9VREZST05UIiwiaWNvblBvc0FjY2Vzc29yIiwibGF0IiwibG5nIiwiZCIsImRhdGEiLCJmaWVsZElkeCIsImljb25BY2Nlc3NvciIsImljb24iLCJpY29uUmVxdWlyZWRDb2x1bW5zIiwicG9pbnRWaXNDb25maWdzIiwicmFkaXVzIiwiZml4ZWRSYWRpdXMiLCJvcGFjaXR5IiwiY29sb3JSYW5nZSIsInJhZGl1c1JhbmdlIiwiZmxhdHRlckljb25Qb3NpdGlvbnMiLCJtZXNoIiwiY2VsbHMiLCJyZWR1Y2UiLCJwcmV2IiwiY2VsbCIsImZvckVhY2giLCJwIiwicHVzaCIsInBvc2l0aW9ucyIsIkljb25MYXllciIsInByb3BzIiwicmVnaXN0ZXJWaXNDb25maWciLCJnZXRQb3NpdGlvbkFjY2Vzc29yIiwiY29uZmlnIiwiY29sdW1ucyIsImdldEljb25BY2Nlc3NvciIsIl9sYXllckluZm9Nb2RhbCIsImljb25HZW9tZXRyeSIsImdldFN2Z0ljb25zIiwiZmV0Y2hDb25maWciLCJtZXRob2QiLCJtb2RlIiwiY2FjaGUiLCJ3aW5kb3ciLCJmZXRjaCIsInRoZW4iLCJyZXNwb25zZSIsImpzb24iLCJwYXJzZWQiLCJzdmdJY29ucyIsImFjY3UiLCJjdXJyIiwiaWQiLCJnZXRQb3NpdGlvbiIsImFsbERhdGEiLCJmaWx0ZXJlZEluZGV4IiwiZ2V0SWNvbiIsImkiLCJsZW5ndGgiLCJpbmRleCIsInBvcyIsImV2ZXJ5IiwiTnVtYmVyIiwiaXNGaW5pdGUiLCJkYXRhc2V0cyIsIm9sZExheWVyRGF0YSIsIm9wdCIsImNvbG9yU2NhbGUiLCJjb2xvckRvbWFpbiIsImNvbG9yRmllbGQiLCJjb2xvciIsInNpemVGaWVsZCIsInNpemVTY2FsZSIsInNpemVEb21haW4iLCJ0ZXh0TGFiZWwiLCJ2aXNDb25maWciLCJncHVGaWx0ZXIiLCJkYXRhSWQiLCJ1cGRhdGVEYXRhIiwidHJpZ2dlckNoYW5nZWQiLCJjU2NhbGUiLCJnZXRWaXNDaGFubmVsU2NhbGUiLCJjb2xvcnMiLCJtYXAiLCJoZXhUb1JnYiIsInJTY2FsZSIsImdldFJhZGl1cyIsImdldEVuY29kZWRDaGFubmVsVmFsdWUiLCJnZXRGaWxsQ29sb3IiLCJ0ZXh0TGFiZWxzIiwiZ2V0RmlsdGVyVmFsdWUiLCJmaWx0ZXJWYWx1ZUFjY2Vzc29yIiwiYm91bmRzIiwiZ2V0UG9pbnRzQm91bmRzIiwidXBkYXRlTWV0YSIsIm9wdHMiLCJvYmplY3RIb3ZlcmVkIiwibWFwU3RhdGUiLCJpbnRlcmFjdGlvbkNvbmZpZyIsInJhZGl1c1NjYWxlIiwiZ2V0UmFkaXVzU2NhbGVCeVpvb20iLCJsYXllclByb3BzIiwicmFkaXVzTWF4UGl4ZWxzIiwidXBkYXRlVHJpZ2dlcnMiLCJmaWx0ZXJWYWx1ZVVwZGF0ZVRyaWdnZXJzIiwiZGVmYXVsdExheWVyUHJvcHMiLCJnZXREZWZhdWx0RGVja0xheWVyUHJvcHMiLCJicnVzaGluZ1Byb3BzIiwiZ2V0QnJ1c2hpbmdFeHRlbnNpb25Qcm9wcyIsImdldFBpeGVsT2Zmc2V0IiwiZXh0ZW5zaW9ucyIsInNoYXJlZFByb3BzIiwiZmlsdGVyUmFuZ2UiLCJsYWJlbExheWVycyIsInJlbmRlclRleHRMYWJlbExheWVyIiwiU3ZnSWNvbkxheWVyIiwiZ2V0SWNvbkdlb21ldHJ5IiwiaXNMYXllckhvdmVyZWQiLCJnZXREZWZhdWx0SG92ZXJMYXllclByb3BzIiwib2JqZWN0IiwiaGlnaGxpZ2h0Q29sb3IiLCJkZWZhdWx0UG9pbnRDb2x1bW5QYWlycyIsIkljb25MYXllckljb24iLCJzaXplIiwicmFuZ2UiLCJwcm9wZXJ0eSIsImNoYW5uZWxTY2FsZVR5cGUiLCJ0ZW1wbGF0ZSIsIm1vZGFsUHJvcHMiLCJ0aXRsZSIsImZpZWxkUGFpcnMiLCJmaWVsZHMiLCJub3RGb3VuZCIsImljb25GaWVsZHMiLCJmaWx0ZXIiLCJuYW1lIiwicmVwbGFjZSIsInRyaW0iLCJzcGxpdCIsInNvbWUiLCJzZWciLCJJQ09OX0ZJRUxEUyIsInQiLCJpbmNsdWRlcyIsInB0UGFpciIsImljb25GaWVsZCIsImxhYmVsIiwicGFpciIsInZhbHVlIiwidGFibGVGaWVsZEluZGV4IiwiaXNWaXNpYmxlIiwiTGF5ZXIiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFvQkE7O0FBQ0E7O0FBRUE7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7Ozs7OztBQUVBLElBQU1BLGlCQUFpQixHQUFHLElBQUlDLDZCQUFKLEVBQTFCO0FBRU8sSUFBTUMsWUFBWSxhQUFNQywyQkFBTiwwQkFBbEI7OztBQUVBLElBQU1DLGVBQWUsR0FBRyxTQUFsQkEsZUFBa0I7QUFBQSxNQUFFQyxHQUFGLFFBQUVBLEdBQUY7QUFBQSxNQUFPQyxHQUFQLFFBQU9BLEdBQVA7QUFBQSxTQUFnQixVQUFBQyxDQUFDO0FBQUEsV0FBSSxDQUFDQSxDQUFDLENBQUNDLElBQUYsQ0FBT0YsR0FBRyxDQUFDRyxRQUFYLENBQUQsRUFBdUJGLENBQUMsQ0FBQ0MsSUFBRixDQUFPSCxHQUFHLENBQUNJLFFBQVgsQ0FBdkIsQ0FBSjtBQUFBLEdBQWpCO0FBQUEsQ0FBeEI7Ozs7QUFDQSxJQUFNQyxZQUFZLEdBQUcsU0FBZkEsWUFBZTtBQUFBLE1BQUVDLElBQUYsU0FBRUEsSUFBRjtBQUFBLFNBQVksVUFBQUosQ0FBQztBQUFBLFdBQUlBLENBQUMsQ0FBQ0MsSUFBRixDQUFPRyxJQUFJLENBQUNGLFFBQVosQ0FBSjtBQUFBLEdBQWI7QUFBQSxDQUFyQjs7O0FBRUEsSUFBTUcsbUJBQW1CLEdBQUcsQ0FBQyxLQUFELEVBQVEsS0FBUixFQUFlLE1BQWYsQ0FBNUI7O0FBRUEsSUFBTUMsZUFBZSxHQUFHO0FBQzdCQyxFQUFBQSxNQUFNLEVBQUUsUUFEcUI7QUFFN0JDLEVBQUFBLFdBQVcsRUFBRSxhQUZnQjtBQUc3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eXJpZ2h0IChjKSAyMDIwIFViZXIgVGVjaG5vbG9naWVzLCBJbmMuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuLy8gb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbFxuLy8gaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0c1xuLy8gdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbFxuLy8gY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzXG4vLyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4vLyBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSxcbi8vIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuLy8gQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuLy8gTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSxcbi8vIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbi8vIFRIRSBTT0ZUV0FSRS5cblxuaW1wb3J0IHdpbmRvdyBmcm9tICdnbG9iYWwvd2luZG93JztcbmltcG9ydCB7QnJ1c2hpbmdFeHRlbnNpb259IGZyb20gJ0BkZWNrLmdsL2V4dGVuc2lvbnMnO1xuXG5pbXBvcnQge2hleFRvUmdifSBmcm9tICd1dGlscy9jb2xvci11dGlscyc7XG5pbXBvcnQgU3ZnSWNvbkxheWVyIGZyb20gJ2RlY2tnbC1sYXllcnMvc3ZnLWljb24tbGF5ZXIvc3ZnLWljb24tbGF5ZXInO1xuaW1wb3J0IEljb25MYXllckljb24gZnJvbSAnLi9pY29uLWxheWVyLWljb24nO1xuaW1wb3J0IHtJQ09OX0ZJRUxEUywgQ0xPVURGUk9OVH0gZnJvbSAnY29uc3RhbnRzL2RlZmF1bHQtc2V0dGluZ3MnO1xuaW1wb3J0IEljb25JbmZvTW9kYWxGYWN0b3J5IGZyb20gJy4vaWNvbi1pbmZvLW1vZGFsJztcbmltcG9ydCBMYXllciBmcm9tICcuLi9iYXNlLWxheWVyJztcbmltcG9ydCB7Z2V0VGV4dE9mZnNldEJ5UmFkaXVzLCBmb3JtYXRUZXh0TGFiZWxEYXRhfSBmcm9tICcuLi9sYXllci10ZXh0LWxhYmVsJztcblxuY29uc3QgYnJ1c2hpbmdFeHRlbnNpb24gPSBuZXcgQnJ1c2hpbmdFeHRlbnNpb24oKTtcblxuZXhwb3J0IGNvbnN0IFNWR19JQ09OX1VSTCA9IGAke0NMT1VERlJPTlR9L2ljb25zL3N2Zy1pY29ucy5qc29uYDtcblxuZXhwb3J0IGNvbnN0IGljb25Qb3NBY2Nlc3NvciA9ICh7bGF0LCBsbmd9KSA9PiBkID0+IFtkLmRhdGFbbG5nLmZpZWxkSWR4XSwgZC5kYXRhW2xhdC5maWVsZElkeF1dO1xuZXhwb3J0IGNvbnN0IGljb25BY2Nlc3NvciA9ICh7aWNvbn0pID0+IGQgPT4gZC5kYXRhW2ljb24uZmllbGRJZHhdO1xuXG5leHBvcnQgY29uc3QgaWNvblJlcXVpcmVkQ29sdW1ucyA9IFsnbGF0JywgJ2xuZycsICdpY29uJ107XG5cbmV4cG9ydCBjb25zdCBwb2ludFZpc0NvbmZpZ3MgPSB7XG4gIHJhZGl1czogJ3JhZGl1cycsXG4gIGZpeGVkUmFkaXVzOiAnZml4ZWRSYWRpdXMnLFxuICBvcGFjaXR5OiAnb3BhY2l0eScsXG4gIGNvbG9yUmFuZ2U6ICdjb2xvclJhbmdlJyxcbiAgcmFkaXVzUmFuZ2U6ICdyYWRpdXNSYW5nZSdcbn07XG5cbmZ1bmN0aW9uIGZsYXR0ZXJJY29uUG9zaXRpb25zKGljb24pIHtcbiAgLy8gaGFkIHRvIGZsaXAgeSwgc2luY2UgQGx1bWEgbW9kYWwgaGFzIGNoYW5nZWRcbiAgcmV0dXJuIGljb24ubWVzaC5jZWxscy5yZWR1Y2UoKHByZXYsIGNlbGwpID0+IHtcbiAgICBjZWxsLmZvckVhY2gocCA9PiB7XG4gICAgICBwcmV2LnB1c2goXG4gICAgICAgIC4uLltpY29uLm1lc2gucG9zaXRpb25zW3BdWzBdLCAtaWNvbi5tZXNoLnBvc2l0aW9uc1twXVsxXSwgaWNvbi5tZXNoLnBvc2l0aW9uc1twXVsyXV1cbiAgICAgICk7XG4gICAgfSk7XG4gICAgcmV0dXJuIHByZXY7XG4gIH0sIFtdKTtcbn1cblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgSWNvbkxheWVyIGV4dGVuZHMgTGF5ZXIge1xuICBjb25zdHJ1Y3Rvcihwcm9wcyA9IHt9KSB7XG4gICAgc3VwZXIocHJvcHMpO1xuXG4gICAgdGhpcy5yZWdpc3RlclZpc0NvbmZpZyhwb2ludFZpc0NvbmZpZ3MpO1xuICAgIHRoaXMuZ2V0UG9zaXRpb25BY2Nlc3NvciA9ICgpID0+IGljb25Qb3NBY2Nlc3Nvcih0aGlzLmNvbmZpZy5jb2x1bW5zKTtcbiAgICB0aGlzLmdldEljb25BY2Nlc3NvciA9ICgpID0+IGljb25BY2Nlc3Nvcih0aGlzLmNvbmZpZy5jb2x1bW5zKTtcblxuICAgIC8vIHByZXBhcmUgbGF5ZXIgaW5mbyBtb2RhbFxuICAgIHRoaXMuX2xheWVySW5mb01vZGFsID0gSWNvbkluZm9Nb2RhbEZhY3RvcnkoKTtcbiAgICB0aGlzLmljb25HZW9tZXRyeSA9IHByb3BzLmljb25HZW9tZXRyeSB8fCBudWxsO1xuICAgIHRoaXMuZ2V0U3ZnSWNvbnMoKTtcbiAgfVxuXG4gIGdldCB0eXBlKCkge1xuICAgIHJldHVybiAnaWNvbic7XG4gIH1cblxuICBnZXQgcmVxdWlyZWRMYXllckNvbHVtbnMoKSB7XG4gICAgcmV0dXJuIGljb25SZXF1aXJlZENvbHVtbnM7XG4gIH1cblxuICBnZXQgY29sdW1uUGFpcnMoKSB7XG4gICAgcmV0dXJuIHRoaXMuZGVmYXVsdFBvaW50Q29sdW1uUGFpcnM7XG4gIH1cblxuICBnZXQgbGF5ZXJJY29uKCkge1xuICAgIHJldHVybiBJY29uTGF5ZXJJY29uO1xuICB9XG5cbiAgZ2V0IHZpc3VhbENoYW5uZWxzKCkge1xuICAgIHJldHVybiB7XG4gICAgICAuLi5zdXBlci52aXN1YWxDaGFubmVscyxcbiAgICAgIHNpemU6IHtcbiAgICAgICAgLi4uc3VwZXIudmlzdWFsQ2hhbm5lbHMuc2l6ZSxcbiAgICAgICAgcmFuZ2U6ICdyYWRpdXNSYW5nZScsXG4gICAgICAgIHByb3BlcnR5OiAncmFkaXVzJyxcbiAgICAgICAgY2hhbm5lbFNjYWxlVHlwZTogJ3JhZGl1cydcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgZ2V0IGxheWVySW5mb01vZGFsKCkge1xuICAgIHJldHVybiB7XG4gICAgICBpZDogJ2ljb25JbmZvJyxcbiAgICAgIHRlbXBsYXRlOiB0aGlzLl9sYXllckluZm9Nb2RhbCxcbiAgICAgIG1vZGFsUHJvcHM6IHtcbiAgICAgICAgdGl0bGU6ICdtb2RhbC5pY29uSW5mby50aXRsZSdcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgZ2V0U3ZnSWNvbnMoKSB7XG4gICAgY29uc3QgZmV0Y2hDb25maWcgPSB7XG4gICAgICBtZXRob2Q6ICdHRVQnLFxuICAgICAgbW9kZTogJ2NvcnMnLFxuICAgICAgY2FjaGU6ICduby1jYWNoZSdcbiAgICB9O1xuXG4gICAgaWYgKHdpbmRvdy5mZXRjaCkge1xuICAgICAgd2luZG93XG4gICAgICAgIC5mZXRjaChTVkdfSUNPTl9VUkwsIGZldGNoQ29uZmlnKVxuICAgICAgICAudGhlbihyZXNwb25zZSA9PiByZXNwb25zZS5qc29uKCkpXG4gICAgICAgIC50aGVuKChwYXJzZWQgPSB7fSkgPT4ge1xuICAgICAgICAgIGNvbnN0IHtzdmdJY29ucyA9IFtdfSA9IHBhcnNlZDtcbiAgICAgICAgICB0aGlzLmljb25HZW9tZXRyeSA9IHN2Z0ljb25zLnJlZHVjZShcbiAgICAgICAgICAgIChhY2N1LCBjdXJyKSA9PiAoe1xuICAgICAgICAgICAgICAuLi5hY2N1LFxuICAgICAgICAgICAgICBbY3Vyci5pZF06IGZsYXR0ZXJJY29uUG9zaXRpb25zKGN1cnIpXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIHt9XG4gICAgICAgICAgKTtcblxuICAgICAgICAgIHRoaXMuX2xheWVySW5mb01vZGFsID0gSWNvbkluZm9Nb2RhbEZhY3Rvcnkoc3ZnSWNvbnMpO1xuICAgICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBzdGF0aWMgZmluZERlZmF1bHRMYXllclByb3BzKHtmaWVsZFBhaXJzID0gW10sIGZpZWxkcyA9IFtdfSkge1xuICAgIGNvbnN0IG5vdEZvdW5kID0ge3Byb3BzOiBbXX07XG4gICAgaWYgKCFmaWVsZFBhaXJzLmxlbmd0aCB8fCAhZmllbGRzLmxlbmd0aCkge1xuICAgICAgcmV0dXJuIG5vdEZvdW5kO1xuICAgIH1cblxuICAgIGNvbnN0IGljb25GaWVsZHMgPSBmaWVsZHMuZmlsdGVyKCh7bmFtZX0pID0+XG4gICAgICBuYW1lXG4gICAgICAgIC5yZXBsYWNlKC9bXywuXSsvZywgJyAnKVxuICAgICAgICAudHJpbSgpXG4gICAgICAgIC5zcGxpdCgnICcpXG4gICAgICAgIC5zb21lKHNlZyA9PiBJQ09OX0ZJRUxEUy5pY29uLnNvbWUodCA9PiB0LmluY2x1ZGVzKHNlZykpKVxuICAgICk7XG5cbiAgICBpZiAoIWljb25GaWVsZHMubGVuZ3RoKSB7XG4gICAgICByZXR1cm4gbm90Rm91bmQ7XG4gICAgfVxuXG4gICAgLy8gY3JlYXRlIGljb24gbGF5ZXJzIGZvciBmaXJzdCBwb2ludCBwYWlyXG4gICAgY29uc3QgcHRQYWlyID0gZmllbGRQYWlyc1swXTtcblxuICAgIGNvbnN0IHByb3BzID0gaWNvbkZpZWxkcy5tYXAoaWNvbkZpZWxkID0+ICh7XG4gICAgICBsYWJlbDogaWNvbkZpZWxkLm5hbWUucmVwbGFjZSgvW18sLl0rL2csICcgJykudHJpbSgpLFxuICAgICAgY29sdW1uczoge1xuICAgICAgICBsYXQ6IHB0UGFpci5wYWlyLmxhdCxcbiAgICAgICAgbG5nOiBwdFBhaXIucGFpci5sbmcsXG4gICAgICAgIGljb246IHtcbiAgICAgICAgICB2YWx1ZTogaWNvbkZpZWxkLm5hbWUsXG4gICAgICAgICAgZmllbGRJZHg6IGljb25GaWVsZC50YWJsZUZpZWxkSW5kZXggLSAxXG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICBpc1Zpc2libGU6IHRydWVcbiAgICB9KSk7XG5cbiAgICByZXR1cm4ge3Byb3BzfTtcbiAgfVxuXG4gIGNhbGN1bGF0ZURhdGFBdHRyaWJ1dGUoe2FsbERhdGEsIGZpbHRlcmVkSW5kZXh9LCBnZXRQb3NpdGlvbikge1xuICAgIGNvbnN0IGdldEljb24gPSB0aGlzLmdldEljb25BY2Nlc3NvcigpO1xuICAgIGNvbnN0IGRhdGEgPSBbXTtcblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZmlsdGVyZWRJbmRleC5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgaW5kZXggPSBmaWx0ZXJlZEluZGV4W2ldO1xuICAgICAgY29uc3QgcG9zID0gZ2V0UG9zaXRpb24oe2RhdGE6IGFsbERhdGFbaW5kZXhdfSk7XG4gICAgICBjb25zdCBpY29uID0gZ2V0SWNvbih7ZGF0YTogYWxsRGF0YVtpbmRleF19KTtcblxuICAgICAgLy8gaWYgZG9lc24ndCBoYXZlIHBvaW50IGxhdCBvciBsbmcsIGRvIG5vdCBhZGQgdGhlIHBvaW50XG4gICAgICAvLyBkZWNrLmdsIGNhbid0IGhhbmRsZSBwb3NpdGlvbiA9IG51bGxcbiAgICAgIGlmIChwb3MuZXZlcnkoTnVtYmVyLmlzRmluaXRlKSAmJiB0eXBlb2YgaWNvbiA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgZGF0YS5wdXNoKHtcbiAgICAgICAgICBpbmRleCxcbiAgICAgICAgICBpY29uLFxuICAgICAgICAgIGRhdGE6IGFsbERhdGFbaW5kZXhdXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBkYXRhO1xuICB9XG5cbiAgZm9ybWF0TGF5ZXJEYXRhKGRhdGFzZXRzLCBvbGRMYXllckRhdGEsIG9wdCA9IHt9KSB7XG4gICAgY29uc3Qge1xuICAgICAgY29sb3JTY2FsZSxcbiAgICAgIGNvbG9yRG9tYWluLFxuICAgICAgY29sb3JGaWVsZCxcbiAgICAgIGNvbG9yLFxuICAgICAgc2l6ZUZpZWxkLFxuICAgICAgc2l6ZVNjYWxlLFxuICAgICAgc2l6ZURvbWFpbixcbiAgICAgIHRleHRMYWJlbCxcbiAgICAgIHZpc0NvbmZpZzoge3JhZGl1c1JhbmdlLCBjb2xvclJhbmdlfVxuICAgIH0gPSB0aGlzLmNvbmZpZztcbiAgICBjb25zdCBnZXRQb3NpdGlvbiA9IHRoaXMuZ2V0UG9zaXRpb25BY2Nlc3NvcigpO1xuXG4gICAgY29uc3Qge2dwdUZpbHRlcn0gPSBkYXRhc2V0c1t0aGlzLmNvbmZpZy5kYXRhSWRdO1xuICAgIGNvbnN0IHtkYXRhLCB0cmlnZ2VyQ2hhbmdlZH0gPSB0aGlzLnVwZGF0ZURhdGEoZGF0YXNldHMsIG9sZExheWVyRGF0YSk7XG5cbiAgICAvLyBwb2ludCBjb2xvclxuICAgIGNvbnN0IGNTY2FsZSA9XG4gICAgICBjb2xvckZpZWxkICYmXG4gICAgICB0aGlzLmdldFZpc0NoYW5uZWxTY2FsZShjb2xvclNjYWxlLCBjb2xvckRvbWFpbiwgY29sb3JSYW5nZS5jb2xvcnMubWFwKGhleFRvUmdiKSk7XG5cbiAgICAvLyBwb2ludCByYWRpdXNcbiAgICBjb25zdCByU2NhbGUgPSBzaXplRmllbGQgJiYgdGhpcy5nZXRWaXNDaGFubmVsU2NhbGUoc2l6ZVNjYWxlLCBzaXplRG9tYWluLCByYWRpdXNSYW5nZSwgMCk7XG5cbiAgICBjb25zdCBnZXRSYWRpdXMgPSByU2NhbGUgPyBkID0+IHRoaXMuZ2V0RW5jb2RlZENoYW5uZWxWYWx1ZShyU2NhbGUsIGQuZGF0YSwgc2l6ZUZpZWxkKSA6IDE7XG5cbiAgICBjb25zdCBnZXRGaWxsQ29sb3IgPSBjU2NhbGVcbiAgICAgID8gZCA9PiB0aGlzLmdldEVuY29kZWRDaGFubmVsVmFsdWUoY1NjYWxlLCBkLmRhdGEsIGNvbG9yRmllbGQpXG4gICAgICA6IGNvbG9yO1xuXG4gICAgLy8gZ2V0IGFsbCBkaXN0aW5jdCBjaGFyYWN0ZXJzIGluIHRoZSB0ZXh0IGxhYmVsc1xuICAgIGNvbnN0IHRleHRMYWJlbHMgPSBmb3JtYXRUZXh0TGFiZWxEYXRhKHtcbiAgICAgIHRleHRMYWJlbCxcbiAgICAgIHRyaWdnZXJDaGFuZ2VkLFxuICAgICAgb2xkTGF5ZXJEYXRhLFxuICAgICAgZGF0YVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGRhdGEsXG4gICAgICBnZXRQb3NpdGlvbixcbiAgICAgIGdldEZpbGxDb2xvcixcbiAgICAgIGdldEZpbHRlclZhbHVlOiBncHVGaWx0ZXIuZmlsdGVyVmFsdWVBY2Nlc3NvcigpLFxuICAgICAgZ2V0UmFkaXVzLFxuICAgICAgdGV4dExhYmVsc1xuICAgIH07XG4gIH1cblxuICB1cGRhdGVMYXllck1ldGEoYWxsRGF0YSwgZ2V0UG9zaXRpb24pIHtcbiAgICBjb25zdCBib3VuZHMgPSB0aGlzLmdldFBvaW50c0JvdW5kcyhhbGxEYXRhLCBkID0+IGdldFBvc2l0aW9uKHtkYXRhOiBkfSkpO1xuICAgIHRoaXMudXBkYXRlTWV0YSh7Ym91bmRzfSk7XG4gIH1cblxuICByZW5kZXJMYXllcihvcHRzKSB7XG4gICAgY29uc3Qge2RhdGEsIGdwdUZpbHRlciwgb2JqZWN0SG92ZXJlZCwgbWFwU3RhdGUsIGludGVyYWN0aW9uQ29uZmlnfSA9IG9wdHM7XG5cbiAgICBjb25zdCByYWRpdXNTY2FsZSA9IHRoaXMuZ2V0UmFkaXVzU2NhbGVCeVpvb20obWFwU3RhdGUpO1xuXG4gICAgY29uc3QgbGF5ZXJQcm9wcyA9IHtcbiAgICAgIHJhZGl1c1NjYWxlLFxuICAgICAgLi4uKHRoaXMuY29uZmlnLnZpc0NvbmZpZy5maXhlZFJhZGl1cyA/IHt9IDoge3JhZGl1c01heFBpeGVsczogNTAwfSlcbiAgICB9O1xuXG4gICAgY29uc3QgdXBkYXRlVHJpZ2dlcnMgPSB7XG4gICAgICBnZXRGaWx0ZXJWYWx1ZTogZ3B1RmlsdGVyLmZpbHRlclZhbHVlVXBkYXRlVHJpZ2dlcnMsXG4gICAgICBnZXRSYWRpdXM6IHtcbiAgICAgICAgc2l6ZUZpZWxkOiB0aGlzLmNvbmZpZy5jb2xvckZpZWxkLFxuICAgICAgICByYWRpdXNSYW5nZTogdGhpcy5jb25maWcudmlzQ29uZmlnLnJhZGl1c1JhbmdlLFxuICAgICAgICBzaXplU2NhbGU6IHRoaXMuY29uZmlnLnNpemVTY2FsZVxuICAgICAgfSxcbiAgICAgIGdldEZpbGxDb2xvcjoge1xuICAgICAgICBjb2xvcjogdGhpcy5jb25maWcuY29sb3IsXG4gICAgICAgIGNvbG9yRmllbGQ6IHRoaXMuY29uZmlnLmNvbG9yRmllbGQsXG4gICAgICAgIGNvbG9yUmFuZ2U6IHRoaXMuY29uZmlnLnZpc0NvbmZpZy5jb2xvclJhbmdlLFxuICAgICAgICBjb2xvclNjYWxlOiB0aGlzLmNvbmZpZy5jb2xvclNjYWxlXG4gICAgICB9XG4gICAgfTtcblxuICAgIGNvbnN0IGRlZmF1bHRMYXllclByb3BzID0gdGhpcy5nZXREZWZhdWx0RGVja0xheWVyUHJvcHMob3B0cyk7XG4gICAgY29uc3QgYnJ1c2hpbmdQcm9wcyA9IHRoaXMuZ2V0QnJ1c2hpbmdFeHRlbnNpb25Qcm9wcyhpbnRlcmFjdGlvbkNvbmZpZyk7XG4gICAgY29uc3QgZ2V0UGl4ZWxPZmZzZXQgPSBnZXRUZXh0T2Zmc2V0QnlSYWRpdXMocmFkaXVzU2NhbGUsIGRhdGEuZ2V0UmFkaXVzLCBtYXBTdGF0ZSk7XG4gICAgY29uc3QgZXh0ZW5zaW9ucyA9IFsuLi5kZWZhdWx0TGF5ZXJQcm9wcy5leHRlbnNpb25zLCBicnVzaGluZ0V4dGVuc2lvbl07XG5cbiAgICAvLyBzaGFyZWQgUHJvcHMgYmV0d2VlbiBsYXllciBhbmQgbGFiZWwgbGF5ZXJcbiAgICBjb25zdCBzaGFyZWRQcm9wcyA9IHtcbiAgICAgIGdldEZpbHRlclZhbHVlOiBkYXRhLmdldEZpbHRlclZhbHVlLFxuICAgICAgZXh0ZW5zaW9ucyxcbiAgICAgIGZpbHRlclJhbmdlOiBkZWZhdWx0TGF5ZXJQcm9wcy5maWx0ZXJSYW5nZSxcbiAgICAgIC4uLmJydXNoaW5nUHJvcHNcbiAgICB9O1xuXG4gICAgY29uc3QgbGFiZWxMYXllcnMgPSBbXG4gICAgICAuLi50aGlzLnJlbmRlclRleHRMYWJlbExheWVyKFxuICAgICAgICB7XG4gICAgICAgICAgZ2V0UG9zaXRpb246IGRhdGEuZ2V0UG9zaXRpb24sXG4gICAgICAgICAgc2hhcmVkUHJvcHMsXG4gICAgICAgICAgZ2V0UGl4ZWxPZmZzZXQsXG4gICAgICAgICAgdXBkYXRlVHJpZ2dlcnNcbiAgICAgICAgfSxcbiAgICAgICAgb3B0c1xuICAgICAgKVxuICAgIF07XG5cbiAgICByZXR1cm4gIXRoaXMuaWNvbkdlb21ldHJ5XG4gICAgICA/IFtdXG4gICAgICA6IFtcbiAgICAgICAgICBuZXcgU3ZnSWNvbkxheWVyKHtcbiAgICAgICAgICAgIC4uLmRlZmF1bHRMYXllclByb3BzLFxuICAgICAgICAgICAgLi4uYnJ1c2hpbmdQcm9wcyxcbiAgICAgICAgICAgIC4uLmxheWVyUHJvcHMsXG4gICAgICAgICAgICAuLi5kYXRhLFxuICAgICAgICAgICAgZ2V0SWNvbkdlb21ldHJ5OiBpZCA9PiB0aGlzLmljb25HZW9tZXRyeVtpZF0sXG5cbiAgICAgICAgICAgIC8vIHVwZGF0ZSB0cmlnZ2Vyc1xuICAgICAgICAgICAgdXBkYXRlVHJpZ2dlcnMsXG4gICAgICAgICAgICBleHRlbnNpb25zXG4gICAgICAgICAgfSksXG5cbiAgICAgICAgICAuLi4odGhpcy5pc0xheWVySG92ZXJlZChvYmplY3RIb3ZlcmVkKVxuICAgICAgICAgICAgPyBbXG4gICAgICAgICAgICAgICAgbmV3IFN2Z0ljb25MYXllcih7XG4gICAgICAgICAgICAgICAgICAuLi50aGlzLmdldERlZmF1bHRIb3ZlckxheWVyUHJvcHMoKSxcbiAgICAgICAgICAgICAgICAgIC4uLmxheWVyUHJvcHMsXG4gICAgICAgICAgICAgICAgICBkYXRhOiBbb2JqZWN0SG92ZXJlZC5vYmplY3RdLFxuICAgICAgICAgICAgICAgICAgZ2V0UG9zaXRpb246IGRhdGEuZ2V0UG9zaXRpb24sXG4gICAgICAgICAgICAgICAgICBnZXRSYWRpdXM6IGRhdGEuZ2V0UmFkaXVzLFxuICAgICAgICAgICAgICAgICAgZ2V0RmlsbENvbG9yOiB0aGlzLmNvbmZpZy5oaWdobGlnaHRDb2xvcixcbiAgICAgICAgICAgICAgICAgIGdldEljb25HZW9tZXRyeTogaWQgPT4gdGhpcy5pY29uR2VvbWV0cnlbaWRdXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgOiBbXSksXG5cbiAgICAgICAgICAvLyB0ZXh0IGxhYmVsIGxheWVyXG4gICAgICAgICAgLi4ubGFiZWxMYXllcnNcbiAgICAgICAgXTtcbiAgfVxufVxuIl19