UNPKG

kepler.gl.geoiq

Version:

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

300 lines (257 loc) 32.3 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.pointPosResolver = exports.pointPosAccessor = exports.getValueAggr = exports["default"] = exports.aggregateRequiredColumns = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); 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 _get2 = _interopRequireDefault(require("@babel/runtime/helpers/get")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _lodash = _interopRequireDefault(require("lodash.memoize")); var _baseLayer = _interopRequireDefault(require("./base-layer")); var _colorUtils = require("../utils/color-utils"); var _aggregateUtils = require("../utils/aggregate-utils"); var _defaultSettings = require("../constants/default-settings"); 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 _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } var pointPosAccessor = exports.pointPosAccessor = function pointPosAccessor(_ref) { var lat = _ref.lat, lng = _ref.lng; return function (d) { return [d[lng.fieldIdx], d[lat.fieldIdx]]; }; }; var pointPosResolver = exports.pointPosResolver = function pointPosResolver(_ref2) { var lat = _ref2.lat, lng = _ref2.lng; return "".concat(lat.fieldIdx, "-").concat(lng.fieldIdx); }; var getValueAggr = exports.getValueAggr = function getValueAggr(field, aggregation) { return function (points) { return (0, _aggregateUtils.aggregate)(points.map(function (p) { return p[field.tableFieldIndex - 1]; }), aggregation); }; }; var aggrResolver = function aggrResolver(field, aggregation) { return "".concat(field.name, "-").concat(aggregation); }; var getLayerColorRange = function getLayerColorRange(colorRange) { return colorRange.colors.map(_colorUtils.hexToRgb); }; var aggregateRequiredColumns = exports.aggregateRequiredColumns = ['lat', 'lng']; var AggregationLayer = exports["default"] = /*#__PURE__*/function (_Layer) { (0, _inherits2["default"])(AggregationLayer, _Layer); var _super = _createSuper(AggregationLayer); function AggregationLayer(props) { var _this; (0, _classCallCheck2["default"])(this, AggregationLayer); _this = _super.call(this, props); _this.getPosition = (0, _lodash["default"])(pointPosAccessor, pointPosResolver); _this.getColorValue = (0, _lodash["default"])(getValueAggr, aggrResolver); _this.getColorRange = (0, _lodash["default"])(getLayerColorRange); _this.getElevationValue = (0, _lodash["default"])(getValueAggr, aggrResolver); return _this; } (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"])((0, _get2["default"])((0, _getPrototypeOf2["default"])(AggregationLayer.prototype), "noneLayerDataAffectingProps", this)), ['enable3d', 'colorRange', 'colorScale', 'colorDomain', 'sizeRange', 'sizeScale', 'sizeDomain', 'percentile', 'coverage', 'elevationPercentile', 'elevationScale']); } }, { key: "visualChannels", get: function get() { return { color: { aggregation: 'colorAggregation', channelScaleType: _defaultSettings.CHANNEL_SCALES.colorAggr, defaultMeasure: 'Point Count', domain: 'colorDomain', field: 'colorField', key: 'color', property: 'color', range: 'colorRange', scale: 'colorScale' }, size: { aggregation: 'sizeAggregation', channelScaleType: _defaultSettings.CHANNEL_SCALES.sizeAggr, condition: function condition(config) { return config.visConfig.enable3d; }, defaultMeasure: 'Point Count', domain: 'sizeDomain', field: 'sizeField', key: 'size', property: 'height', range: 'sizeRange', scale: 'sizeScale' } }; } /** * Get the description of a visualChannel config * @param key * @returns {{label: string, measure: (string|string)}} */ }, { key: "getVisualChannelDescription", value: function getVisualChannelDescription(key) { // e.g. label: Color, measure: Average of ETA var _this$visualChannels$ = this.visualChannels[key], range = _this$visualChannels$.range, field = _this$visualChannels$.field, defaultMeasure = _this$visualChannels$.defaultMeasure, aggregation = _this$visualChannels$.aggregation; return { label: this.visConfigSettings[range].label, measure: this.config[field] ? "".concat(this.config.visConfig[aggregation], " of ").concat(this.config[field].name) : defaultMeasure }; } }, { key: "getHoverData", value: function getHoverData(object) { // return aggregated object return object; } /** * Aggregation layer handles visual channel aggregation inside deck.gl layer */ }, { key: "updateLayerVisualChannel", value: function updateLayerVisualChannel(_ref3, channel) { var data = _ref3.data, allData = _ref3.allData; 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])); } } }, { key: "getAggregationOptions", value: function getAggregationOptions(channel) { var visualChannel = this.visualChannels[channel]; var field = visualChannel.field, channelScaleType = visualChannel.channelScaleType; return Object.keys(this.config[field] ? _defaultSettings.FIELD_OPTS[this.config[field].type].scale[channelScaleType] : _defaultSettings.DEFAULT_AGGREGATION[channelScaleType]); } /** * Get scale options based on current field and aggregation type * @param {string} channel * @returns {string[]} */ }, { key: "getScaleOptions", value: function getScaleOptions(channel) { var visualChannel = this.visualChannels[channel]; var field = visualChannel.field, aggregation = visualChannel.aggregation, channelScaleType = visualChannel.channelScaleType; var aggregationType = this.config.visConfig[aggregation]; return this.config[field] ? // scale options based on aggregation _defaultSettings.FIELD_OPTS[this.config[field].type].scale[channelScaleType][aggregationType] : // default scale options for point count _defaultSettings.DEFAULT_AGGREGATION[channelScaleType][aggregationType]; } /** * Aggregation layer handles visual channel aggregation inside deck.gl layer */ }, { key: "updateLayerDomain", value: function updateLayerDomain(dataset, newFilter) { return this; } }, { key: "updateLayerMeta", value: function updateLayerMeta(allData, getPosition) { // get bounds from points var bounds = this.getPointsBounds(allData, getPosition); // get lightSettings from points var lightSettings = this.getLightSettingsFromBounds(bounds); this.updateMeta({ bounds: bounds, lightSettings: lightSettings }); } }, { key: "formatLayerData", value: function formatLayerData(_, allData, filteredIndex, oldLayerData) { var opt = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; var getPosition = this.getPosition(this.config.columns); if (!oldLayerData || oldLayerData.getPosition !== getPosition) { this.updateLayerMeta(allData, getPosition); } var getColorValue = this.config.colorField ? this.getColorValue(this.config.colorField, this.config.visConfig.colorAggregation) : undefined; var getElevationValue = this.config.sizeField ? this.getElevationValue(this.config.sizeField, this.config.visConfig.sizeAggregation) : undefined; var data; if (oldLayerData && oldLayerData.data && opt.sameData && oldLayerData.getPosition === getPosition) { data = oldLayerData.data; } else { data = filteredIndex.map(function (i) { return allData[i]; }); } return _objectSpread(_objectSpread({ data: data, getPosition: getPosition }, getColorValue ? { getColorValue: getColorValue } : {}), getElevationValue ? { getElevationValue: getElevationValue } : {}); } }]); return AggregationLayer; }(_baseLayer["default"]); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93aWRnZXRzL2FnZ3JlZ2F0aW9uLWxheWVyLmpzIl0sIm5hbWVzIjpbInBvaW50UG9zQWNjZXNzb3IiLCJsYXQiLCJsbmciLCJkIiwiZmllbGRJZHgiLCJwb2ludFBvc1Jlc29sdmVyIiwiZ2V0VmFsdWVBZ2dyIiwiZmllbGQiLCJhZ2dyZWdhdGlvbiIsInBvaW50cyIsIm1hcCIsInAiLCJ0YWJsZUZpZWxkSW5kZXgiLCJhZ2dyUmVzb2x2ZXIiLCJuYW1lIiwiZ2V0TGF5ZXJDb2xvclJhbmdlIiwiY29sb3JSYW5nZSIsImNvbG9ycyIsImhleFRvUmdiIiwiYWdncmVnYXRlUmVxdWlyZWRDb2x1bW5zIiwiQWdncmVnYXRpb25MYXllciIsInByb3BzIiwiZ2V0UG9zaXRpb24iLCJnZXRDb2xvclZhbHVlIiwiZ2V0Q29sb3JSYW5nZSIsImdldEVsZXZhdGlvblZhbHVlIiwiZGVmYXVsdFBvaW50Q29sdW1uUGFpcnMiLCJjb2xvciIsImNoYW5uZWxTY2FsZVR5cGUiLCJDSEFOTkVMX1NDQUxFUyIsImNvbG9yQWdnciIsImRlZmF1bHRNZWFzdXJlIiwiZG9tYWluIiwia2V5IiwicHJvcGVydHkiLCJyYW5nZSIsInNjYWxlIiwic2l6ZSIsInNpemVBZ2dyIiwiY29uZGl0aW9uIiwiY29uZmlnIiwidmlzQ29uZmlnIiwiZW5hYmxlM2QiLCJ2aXN1YWxDaGFubmVscyIsImxhYmVsIiwidmlzQ29uZmlnU2V0dGluZ3MiLCJtZWFzdXJlIiwib2JqZWN0IiwiY2hhbm5lbCIsImRhdGEiLCJhbGxEYXRhIiwidmFsaWRhdGVWaXN1YWxDaGFubmVsIiwidmFsaWRhdGVGaWVsZFR5cGUiLCJ2YWxpZGF0ZUFnZ3JlZ2F0aW9uVHlwZSIsInZhbGlkYXRlU2NhbGUiLCJ2aXN1YWxDaGFubmVsIiwiYWdncmVnYXRpb25PcHRpb25zIiwiZ2V0QWdncmVnYXRpb25PcHRpb25zIiwibGVuZ3RoIiwidXBkYXRlTGF5ZXJDb25maWciLCJpbmNsdWRlcyIsInVwZGF0ZUxheWVyVmlzQ29uZmlnIiwiT2JqZWN0Iiwia2V5cyIsIkZJRUxEX09QVFMiLCJ0eXBlIiwiREVGQVVMVF9BR0dSRUdBVElPTiIsImFnZ3JlZ2F0aW9uVHlwZSIsImRhdGFzZXQiLCJuZXdGaWx0ZXIiLCJib3VuZHMiLCJnZXRQb2ludHNCb3VuZHMiLCJsaWdodFNldHRpbmdzIiwiZ2V0TGlnaHRTZXR0aW5nc0Zyb21Cb3VuZHMiLCJ1cGRhdGVNZXRhIiwiXyIsImZpbHRlcmVkSW5kZXgiLCJvbGRMYXllckRhdGEiLCJvcHQiLCJjb2x1bW5zIiwidXBkYXRlTGF5ZXJNZXRhIiwiY29sb3JGaWVsZCIsImNvbG9yQWdncmVnYXRpb24iLCJ1bmRlZmluZWQiLCJzaXplRmllbGQiLCJzaXplQWdncmVnYXRpb24iLCJzYW1lRGF0YSIsImkiLCJMYXllciJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQW9CQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7Ozs7Ozs7OztBQUVPLElBQU1BLGdCQUFnQiw4QkFBRyxTQUFuQkEsZ0JBQW1CO0FBQUEsTUFBRUMsR0FBRixRQUFFQSxHQUFGO0FBQUEsTUFBT0MsR0FBUCxRQUFPQSxHQUFQO0FBQUEsU0FBZ0IsVUFBQUMsQ0FBQztBQUFBLFdBQUksQ0FDbkRBLENBQUMsQ0FBQ0QsR0FBRyxDQUFDRSxRQUFMLENBRGtELEVBRW5ERCxDQUFDLENBQUNGLEdBQUcsQ0FBQ0csUUFBTCxDQUZrRCxDQUFKO0FBQUEsR0FBakI7QUFBQSxDQUF6Qjs7QUFLQSxJQUFNQyxnQkFBZ0IsOEJBQUcsU0FBbkJBLGdCQUFtQjtBQUFBLE1BQUVKLEdBQUYsU0FBRUEsR0FBRjtBQUFBLE1BQU9DLEdBQVAsU0FBT0EsR0FBUDtBQUFBLG1CQUMzQkQsR0FBRyxDQUFDRyxRQUR1QixjQUNYRixHQUFHLENBQUNFLFFBRE87QUFBQSxDQUF6Qjs7QUFHQSxJQUFNRSxZQUFZLDBCQUFHLFNBQWZBLFlBQWUsQ0FBQ0MsS0FBRCxFQUFRQyxXQUFSO0FBQUEsU0FBd0IsVUFBQUMs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aUIsTUFBTCxDQUFZeUMsVUFEZCxFQUVFLEtBQUt6QyxNQUFMLENBQVlDLFNBQVosQ0FBc0J5QyxnQkFGeEIsQ0FEa0IsR0FLbEJDLFNBTEo7QUFPQSxVQUFNMUQsaUJBQWlCLEdBQUcsS0FBS2UsTUFBTCxDQUFZNEMsU0FBWixHQUN0QixLQUFLM0QsaUJBQUwsQ0FDRSxLQUFLZSxNQUFMLENBQVk0QyxTQURkLEVBRUUsS0FBSzVDLE1BQUwsQ0FBWUMsU0FBWixDQUFzQjRDLGVBRnhCLENBRHNCLEdBS3RCRixTQUxKO0FBT0EsVUFBSWxDLElBQUo7O0FBQ0EsVUFDRTRCLFlBQVksSUFDWkEsWUFBWSxDQUFDNUIsSUFEYixJQUVBNkIsR0FBRyxDQUFDUSxRQUZKLElBR0FULFlBQVksQ0FBQ3ZELFdBQWIsS0FBNkJBLFdBSi9CLEVBS0U7QUFDQTJCLFFBQUFBLElBQUksR0FBRzRCLFlBQVksQ0FBQzVCLElBQXBCO0FBQ0QsT0FQRCxNQU9PO0FBQ0xBLFFBQUFBLElBQUksR0FBRzJCLGFBQWEsQ0FBQ2xFLEdBQWQsQ0FBa0IsVUFBQTZFLENBQUM7QUFBQSxpQkFBSXJDLE9BQU8sQ0FBQ3FDLENBQUQsQ0FBWDtBQUFBLFNBQW5CLENBQVA7QUFDRDs7QUFFRDtBQUNFdEMsUUFBQUEsSUFBSSxFQUFKQSxJQURGO0FBRUUzQixRQUFBQSxXQUFXLEVBQVhBO0FBRkYsU0FHTUMsYUFBYSxHQUFHO0FBQUNBLFFBQUFBLGFBQWEsRUFBYkE7QUFBRCxPQUFILEdBQXFCLEVBSHhDLEdBSU1FLGlCQUFpQixHQUFHO0FBQUNBLFFBQUFBLGlCQUFpQixFQUFqQkE7QUFBRCxPQUFILEdBQXlCLEVBSmhEO0FBTUQ7OztFQW5OMkMrRCxxQiIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAoYykgMjAyMyBVYmVyIFRlY2hub2xvZ2llcywgSW5jLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvIGRlYWxcbi8vIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHNcbi8vIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGxcbi8vIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcbi8vXG4vLyBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpblxuLy8gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEVcbi8vIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOXG4vLyBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCBtZW1vaXplIGZyb20gJ2xvZGFzaC5tZW1vaXplJztcbmltcG9ydCBMYXllciBmcm9tICcuL2Jhc2UtbGF5ZXInO1xuaW1wb3J0IHtoZXhUb1JnYn0gZnJvbSAndXRpbHMvY29sb3ItdXRpbHMnO1xuaW1wb3J0IHthZ2dyZWdhdGV9IGZyb20gJ3V0aWxzL2FnZ3JlZ2F0ZS11dGlscyc7XG5pbXBvcnQge0NIQU5ORUxfU0NBTEVTLCBGSUVMRF9PUFRTLCBERUZBVUxUX0FHR1JFR0FUSU9OfSBmcm9tICdjb25zdGFudHMvZGVmYXVsdC1zZXR0aW5ncyc7XG5cbmV4cG9ydCBjb25zdCBwb2ludFBvc0FjY2Vzc29yID0gKHtsYXQsIGxuZ30pID0+IGQgPT4gW1xuICBkW2xuZy5maWVsZElkeF0sXG4gIGRbbGF0LmZpZWxkSWR4XVxuXTtcblxuZXhwb3J0IGNvbnN0IHBvaW50UG9zUmVzb2x2ZXIgPSAoe2xhdCwgbG5nfSkgPT5cbiAgYCR7bGF0LmZpZWxkSWR4fS0ke2xuZy5maWVsZElkeH1gO1xuXG5leHBvcnQgY29uc3QgZ2V0VmFsdWVBZ2dyID0gKGZpZWxkLCBhZ2dyZWdhdGlvbikgPT4gcG9pbnRzID0+XG4gIGFnZ3JlZ2F0ZShwb2ludHMubWFwKHAgPT4gcFtmaWVsZC50YWJsZUZpZWxkSW5kZXggLSAxXSksIGFnZ3JlZ2F0aW9uKTtcblxuY29uc3QgYWdnclJlc29sdmVyID0gKGZpZWxkLCBhZ2dyZWdhdGlvbikgPT4gYCR7ZmllbGQubmFtZX0tJHthZ2dyZWdhdGlvbn1gO1xuXG5jb25zdCBnZXRMYXllckNvbG9yUmFuZ2UgPSBjb2xvclJhbmdlID0+IGNvbG9yUmFuZ2UuY29sb3JzLm1hcChoZXhUb1JnYik7XG5cbmV4cG9ydCBjb25zdCBhZ2dyZWdhdGVSZXF1aXJlZENvbHVtbnMgPSBbJ2xhdCcsICdsbmcnXTtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQWdncmVnYXRpb25MYXllciBleHRlbmRzIExheWVyIHtcbiAgY29uc3RydWN0b3IocHJvcHMpIHtcbiAgICBzdXBlcihwcm9wcyk7XG5cbiAgICB0aGlzLmdldFBvc2l0aW9uID0gbWVtb2l6ZShwb2ludFBvc0FjY2Vzc29yLCBwb2ludFBvc1Jlc29sdmVyKTtcbiAgICB0aGlzLmdldENvbG9yVmFsdWUgPSBtZW1vaXplKGdldFZhbHVlQWdnciwgYWdnclJlc29sdmVyKTtcbiAgICB0aGlzLmdldENvbG9yUmFuZ2UgPSBtZW1vaXplKGdldExheWVyQ29sb3JSYW5nZSk7XG4gICAgdGhpcy5nZXRFbGV2YXRpb25WYWx1ZSA9IG1lbW9pemUoZ2V0VmFsdWVBZ2dyLCBhZ2dyUmVzb2x2ZXIpO1xuICB9XG5cbiAgZ2V0IGlzQWdncmVnYXRlZCgpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIGdldCByZXF1aXJlZExheWVyQ29sdW1ucygpIHtcbiAgICByZXR1cm4gYWdncmVnYXRlUmVxdWlyZWRDb2x1bW5zO1xuICB9XG5cbiAgZ2V0IGNvbHVtblBhaXJzKCkge1xuICAgIHJldHVybiB0aGlzLmRlZmF1bHRQb2ludENvbHVtblBhaXJzO1xuICB9XG5cbiAgZ2V0IG5vbmVMYXllckRhdGFBZmZlY3RpbmdQcm9wcygpIHtcbiAgICByZXR1cm4gW1xuICAgICAgLi4uc3VwZXIubm9uZUxheWVyRGF0YUFmZmVjdGluZ1Byb3BzLFxuICAgICAgJ2VuYWJsZTNkJyxcbiAgICAgICdjb2xvclJhbmdlJyxcbiAgICAgICdjb2xvclNjYWxlJyxcbiAgICAgICdjb2xvckRvbWFpbicsXG4gICAgICAnc2l6ZVJhbmdlJyxcbiAgICAgICdzaXplU2NhbGUnLFxuICAgICAgJ3NpemVEb21haW4nLFxuICAgICAgJ3BlcmNlbnRpbGUnLFxuICAgICAgJ2NvdmVyYWdlJyxcbiAgICAgICdlbGV2YXRpb25QZXJjZW50aWxlJyxcbiAgICAgICdlbGV2YXRpb25TY2FsZSdcbiAgICBdO1xuICB9XG5cbiAgZ2V0IHZpc3VhbENoYW5uZWxzKCkge1xuICAgIHJldHVybiB7XG4gICAgICBjb2xvcjoge1xuICAgICAgICBhZ2dyZWdhdGlvbjogJ2NvbG9yQWdncmVnYXRpb24nLFxuICAgICAgICBjaGFubmVsU2NhbGVUeXBlOiBDSEFOTkVMX1NDQUxFUy5jb2xvckFnZ3IsXG4gICAgICAgIGRlZmF1bHRNZWFzdXJlOiAnUG9pbnQgQ291bnQnLFxuICAgICAgICBkb21haW46ICdjb2xvckRvbWFpbicsXG4gICAgICAgIGZpZWxkOiAnY29sb3JGaWVsZCcsXG4gICAgICAgIGtleTogJ2NvbG9yJyxcbiAgICAgICAgcHJvcGVydHk6ICdjb2xvcicsXG4gICAgICAgIHJhbmdlOiAnY29sb3JSYW5nZScsXG4gICAgICAgIHNjYWxlOiAnY29sb3JTY2FsZSdcbiAgICAgIH0sXG4gICAgICBzaXplOiB7XG4gICAgICAgIGFnZ3JlZ2F0aW9uOiAnc2l6ZUFnZ3JlZ2F0aW9uJyxcbiAgICAgICAgY2hhbm5lbFNjYWxlVHlwZTogQ0hBTk5FTF9TQ0FMRVMuc2l6ZUFnZ3IsXG4gICAgICAgIGNvbmRpdGlvbjogY29uZmlnID0+IGNvbmZpZy52aXNDb25maWcuZW5hYmxlM2QsXG4gICAgICAgIGRlZmF1bHRNZWFzdXJlOiAnUG9pbnQgQ291bnQnLFxuICAgICAgICBkb21haW46ICdzaXplRG9tYWluJyxcbiAgICAgICAgZmllbGQ6ICdzaXplRmllbGQnLFxuICAgICAgICBrZXk6ICdzaXplJyxcbiAgICAgICAgcHJvcGVydHk6ICdoZWlnaHQnLFxuICAgICAgICByYW5nZTogJ3NpemVSYW5nZScsXG4gICAgICAgIHNjYWxlOiAnc2l6ZVNjYWxlJ1xuICAgICAgfVxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBkZXNjcmlwdGlvbiBvZiBhIHZpc3VhbENoYW5uZWwgY29uZmlnXG4gICAqIEBwYXJhbSBrZXlcbiAgICogQHJldHVybnMge3tsYWJlbDogc3RyaW5nLCBtZWFzdXJlOiAoc3RyaW5nfHN0cmluZyl9fVxuICAgKi9cbiAgZ2V0VmlzdWFsQ2hhbm5lbERlc2NyaXB0aW9uKGtleSkge1xuICAgIC8vIGUuZy4gbGFiZWw6IENvbG9yLCBtZWFzdXJlOiBBdmVyYWdlIG9mIEVUQVxuICAgIGNvbnN0IHtyYW5nZSwgZmllbGQsIGRlZmF1bHRNZWFzdXJlLCBhZ2dyZWdhdGlvbn0gPSB0aGlzLnZpc3VhbENoYW5uZWxzW2tleV07XG4gICAgcmV0dXJuIHtcbiAgICAgIGxhYmVsOiB0aGlzLnZpc0NvbmZpZ1NldHRpbmdzW3JhbmdlXS5sYWJlbCxcbiAgICAgIG1lYXN1cmU6IHRoaXMuY29uZmlnW2ZpZWxkXVxuICAgICAgICA/IGAke3RoaXMuY29uZmlnLnZpc0NvbmZpZ1thZ2dyZWdhdGlvbl19IG9mICR7dGhpcy5jb25maWdbZmllbGRdLm5hbWV9YFxuICAgICAgICA6IGRlZmF1bHRNZWFzdXJlXG4gICAgfVxuICB9XG5cbiAgZ2V0SG92ZXJEYXRhKG9iamVjdCkge1xuICAgIC8vIHJldHVybiBhZ2dyZWdhdGVkIG9iamVjdFxuICAgIHJldHVybiBvYmplY3Q7XG4gIH1cblxuICAvKipcbiAgICogQWdncmVnYXRpb24gbGF5ZXIgaGFuZGxlcyB2aXN1YWwgY2hhbm5lbCBhZ2dyZWdhdGlvbiBpbnNpZGUgZGVjay5nbCBsYXllclxuICAgKi9cbiAgdXBkYXRlTGF5ZXJWaXN1YWxDaGFubmVsKHtkYXRhLCBhbGxEYXRhfSwgY2hhbm5lbCkge1xuICAgIHRoaXMudmFsaWRhdGVWaXN1YWxDaGFubmVsKGNoYW5uZWwpO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGFnZ3JlZ2F0aW9uIHR5cGUgb24gdG9wIG9mIGJhc2ljIGxheWVyIHZpc3VhbCBjaGFubmVsIHZhbGlkYXRpb25cbiAgICogQHBhcmFtIGNoYW5uZWxcbiAgICovXG4gIHZhbGlkYXRlVmlzdWFsQ2hhbm5lbChjaGFubmVsKSB7XG5cbiAgICAvLyBmaWVsZCB0eXBlIGRlY2lkZXMgYWdncmVnYXRpb24gdHlwZSBkZWNpZGVzIHNjYWxlIHR5cGVcbiAgICB0aGlzLnZhbGlkYXRlRmllbGRUeXBlKGNoYW5uZWwpO1xuICAgIHRoaXMudmFsaWRhdGVBZ2dyZWdhdGlvblR5cGUoY2hhbm5lbCk7XG4gICAgdGhpcy52YWxpZGF0ZVNjYWxlKGNoYW5uZWwpO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGFnZ3JlZ2F0aW9uIHR5cGUgYmFzZWQgb24gc2VsZWN0ZWQgZmllbGRcbiAgICovXG4gIHZhbGlkYXRlQWdncmVnYXRpb25UeXBlKGNoYW5uZWwpIHtcbiAgICBjb25zdCB2aXN1YWxDaGFubmVsID0gdGhpcy52aXN1YWxDaGFubmVsc1tjaGFubmVsXTtcbiAgICBjb25zdCB7ZmllbGQsIGFnZ3JlZ2F0aW9ufSA9IHZpc3VhbENoYW5uZWw7XG4gICAgY29uc3QgYWdncmVnYXRpb25PcHRpb25zID0gdGhpcy5nZXRBZ2dyZWdhdGlvbk9wdGlvbnMoY2hhbm5lbCk7XG5cbiAgICBpZiAoIWFnZ3JlZ2F0aW9uKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCFhZ2dyZWdhdGlvbk9wdGlvbnMubGVuZ3RoKSB7XG4gICAgICAvLyBpZiBmaWVsZCBjYW5ub3QgYmUgYWdncmVnYXRlZCwgc2V0IGZpZWxkIHRvIG51bGxcbiAgICAgIHRoaXMudXBkYXRlTGF5ZXJDb25maWcoe1tmaWVsZF06IG51bGx9KTtcblxuICAgIH0gZWxzZSBpZiAoIWFnZ3JlZ2F0aW9uT3B0aW9ucy5pbmNsdWRlcyh0aGlzLmNvbmZpZy52aXNDb25maWdbYWdncmVnYXRpb25dKSkge1xuICAgICAgLy8gY3VycmVudCBhZ2dyZWdhdGlvbiB0eXBlIGlzIG5vdCBzdXBwb3J0ZWQgYnkgdGhpcyBmaWVsZFxuICAgICAgLy8gc2V0IGFnZ3JlZ2F0aW9uIHRvIHRoZSBmaXJzdCBzdXBwb3J0ZWQgb3B0aW9uXG4gICAgICB0aGlzLnVwZGF0ZUxheWVyVmlzQ29uZmlnKHtbYWdncmVnYXRpb25dOiBhZ2dyZWdhdGlvbk9wdGlvbnNbMF19KTtcbiAgICB9XG4gIH1cblxuICBnZXRBZ2dyZWdhdGlvbk9wdGlvbnMoY2hhbm5lbCkge1xuICAgIGNvbnN0IHZpc3VhbENoYW5uZWwgPSB0aGlzLnZpc3VhbENoYW5uZWxzW2NoYW5uZWxdO1xuICAgIGNvbnN0IHtmaWVsZCwgY2hhbm5lbFNjYWxlVHlwZX0gPSB2aXN1YWxDaGFubmVsO1xuXG4gICAgcmV0dXJuIE9iamVjdC5rZXlzKFxuICAgICAgdGhpcy5jb25maWdbZmllbGRdID8gRklFTERfT1BUU1t0aGlzLmNvbmZpZ1tmaWVsZF0udHlwZV0uc2NhbGVbY2hhbm5lbFNjYWxlVHlwZV0gOlxuICAgICAgICBERUZBVUxUX0FHR1JFR0FUSU9OW2NoYW5uZWxTY2FsZVR5cGVdKVxuICB9XG5cbiAgLyoqXG4gICAqIEdldCBzY2FsZSBvcHRpb25zIGJhc2VkIG9uIGN1cnJlbnQgZmllbGQgYW5kIGFnZ3JlZ2F0aW9uIHR5cGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNoYW5uZWxcbiAgICogQHJldHVybnMge3N0cmluZ1tdfVxuICAgKi9cbiAgZ2V0U2NhbGVPcHRpb25zKGNoYW5uZWwpIHtcbiAgICBjb25zdCB2aXN1YWxDaGFubmVsID0gdGhpcy52aXN1YWxDaGFubmVsc1tjaGFubmVsXTtcbiAgICBjb25zdCB7ZmllbGQsIGFnZ3JlZ2F0aW9uLCBjaGFubmVsU2NhbGVUeXBlfSA9IHZpc3VhbENoYW5uZWw7XG4gICAgY29uc3QgYWdncmVnYXRpb25UeXBlID0gdGhpcy5jb25maWcudmlzQ29uZmlnW2FnZ3JlZ2F0aW9uXTtcbiAgICByZXR1cm4gdGhpcy5jb25maWdbZmllbGRdID9cbiAgICAgIC8vIHNjYWxlIG9wdGlvbnMgYmFzZWQgb24gYWdncmVnYXRpb25cbiAgICAgIEZJRUxEX09QVFNbdGhpcy5jb25maWdbZmllbGRdLnR5cGVdLnNjYWxlW2NoYW5uZWxTY2FsZVR5cGVdW2FnZ3JlZ2F0aW9uVHlwZV0gOlxuICAgICAgLy8gZGVmYXVsdCBzY2FsZSBvcHRpb25zIGZvciBwb2ludCBjb3VudFxuICAgICAgREVGQVVMVF9BR0dSRUdBVElPTltjaGFubmVsU2NhbGVUeXBlXVthZ2dyZWdhdGlvblR5cGVdO1xuICB9XG5cbiAgLyoqXG4gICAqIEFnZ3JlZ2F0aW9uIGxheWVyIGhhbmRsZXMgdmlzdWFsIGNoYW5uZWwgYWdncmVnYXRpb24gaW5zaWRlIGRlY2suZ2wgbGF5ZXJcbiAgICovXG4gIHVwZGF0ZUxheWVyRG9tYWluKGRhdGFzZXQsIG5ld0ZpbHRlcikge1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgdXBkYXRlTGF5ZXJNZXRhKGFsbERhdGEsIGdldFBvc2l0aW9uKSB7XG4gICAgLy8gZ2V0IGJvdW5kcyBmcm9tIHBvaW50c1xuICAgIGNvbnN0IGJvdW5kcyA9IHRoaXMuZ2V0UG9pbnRzQm91bmRzKGFsbERhdGEsIGdldFBvc2l0aW9uKTtcblxuICAgIC8vIGdldCBsaWdodFNldHRpbmdzIGZyb20gcG9pbnRzXG4gICAgY29uc3QgbGlnaHRTZXR0aW5ncyA9IHRoaXMuZ2V0TGlnaHRTZXR0aW5nc0Zyb21Cb3VuZHMoYm91bmRzKTtcblxuICAgIHRoaXMudXBkYXRlTWV0YSh7Ym91bmRzLCBsaWdodFNldHRpbmdzfSk7XG4gIH1cblxuICBmb3JtYXRMYXllckRhdGEoXywgYWxsRGF0YSwgZmlsdGVyZWRJbmRleCwgb2xkTGF5ZXJEYXRhLCBvcHQgPSB7fSkge1xuICAgIGNvbnN0IGdldFBvc2l0aW9uID0gdGhpcy5nZXRQb3NpdGlvbih0aGlzLmNvbmZpZy5jb2x1bW5zKTtcblxuICAgIGlmICghb2xkTGF5ZXJEYXRhIHx8IG9sZExheWVyRGF0YS5nZXRQb3NpdGlvbiAhPT0gZ2V0UG9zaXRpb24pIHtcbiAgICAgIHRoaXMudXBkYXRlTGF5ZXJNZXRhKGFsbERhdGEsIGdldFBvc2l0aW9uKTtcbiAgICB9XG5cbiAgICBjb25zdCBnZXRDb2xvclZhbHVlID0gdGhpcy5jb25maWcuY29sb3JGaWVsZFxuICAgICAgPyB0aGlzLmdldENvbG9yVmFsdWUoXG4gICAgICAgICAgdGhpcy5jb25maWcuY29sb3JGaWVsZCxcbiAgICAgICAgICB0aGlzLmNvbmZpZy52aXNDb25maWcuY29sb3JBZ2dyZWdhdGlvblxuICAgICAgICApXG4gICAgICA6IHVuZGVmaW5lZDtcblxuICAgIGNvbnN0IGdldEVsZXZhdGlvblZhbHVlID0gdGhpcy5jb25maWcuc2l6ZUZpZWxkXG4gICAgICA/IHRoaXMuZ2V0RWxldmF0aW9uVmFsdWUoXG4gICAgICAgICAgdGhpcy5jb25maWcuc2l6ZUZpZWxkLFxuICAgICAgICAgIHRoaXMuY29uZmlnLnZpc0NvbmZpZy5zaXplQWdncmVnYXRpb25cbiAgICAgICAgKVxuICAgICAgOiB1bmRlZmluZWQ7XG5cbiAgICBsZXQgZGF0YTtcbiAgICBpZiAoXG4gICAgICBvbGRMYXllckRhdGEgJiZcbiAgICAgIG9sZExheWVyRGF0YS5kYXRhICYmXG4gICAgICBvcHQuc2FtZURhdGEgJiZcbiAgICAgIG9sZExheWVyRGF0YS5nZXRQb3NpdGlvbiA9PT0gZ2V0UG9zaXRpb25cbiAgICApIHtcbiAgICAgIGRhdGEgPSBvbGRMYXllckRhdGEuZGF0YTtcbiAgICB9IGVsc2Uge1xuICAgICAgZGF0YSA9IGZpbHRlcmVkSW5kZXgubWFwKGkgPT4gYWxsRGF0YVtpXSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGRhdGEsXG4gICAgICBnZXRQb3NpdGlvbixcbiAgICAgIC4uLihnZXRDb2xvclZhbHVlID8ge2dldENvbG9yVmFsdWV9IDoge30pLFxuICAgICAgLi4uKGdldEVsZXZhdGlvblZhbHVlID8ge2dldEVsZXZhdGlvblZhbHVlfSA6IHt9KVxuICAgIH07XG4gIH1cbn1cbiJdfQ==