UNPKG

kepler.gl

Version:

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

348 lines (281 loc) 32.4 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = undefined; var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _deck = require('deck.gl'); var _geoViewport = require('@mapbox/geo-viewport'); var _geoViewport2 = _interopRequireDefault(_geoViewport); var _d3Array = require('d3-array'); var _dataScaleUtils = require('../../utils/data-scale-utils'); var _utils = require('../layer-utils/utils'); var _colorRanges = require('../../constants/color-ranges'); var _layerFactory = require('../../layers/layer-factory'); var _defaultSettings = require('../../constants/default-settings'); var _clusterUtils = require('../layer-utils/cluster-utils'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var defaultRadius = _layerFactory.LAYER_VIS_CONFIGS.clusterRadius.defaultValue; // Copyright (c) 2018 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. var defaultRadiusRange = _layerFactory.LAYER_VIS_CONFIGS.clusterRadiusRange.defaultValue; var defaultProps = { clusterRadius: defaultRadius, colorDomain: null, colorRange: _colorRanges.DefaultColorRange, colorScale: _defaultSettings.SCALE_TYPES.quantize, radiusRange: defaultRadiusRange, // maybe later... lowerPercentile: 0, upperPercentile: 100, getPosition: function getPosition(x) { return x.position; }, // if want to have color based on customized aggregator, instead of count getColorValue: function getColorValue(points) { return points.length; }, // if want to have radius based on customized aggregator, instead of count getRadiusValue: function getRadiusValue(cell) { return cell.properties.point_count; }, fp64: false }; var ClusterLayer = function (_CompositeLayer) { (0, _inherits3.default)(ClusterLayer, _CompositeLayer); function ClusterLayer() { (0, _classCallCheck3.default)(this, ClusterLayer); return (0, _possibleConstructorReturn3.default)(this, (ClusterLayer.__proto__ || Object.getPrototypeOf(ClusterLayer)).apply(this, arguments)); } (0, _createClass3.default)(ClusterLayer, [{ key: 'initializeState', value: function initializeState() { this.state = { clusters: null, geoJSON: null }; } }, { key: 'shouldUpdateState', value: function shouldUpdateState(_ref) { var changeFlags = _ref.changeFlags; return changeFlags.somethingChanged; } }, { key: 'updateState', value: function updateState(_ref2) { var context = _ref2.context, oldProps = _ref2.oldProps, props = _ref2.props, changeFlags = _ref2.changeFlags; if (changeFlags.dataChanged || this.needsReProjectPoints(oldProps, props)) { // project data into clusters, and get clustered data this.processGeoJSON(); this.getClusters(); // this needs clustered data to be set this.getColorValueDomain(); } else if (this.needsReclusterPoints(oldProps, props)) { this.getClusters(); this.getColorValueDomain(); } else if (this.needsRecalculateScaleFunction(oldProps, props)) { this.getColorValueDomain(); } } }, { key: 'needsReProjectPoints', value: function needsReProjectPoints(oldProps, props) { return oldProps.clusterRadius !== props.clusterRadius || oldProps.getPosition !== props.getPosition; } }, { key: 'needsReclusterPoints', value: function needsReclusterPoints(oldProps, props) { return Math.round(oldProps.zoom) !== Math.round(props.zoom); } }, { key: 'needsRecalculateScaleFunction', value: function needsRecalculateScaleFunction(oldProps, props) { return (0, _utils.needsRecalculateColorDomain)(oldProps, props) || (0, _utils.needReCalculateScaleFunction)(oldProps, props) || (0, _utils.needsRecalculateRadiusRange)(oldProps, props) || oldProps.getColorValue !== props.getColorValue; } }, { key: 'processGeoJSON', value: function processGeoJSON() { var _props = this.props, data = _props.data, getPosition = _props.getPosition; this.setState({ geoJSON: (0, _clusterUtils.getGeoJSON)(data, getPosition) }); (0, _clusterUtils.clearClustererCache)(); } }, { key: 'getClusters', value: function getClusters() { var geoJSON = this.state.geoJSON; var clusterRadius = this.props.clusterRadius; var _context = this.context, viewport = _context.viewport, _context$viewport = _context.viewport, longitude = _context$viewport.longitude, latitude = _context$viewport.latitude, height = _context$viewport.height, width = _context$viewport.width; // zoom needs to be an integer for the different map utils. Also helps with cache key. var zoom = Math.round(viewport.zoom); var bbox = _geoViewport2.default.bounds([longitude, latitude], zoom, [width, height]); var clusters = (0, _clusterUtils.clustersAtZoom)({ bbox: bbox, clusterRadius: clusterRadius, geoJSON: geoJSON, zoom: zoom }); this.setState({ clusters: clusters }); } }, { key: 'getColorValueDomain', value: function getColorValueDomain() { var _props2 = this.props, colorScale = _props2.colorScale, getColorValue = _props2.getColorValue, getRadiusValue = _props2.getRadiusValue, onSetColorDomain = _props2.onSetColorDomain; var clusters = this.state.clusters; var radiusDomain = [0, (0, _d3Array.max)(clusters, getRadiusValue)]; var colorValues = clusters.map(function (d) { return getColorValue(d.properties.points); }); var identity = function identity(d) { return d; }; var colorDomain = colorScale === _defaultSettings.SCALE_TYPES.ordinal ? (0, _dataScaleUtils.getOrdinalDomain)(colorValues, identity) : colorScale === _defaultSettings.SCALE_TYPES.quantile ? (0, _dataScaleUtils.getQuantileDomain)(colorValues, identity, _d3Array.ascending) : (0, _dataScaleUtils.getLinearDomain)(colorValues, identity); this.setState({ colorDomain: colorDomain, radiusDomain: radiusDomain }); (0, _utils.getColorScaleFunction)(this); (0, _utils.getRadiusScaleFunction)(this); onSetColorDomain(colorDomain); } }, { key: 'getUpdateTriggers', value: function getUpdateTriggers() { return { getColor: { colorRange: this.props.colorRange, colorDomain: this.props.colorDomain, getColorValue: this.props.getColorValue, colorScale: this.props.colorScale, lowerPercentile: this.props.lowerPercentile, upperPercentile: this.props.upperPercentile }, getRadius: { radiusRange: this.props.radiusRange, radiusDomain: this.props.radiusDomain, getRadiusValue: this.props.getRadiusValue } }; } /* * override default layer method to calculate cell color based on color scale function */ }, { key: '_onGetSublayerColor', value: function _onGetSublayerColor(cell) { var getColorValue = this.props.getColorValue; var _state = this.state, colorScaleFunc = _state.colorScaleFunc, colorDomain = _state.colorDomain; var cv = getColorValue(cell.properties.points); // if cell value is outside domain, set alpha to 0 var color = cv >= colorDomain[0] && cv <= colorDomain[colorDomain.length - 1] ? colorScaleFunc(cv) : [0, 0, 0, 0]; // add final alpha to color color[3] = Number.isFinite(color[3]) ? color[3] : 255; return color; } }, { key: '_onGetSublayerRadius', value: function _onGetSublayerRadius(cell) { var getRadiusValue = this.props.getRadiusValue; var radiusScaleFunc = this.state.radiusScaleFunc; return radiusScaleFunc(getRadiusValue(cell)); } }, { key: 'getPickingInfo', value: function getPickingInfo(_ref3) { var info = _ref3.info; var clusters = this.state.clusters; var isPicked = info.picked && info.index > -1; var object = null; if (isPicked) { // add cluster colorValue to object var cluster = clusters[info.index]; var colorValue = this.props.getColorValue(cluster.properties.points); object = (0, _extends3.default)({}, cluster.properties, { colorValue: colorValue, radius: this._onGetSublayerRadius(cluster), position: cluster.geometry.coordinates }); } return (0, _extends3.default)({}, info, { picked: Boolean(object), // override object with picked cluster property object: object }); } }, { key: 'renderLayers', value: function renderLayers() { // for subclassing, override this method to return // customized sub layer props var _props3 = this.props, id = _props3.id, radiusScale = _props3.radiusScale, fp64 = _props3.fp64; // base layer props var _props4 = this.props, opacity = _props4.opacity, pickable = _props4.pickable, autoHighlight = _props4.autoHighlight, highlightColor = _props4.highlightColor; // return props to the sublayer constructor return new _deck.ScatterplotLayer({ id: id + '-cluster', data: this.state.clusters, radiusScale: radiusScale, fp64: fp64, opacity: opacity, pickable: pickable, autoHighlight: autoHighlight, highlightColor: highlightColor, getPosition: function getPosition(d) { return d.geometry.coordinates; }, getRadius: this._onGetSublayerRadius.bind(this), getColor: this._onGetSublayerColor.bind(this), updateTriggers: this.getUpdateTriggers() }); } }]); return ClusterLayer; }(_deck.CompositeLayer); exports.default = ClusterLayer; ClusterLayer.layerName = 'ClusterLayer'; ClusterLayer.defaultProps = defaultProps; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9kZWNrZ2wtbGF5ZXJzL2NsdXN0ZXItbGF5ZXIvY2x1c3Rlci1sYXllci5qcyJdLCJuYW1lcyI6WyJkZWZhdWx0UmFkaXVzIiwiTEFZRVJfVklTX0NPTkZJR1MiLCJjbHVzdGVyUmFkaXVzIiwiZGVmYXVsdFZhbHVlIiwiZGVmYXVsdFJhZGl1c1JhbmdlIiwiY2x1c3RlclJhZGl1c1JhbmdlIiwiZGVmYXVsdFByb3BzIiwiY29sb3JEb21haW4iLCJjb2xvclJhbmdlIiwiRGVmYXVsdENvbG9yUmFuZ2UiLCJjb2xvclNjYWxlIiwiU0NBTEVfVFlQRVMiLCJxdWFudGl6ZSIsInJhZGl1c1JhbmdlIiwibG93ZXJQZXJjZW50aWxlIiwidXBwZXJQZXJjZW50aWxlIiwiZ2V0UG9zaXRpb24iLCJ4IiwicG9zaXRpb24iLCJnZXRDb2xvclZhbHVlIiwicG9pbnRzIiwibGVuZ3RoIiwiZ2V0UmFkaXVzVmFsdWUiLCJjZWxsIiwicHJvcGVydGllcyIsInBvaW50X2NvdW50IiwiZnA2NCIsIkNsdXN0ZXJMYXllciIsInN0YXRlIiwiY2x1c3RlcnMiLCJnZW9KU09OIiwiY2hhbmdlRmxhZ3MiLCJzb21ldGhpbmdDaGFuZ2VkIiwiY29udGV4dCIsIm9sZFByb3BzIiwicHJvcHMiLCJkYXRhQ2hhbmdlZCIsIm5lZWRzUmVQcm9qZWN0UG9pbnRzIiwicHJvY2Vzc0dlb0pTT04iLCJnZXRDbHVzdGVycyIsImdldENvbG9yVmFsdWVEb21haW4iLCJuZWVkc1JlY2x1c3RlclBvaW50cyIsIm5lZWRzUmVjYWxjdWxhdGVTY2FsZUZ1bmN0aW9uIiwiTWF0aCIsInJvdW5kIiwiem9vbSIsImRhdGEiLCJzZXRTdGF0ZSIsInZpZXdwb3J0IiwibG9uZ2l0dWRlIiwibGF0aXR1ZGUiLCJoZWlnaHQiLCJ3aWR0aCIsImJib3giLCJnZW9WaWV3cG9ydCIsImJvdW5kcyIsIm9uU2V0Q29sb3JEb21haW4iLCJyYWRpdXNEb21haW4iLCJjb2xvclZhbHVlcyIsIm1hcCIsImQiLCJpZGVudGl0eSIsIm9yZGluYWwiLCJxdWFudGlsZSIsImFzY2VuZGluZyIsImdldENvbG9yIiwiZ2V0UmFkaXVzIiwiY29sb3JTY2FsZUZ1bmMiLCJjdiIsImNvbG9yIiwiTnVtYmVyIiwiaXNGaW5pdGUiLCJyYWRpdXNTY2FsZUZ1bmMiLCJpbmZvIiwiaXNQaWNrZWQiLCJwaWNrZWQiLCJpbmRleCIsIm9iamVjdCIsImNsdXN0ZXIiLCJjb2xvclZhbHVlIiwicmFkaXVzIiwiX29uR2V0U3VibGF5ZXJSYWRpdXMiLCJnZW9tZXRyeSIsImNvb3JkaW5hdGVzIiwiQm9vbGVhbiIsImlkIiwicmFkaXVzU2NhbGUiLCJvcGFjaXR5IiwicGlja2FibGUiLCJhdXRvSGlnaGxpZ2h0IiwiaGlnaGxpZ2h0Q29sb3IiLCJTY2F0dGVycGxvdExheWVyIiwiYmluZCIsIl9vbkdldFN1YmxheWVyQ29sb3IiLCJ1cGRhdGVUcmlnZ2VycyIsImdldFVwZGF0ZVRyaWdnZXJzIiwiQ29tcG9zaXRlTGF5ZXIiLCJsYXllck5hbWUiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQW9CQTs7QUFDQTs7OztBQUNBOztBQUNBOztBQUtBOztBQU9BOztBQUNBOztBQUNBOztBQUVBOzs7O0FBTUEsSUFBTUEsZ0JBQWdCQyxnQ0FBa0JDLGFBQWxCLENBQWdDQyxZQUF0RCxDLENBN0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQTRCQSxJQUFNQyxxQkFBcUJILGdDQUFrQkksa0JBQWxCLENBQXFDRixZQUFoRTs7QUFFQSxJQUFNRyxlQUFlO0FBQ25CSixpQkFBZUYsYUFESTtBQUVuQk8sZUFBYSxJQUZNO0FBR25CQyxjQUFZQyw4QkFITztBQUluQkMsY0FBWUMsNkJBQVlDLFFBSkw7QUFLbkJDLGVBQWFULGtCQUxNOztBQU9uQjtBQUNBVSxtQkFBaUIsQ0FSRTtBQVNuQkMsbUJBQWlCLEdBVEU7O0FBV25CQyxlQUFhO0FBQUEsV0FBS0MsRUFBRUMsUUFBUDtBQUFBLEdBWE07O0FBYW5CO0FBQ0FDLGlCQUFlO0FBQUEsV0FBVUMsT0FBT0MsTUFBakI7QUFBQSxHQWRJOztBQWdCbkI7QUFDQUMsa0JBQWdCO0FBQUEsV0FBUUMsS0FBS0MsVUFBTCxDQUFnQkMsV0FBeEI7QUFBQSxHQWpCRztBQWtCbkJDLFFBQU07QUFsQmEsQ0FBckI7O0lBcUJxQkMsWTs7Ozs7Ozs7OztzQ0FDRDtBQUNoQixXQUFLQyxLQUFMLEdBQWE7QUFDWEMsa0JBQVUsSUFEQztBQUVYQyxpQkFBUztBQUZFLE9BQWI7QUFJRDs7OzRDQUVnQztBQUFBLFVBQWRDLFdBQWMsUUFBZEEsV0FBYzs7QUFDL0IsYUFBT0EsWUFBWUMsZ0JBQW5CO0FBQ0Q7Ozt1Q0FFb0Q7QUFBQSxVQUF4Q0MsT0FBd0MsU0FBeENBLE9BQXdDO0FBQUEsVUFBL0JDLFFBQStCLFNBQS9CQSxRQUErQjtBQUFBLFVBQXJCQyxLQUFxQixTQUFyQkEsS0FBcUI7QUFBQSxVQUFkSixXQUFjLFNBQWRBLFdBQWM7O0FBQ25ELFVBQUlBLFlBQVlLLFdBQVosSUFBMkIsS0FBS0Msb0JBQUwsQ0FBMEJILFFBQTFCLEVBQW9DQyxLQUFwQyxDQUEvQixFQUEyRTtBQUN6RTtBQUNBLGFBQUtHLGNBQUw7QUFDQSxhQUFLQyxXQUFMOztBQUVBO0FBQ0EsYUFBS0MsbUJBQUw7QUFDRCxPQVBELE1BT08sSUFBSSxLQUFLQyxvQkFBTCxDQUEwQlAsUUFBMUIsRUFBb0NDLEtBQXBDLENBQUosRUFBZ0Q7QUFDckQsYUFBS0ksV0FBTDtBQUNBLGFBQUtDLG1CQUFMO0FBQ0QsT0FITSxNQUdBLElBQUksS0FBS0UsNkJBQUwsQ0FBbUNSLFFBQW5DLEVBQTZDQyxLQUE3QyxDQUFKLEVBQXlEO0FBQzlELGFBQUtLLG1CQUFMO0FBQ0Q7QUFDRjs7O3lDQUVvQk4sUSxFQUFVQyxLLEVBQU87QUFDcEMsYUFDRUQsU0FBU2hDLGFBQVQsS0FBMkJpQyxNQUFNakMsYUFBakMsSUFDQWdDLFNBQVNsQixXQUFULEtBQXlCbUIsTUFBTW5CLFdBRmpDO0FBSUQ7Ozt5Q0FFb0JrQixRLEVBQVVDLEssRUFBTztBQUNwQyxhQUNFUSxLQUFLQyxLQUFMLENBQVdWLFNBQVNXLElBQXBCLE1BQThCRixLQUFLQyxLQUFMLENBQVdULE1BQU1VLElBQWpCLENBRGhDO0FBR0Q7OztrREFFNkJYLFEsRUFBVUMsSyxFQUFPO0FBQzdDLGFBQ0Usd0NBQTRCRCxRQUE1QixFQUFzQ0MsS0FBdEMsS0FDQSx5Q0FBNkJELFFBQTdCLEVBQXVDQyxLQUF2QyxDQURBLElBRUEsd0NBQTRCRCxRQUE1QixFQUFzQ0MsS0FBdEMsQ0FGQSxJQUdBRCxTQUFTZixhQUFULEtBQTJCZ0IsTUFBTWhCLGFBSm5DO0FBTUQ7OztxQ0FFZ0I7QUFBQSxtQkFDYSxLQUFLZ0IsS0FEbEI7QUFBQSxVQUNSVyxJQURRLFVBQ1JBLElBRFE7QUFBQSxVQUNGOUIsV0FERSxVQUNGQSxXQURFOztBQUVmLFdBQUsrQixRQUFMLENBQWMsRUFBQ2pCLFNBQVMsOEJBQVdnQixJQUFYLEVBQWlCOUIsV0FBakIsQ0FBVixFQUFkO0FBQ0E7QUFDRDs7O2tDQUVhO0FBQUEsVUFDTGMsT0FESyxHQUNNLEtBQUtGLEtBRFgsQ0FDTEUsT0FESztBQUFBLFVBRUw1QixhQUZLLEdBRVksS0FBS2lDLEtBRmpCLENBRUxqQyxhQUZLO0FBQUEscUJBTVIsS0FBSytCLE9BTkc7QUFBQSxVQUlWZSxRQUpVLFlBSVZBLFFBSlU7QUFBQSx1Q0FLVkEsUUFMVTtBQUFBLFVBS0NDLFNBTEQscUJBS0NBLFNBTEQ7QUFBQSxVQUtZQyxRQUxaLHFCQUtZQSxRQUxaO0FBQUEsVUFLc0JDLE1BTHRCLHFCQUtzQkEsTUFMdEI7QUFBQSxVQUs4QkMsS0FMOUIscUJBSzhCQSxLQUw5Qjs7QUFRWjs7QUFDQSxVQUFNUCxPQUFPRixLQUFLQyxLQUFMLENBQVdJLFNBQVNILElBQXBCLENBQWI7QUFDQSxVQUFNUSxPQUFPQyxzQkFBWUMsTUFBWixDQUFtQixDQUFDTixTQUFELEVBQVlDLFFBQVosQ0FBbkIsRUFBMENMLElBQTFDLEVBQWdELENBQzNETyxLQUQyRCxFQUUzREQsTUFGMkQsQ0FBaEQsQ0FBYjs7QUFLQSxVQUFNdEIsV0FBVyxrQ0FBZSxFQUFDd0IsVUFBRCxFQUFPbkQsNEJBQVAsRUFBc0I0QixnQkFBdEIsRUFBK0JlLFVBQS9CLEVBQWYsQ0FBakI7O0FBRUEsV0FBS0UsUUFBTCxDQUFjLEVBQUNsQixrQkFBRCxFQUFkO0FBQ0Q7OzswQ0FFcUI7QUFBQSxvQkFNaEIsS0FBS00sS0FOVztBQUFBLFVBRWxCekIsVUFGa0IsV0FFbEJBLFVBRmtCO0FBQUEsVUFHbEJTLGFBSGtCLFdBR2xCQSxhQUhrQjtBQUFBLFVBSWxCRyxjQUprQixXQUlsQkEsY0FKa0I7QUFBQSxVQUtsQmtDLGdCQUxrQixXQUtsQkEsZ0JBTGtCO0FBQUEsVUFPYjNCLFFBUGEsR0FPRCxLQUFLRCxLQVBKLENBT2JDLFFBUGE7OztBQVNwQixVQUFNNEIsZUFBZSxDQUFDLENBQUQsRUFBSSxrQkFBSTVCLFFBQUosRUFBY1AsY0FBZCxDQUFKLENBQXJCOztBQUVBLFVBQU1vQyxjQUFjN0IsU0FBUzhCLEdBQVQsQ0FBYTtBQUFBLGVBQUt4QyxjQUFjeUMsRUFBRXBDLFVBQUYsQ0FBYUosTUFBM0IsQ0FBTDtBQUFBLE9BQWIsQ0FBcEI7O0FBRUEsVUFBTXlDLFdBQVcsU0FBWEEsUUFBVztBQUFBLGVBQUtELENBQUw7QUFBQSxPQUFqQjs7QUFFQSxVQUFNckQsY0FDSkcsZUFBZUMsNkJBQVltRCxPQUEzQixHQUNJLHNDQUFpQkosV0FBakIsRUFBOEJHLFFBQTlCLENBREosR0FFSW5ELGVBQWVDLDZCQUFZb0QsUUFBM0IsR0FDRSx1Q0FBa0JMLFdBQWxCLEVBQStCRyxRQUEvQixFQUF5Q0csa0JBQXpDLENBREYsR0FFRSxxQ0FBZ0JOLFdBQWhCLEVBQTZCRyxRQUE3QixDQUxSOztBQU9BLFdBQUtkLFFBQUwsQ0FBYztBQUNaeEMsZ0NBRFk7QUFFWmtEO0FBRlksT0FBZDs7QUFLQSx3Q0FBc0IsSUFBdEI7QUFDQSx5Q0FBdUIsSUFBdkI7O0FBRUFELHVCQUFpQmpELFdBQWpCO0FBQ0Q7Ozt3Q0FFbUI7QUFDbEIsYUFBTztBQUNMMEQsa0JBQVU7QUFDUnpELHNCQUFZLEtBQUsyQixLQUFMLENBQVczQixVQURmO0FBRVJELHVCQUFhLEtBQUs0QixLQUFMLENBQVc1QixXQUZoQjtBQUdSWSx5QkFBZSxLQUFLZ0IsS0FBTCxDQUFXaEIsYUFIbEI7QUFJUlQsc0JBQVksS0FBS3lCLEtBQUwsQ0FBV3pCLFVBSmY7QUFLUkksMkJBQWlCLEtBQUtxQixLQUFMLENBQVdyQixlQUxwQjtBQU1SQywyQkFBaUIsS0FBS29CLEtBQUwsQ0FBV3BCO0FBTnBCLFNBREw7QUFTTG1ELG1CQUFXO0FBQ1RyRCx1QkFBYSxLQUFLc0IsS0FBTCxDQUFXdEIsV0FEZjtBQUVUNEMsd0JBQWMsS0FBS3RCLEtBQUwsQ0FBV3NCLFlBRmhCO0FBR1RuQywwQkFBZ0IsS0FBS2EsS0FBTCxDQUFXYjtBQUhsQjtBQVROLE9BQVA7QUFlRDs7QUFFRDs7Ozs7O3dDQUdvQkMsSSxFQUFNO0FBQUEsVUFDakJKLGFBRGlCLEdBQ0EsS0FBS2dCLEtBREwsQ0FDakJoQixhQURpQjtBQUFBLG1CQUVjLEtBQUtTLEtBRm5CO0FBQUEsVUFFakJ1QyxjQUZpQixVQUVqQkEsY0FGaUI7QUFBQSxVQUVENUQsV0FGQyxVQUVEQSxXQUZDOzs7QUFJeEIsVUFBTTZELEtBQUtqRCxjQUFjSSxLQUFLQyxVQUFMLENBQWdCSixNQUE5QixDQUFYOztBQUVBO0FBQ0EsVUFBTWlELFFBQ0pELE1BQU03RCxZQUFZLENBQVosQ0FBTixJQUF3QjZELE1BQU03RCxZQUFZQSxZQUFZYyxNQUFaLEdBQXFCLENBQWpDLENBQTlCLEdBQ0k4QyxlQUFlQyxFQUFmLENBREosR0FFSSxDQUFDLENBQUQsRUFBSSxDQUFKLEVBQU8sQ0FBUCxFQUFVLENBQVYsQ0FITjs7QUFLQTtBQUNBQyxZQUFNLENBQU4sSUFBV0MsT0FBT0MsUUFBUCxDQUFnQkYsTUFBTSxDQUFOLENBQWhCLElBQTRCQSxNQUFNLENBQU4sQ0FBNUIsR0FBdUMsR0FBbEQ7O0FBRUEsYUFBT0EsS0FBUDtBQUNEOzs7eUNBRW9COUMsSSxFQUFNO0FBQUEsVUFDbEJELGNBRGtCLEdBQ0EsS0FBS2EsS0FETCxDQUNsQmIsY0FEa0I7QUFBQSxVQUVsQmtELGVBRmtCLEdBRUMsS0FBSzVDLEtBRk4sQ0FFbEI0QyxlQUZrQjs7QUFHekIsYUFBT0EsZ0JBQWdCbEQsZUFBZUMsSUFBZixDQUFoQixDQUFQO0FBQ0Q7OzswQ0FFc0I7QUFBQSxVQUFQa0QsSUFBTyxTQUFQQSxJQUFPO0FBQUEsVUFDZDVDLFFBRGMsR0FDRixLQUFLRCxLQURILENBQ2RDLFFBRGM7O0FBRXJCLFVBQU02QyxXQUFXRCxLQUFLRSxNQUFMLElBQWVGLEtBQUtHLEtBQUwsR0FBYSxDQUFDLENBQTlDOztBQUVBLFVBQUlDLFNBQVMsSUFBYjtBQUNBLFVBQUlILFFBQUosRUFBYztBQUNaO0FBQ0EsWUFBTUksVUFBVWpELFNBQVM0QyxLQUFLRyxLQUFkLENBQWhCO0FBQ0EsWUFBTUcsYUFBYSxLQUFLNUMsS0FBTCxDQUFXaEIsYUFBWCxDQUF5QjJELFFBQVF0RCxVQUFSLENBQW1CSixNQUE1QyxDQUFuQjs7QUFFQXlELDRDQUNLQyxRQUFRdEQsVUFEYjtBQUVFdUQsZ0NBRkY7QUFHRUMsa0JBQVEsS0FBS0Msb0JBQUwsQ0FBMEJILE9BQTFCLENBSFY7QUFJRTVELG9CQUFVNEQsUUFBUUksUUFBUixDQUFpQkM7QUFKN0I7QUFNRDs7QUFFRCx3Q0FDS1YsSUFETDtBQUVFRSxnQkFBUVMsUUFBUVAsTUFBUixDQUZWO0FBR0U7QUFDQUE7QUFKRjtBQU1EOzs7bUNBRWM7QUFDYjtBQUNBO0FBRmEsb0JBR21CLEtBQUsxQyxLQUh4QjtBQUFBLFVBR05rRCxFQUhNLFdBR05BLEVBSE07QUFBQSxVQUdGQyxXQUhFLFdBR0ZBLFdBSEU7QUFBQSxVQUdXNUQsSUFIWCxXQUdXQSxJQUhYOztBQUtiOztBQUxhLG9CQU04QyxLQUFLUyxLQU5uRDtBQUFBLFVBTU5vRCxPQU5NLFdBTU5BLE9BTk07QUFBQSxVQU1HQyxRQU5ILFdBTUdBLFFBTkg7QUFBQSxVQU1hQyxhQU5iLFdBTWFBLGFBTmI7QUFBQSxVQU00QkMsY0FONUIsV0FNNEJBLGNBTjVCOztBQVFiOztBQUNBLGFBQU8sSUFBSUMsc0JBQUosQ0FBcUI7QUFDMUJOLFlBQU9BLEVBQVAsYUFEMEI7QUFFMUJ2QyxjQUFNLEtBQUtsQixLQUFMLENBQVdDLFFBRlM7QUFHMUJ5RCxnQ0FIMEI7QUFJMUI1RCxrQkFKMEI7QUFLMUI2RCx3QkFMMEI7QUFNMUJDLDBCQU4wQjtBQU8xQkMsb0NBUDBCO0FBUTFCQyxzQ0FSMEI7QUFTMUIxRSxxQkFBYTtBQUFBLGlCQUFLNEMsRUFBRXNCLFFBQUYsQ0FBV0MsV0FBaEI7QUFBQSxTQVRhO0FBVTFCakIsbUJBQVcsS0FBS2Usb0JBQUwsQ0FBMEJXLElBQTFCLENBQStCLElBQS9CLENBVmU7QUFXMUIzQixrQkFBVSxLQUFLNEIsbUJBQUwsQ0FBeUJELElBQXpCLENBQThCLElBQTlCLENBWGdCO0FBWTFCRSx3QkFBZ0IsS0FBS0MsaUJBQUw7QUFaVSxPQUFyQixDQUFQO0FBY0Q7OztFQTNNdUNDLG9COztrQkFBckJyRSxZOzs7QUE4TXJCQSxhQUFhc0UsU0FBYixHQUF5QixjQUF6QjtBQUNBdEUsYUFBYXJCLFlBQWIsR0FBNEJBLFlBQTVCIiwiZmlsZSI6ImNsdXN0ZXItbGF5ZXIuanMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgKGMpIDIwMTggVWJlciBUZWNobm9sb2dpZXMsIEluYy5cbi8vXG4vLyBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYSBjb3B5XG4vLyBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0byBkZWFsXG4vLyBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzXG4vLyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsXG4vLyBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbi8vIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuLy9cbi8vIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCBcIkFTIElTXCIsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVYUFJFU1MgT1Jcbi8vIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuLy8gRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4vLyBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1BR0VTIE9SIE9USEVSXG4vLyBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuLy8gT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTlxuLy8gVEhFIFNPRlRXQVJFLlxuXG5pbXBvcnQge0NvbXBvc2l0ZUxheWVyLCBTY2F0dGVycGxvdExheWVyfSBmcm9tICdkZWNrLmdsJztcbmltcG9ydCBnZW9WaWV3cG9ydCBmcm9tICdAbWFwYm94L2dlby12aWV3cG9ydCc7XG5pbXBvcnQge2FzY2VuZGluZywgbWF4fSBmcm9tICdkMy1hcnJheSc7XG5pbXBvcnQge1xuICBnZXRRdWFudGlsZURvbWFpbixcbiAgZ2V0T3JkaW5hbERvbWFpbixcbiAgZ2V0TGluZWFyRG9tYWluXG59IGZyb20gJ3V0aWxzL2RhdGEtc2NhbGUtdXRpbHMnO1xuaW1wb3J0IHtcbiAgZ2V0Q29sb3JTY2FsZUZ1bmN0aW9uLFxuICBnZXRSYWRpdXNTY2FsZUZ1bmN0aW9uLFxuICBuZWVkc1JlY2FsY3VsYXRlUmFkaXVzUmFuZ2UsXG4gIG5lZWRzUmVjYWxjdWxhdGVDb2xvckRvbWFpbixcbiAgbmVlZFJlQ2FsY3VsYXRlU2NhbGVGdW5jdGlvblxufSBmcm9tICcuLi9sYXllci11dGlscy91dGlscyc7XG5pbXBvcnQge0RlZmF1bHRDb2xvclJhbmdlfSBmcm9tICdjb25zdGFudHMvY29sb3ItcmFuZ2VzJztcbmltcG9ydCB7TEFZRVJfVklTX0NPTkZJR1N9IGZyb20gJ2xheWVycy9sYXllci1mYWN0b3J5JztcbmltcG9ydCB7U0NBTEVfVFlQRVN9IGZyb20gJ2NvbnN0YW50cy9kZWZhdWx0LXNldHRpbmdzJztcblxuaW1wb3J0IHtcbiAgY2xlYXJDbHVzdGVyZXJDYWNoZSxcbiAgY2x1c3RlcnNBdFpvb20sXG4gIGdldEdlb0pTT05cbn0gZnJvbSAnLi4vbGF5ZXItdXRpbHMvY2x1c3Rlci11dGlscyc7XG5cbmNvbnN0IGRlZmF1bHRSYWRpdXMgPSBMQVlFUl9WSVNfQ09ORklHUy5jbHVzdGVyUmFkaXVzLmRlZmF1bHRWYWx1ZTtcbmNvbnN0IGRlZmF1bHRSYWRpdXNSYW5nZSA9IExBWUVSX1ZJU19DT05GSUdTLmNsdXN0ZXJSYWRpdXNSYW5nZS5kZWZhdWx0VmFsdWU7XG5cbmNvbnN0IGRlZmF1bHRQcm9wcyA9IHtcbiAgY2x1c3RlclJhZGl1czogZGVmYXVsdFJhZGl1cyxcbiAgY29sb3JEb21haW46IG51bGwsXG4gIGNvbG9yUmFuZ2U6IERlZmF1bHRDb2xvclJhbmdlLFxuICBjb2xvclNjYWxlOiBTQ0FMRV9UWVBFUy5xdWFudGl6ZSxcbiAgcmFkaXVzUmFuZ2U6IGRlZmF1bHRSYWRpdXNSYW5nZSxcblxuICAvLyBtYXliZSBsYXRlci4uLlxuICBsb3dlclBlcmNlbnRpbGU6IDAsXG4gIHVwcGVyUGVyY2VudGlsZTogMTAwLFxuXG4gIGdldFBvc2l0aW9uOiB4ID0+IHgucG9zaXRpb24sXG5cbiAgLy8gaWYgd2FudCB0byBoYXZlIGNvbG9yIGJhc2VkIG9uIGN1c3RvbWl6ZWQgYWdncmVnYXRvciwgaW5zdGVhZCBvZiBjb3VudFxuICBnZXRDb2xvclZhbHVlOiBwb2ludHMgPT4gcG9pbnRzLmxlbmd0aCxcblxuICAvLyAgaWYgd2FudCB0byBoYXZlIHJhZGl1cyBiYXNlZCBvbiBjdXN0b21pemVkIGFnZ3JlZ2F0b3IsIGluc3RlYWQgb2YgY291bnRcbiAgZ2V0UmFkaXVzVmFsdWU6IGNlbGwgPT4gY2VsbC5wcm9wZXJ0aWVzLnBvaW50X2NvdW50LFxuICBmcDY0OiBmYWxzZVxufTtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQ2x1c3RlckxheWVyIGV4dGVuZHMgQ29tcG9zaXRlTGF5ZXIge1xuICBpbml0aWFsaXplU3RhdGUoKSB7XG4gICAgdGhpcy5zdGF0ZSA9IHtcbiAgICAgIGNsdXN0ZXJzOiBudWxsLFxuICAgICAgZ2VvSlNPTjogbnVsbFxuICAgIH07XG4gIH1cblxuICBzaG91bGRVcGRhdGVTdGF0ZSh7Y2hhbmdlRmxhZ3N9KSB7XG4gICAgcmV0dXJuIGNoYW5nZUZsYWdzLnNvbWV0aGluZ0NoYW5nZWQ7XG4gIH1cblxuICB1cGRhdGVTdGF0ZSh7Y29udGV4dCwgb2xkUHJvcHMsIHByb3BzLCBjaGFuZ2VGbGFnc30pIHtcbiAgICBpZiAoY2hhbmdlRmxhZ3MuZGF0YUNoYW5nZWQgfHwgdGhpcy5uZWVkc1JlUHJvamVjdFBvaW50cyhvbGRQcm9wcywgcHJvcHMpKSB7XG4gICAgICAvLyBwcm9qZWN0IGRhdGEgaW50byBjbHVzdGVycywgYW5kIGdldCBjbHVzdGVyZWQgZGF0YVxuICAgICAgdGhpcy5wcm9jZXNzR2VvSlNPTigpO1xuICAgICAgdGhpcy5nZXRDbHVzdGVycygpO1xuXG4gICAgICAvLyB0aGlzIG5lZWRzIGNsdXN0ZXJlZCBkYXRhIHRvIGJlIHNldFxuICAgICAgdGhpcy5nZXRDb2xvclZhbHVlRG9tYWluKCk7XG4gICAgfSBlbHNlIGlmICh0aGlzLm5lZWRzUmVjbHVzdGVyUG9pbnRzKG9sZFByb3BzLCBwcm9wcykpIHtcbiAgICAgIHRoaXMuZ2V0Q2x1c3RlcnMoKTtcbiAgICAgIHRoaXMuZ2V0Q29sb3JWYWx1ZURvbWFpbigpO1xuICAgIH0gZWxzZSBpZiAodGhpcy5uZWVkc1JlY2FsY3VsYXRlU2NhbGVGdW5jdGlvbihvbGRQcm9wcywgcHJvcHMpKSB7XG4gICAgICB0aGlzLmdldENvbG9yVmFsdWVEb21haW4oKTtcbiAgICB9XG4gIH1cblxuICBuZWVkc1JlUHJvamVjdFBvaW50cyhvbGRQcm9wcywgcHJvcHMpIHtcbiAgICByZXR1cm4gKFxuICAgICAgb2xkUHJvcHMuY2x1c3RlclJhZGl1cyAhPT0gcHJvcHMuY2x1c3RlclJhZGl1cyB8fFxuICAgICAgb2xkUHJvcHMuZ2V0UG9zaXRpb24gIT09IHByb3BzLmdldFBvc2l0aW9uXG4gICAgKTtcbiAgfVxuXG4gIG5lZWRzUmVjbHVzdGVyUG9pbnRzKG9sZFByb3BzLCBwcm9wcykge1xuICAgIHJldHVybiAoXG4gICAgICBNYXRoLnJvdW5kKG9sZFByb3BzLnpvb20pICE9PSBNYXRoLnJvdW5kKHByb3BzLnpvb20pXG4gICAgKTtcbiAgfVxuXG4gIG5lZWRzUmVjYWxjdWxhdGVTY2FsZUZ1bmN0aW9uKG9sZFByb3BzLCBwcm9wcykge1xuICAgIHJldHVybiAoXG4gICAgICBuZWVkc1JlY2FsY3VsYXRlQ29sb3JEb21haW4ob2xkUHJvcHMsIHByb3BzKSB8fFxuICAgICAgbmVlZFJlQ2FsY3VsYXRlU2NhbGVGdW5jdGlvbihvbGRQcm9wcywgcHJvcHMpIHx8XG4gICAgICBuZWVkc1JlY2FsY3VsYXRlUmFkaXVzUmFuZ2Uob2xkUHJvcHMsIHByb3BzKSB8fFxuICAgICAgb2xkUHJvcHMuZ2V0Q29sb3JWYWx1ZSAhPT0gcHJvcHMuZ2V0Q29sb3JWYWx1ZVxuICAgICk7XG4gIH1cblxuICBwcm9jZXNzR2VvSlNPTigpIHtcbiAgICBjb25zdCB7ZGF0YSwgZ2V0UG9zaXRpb259ID0gdGhpcy5wcm9wcztcbiAgICB0aGlzLnNldFN0YXRlKHtnZW9KU09OOiBnZXRHZW9KU09OKGRhdGEsIGdldFBvc2l0aW9uKX0pO1xuICAgIGNsZWFyQ2x1c3RlcmVyQ2FjaGUoKTtcbiAgfVxuXG4gIGdldENsdXN0ZXJzKCkge1xuICAgIGNvbnN0IHtnZW9KU09OfSA9IHRoaXMuc3RhdGU7XG4gICAgY29uc3Qge2NsdXN0ZXJSYWRpdXN9ID0gdGhpcy5wcm9wcztcbiAgICBjb25zdCB7XG4gICAgICB2aWV3cG9ydCxcbiAgICAgIHZpZXdwb3J0OiB7bG9uZ2l0dWRlLCBsYXRpdHVkZSwgaGVpZ2h0LCB3aWR0aH1cbiAgICB9ID0gdGhpcy5jb250ZXh0O1xuXG4gICAgLy8gem9vbSBuZWVkcyB0byBiZSBhbiBpbnRlZ2VyIGZvciB0aGUgZGlmZmVyZW50IG1hcCB1dGlscy4gQWxzbyBoZWxwcyB3aXRoIGNhY2hlIGtleS5cbiAgICBjb25zdCB6b29tID0gTWF0aC5yb3VuZCh2aWV3cG9ydC56b29tKTtcbiAgICBjb25zdCBiYm94ID0gZ2VvVmlld3BvcnQuYm91bmRzKFtsb25naXR1ZGUsIGxhdGl0dWRlXSwgem9vbSwgW1xuICAgICAgd2lkdGgsXG4gICAgICBoZWlnaHRcbiAgICBdKTtcblxuICAgIGNvbnN0IGNsdXN0ZXJzID0gY2x1c3RlcnNBdFpvb20oe2Jib3gsIGNsdXN0ZXJSYWRpdXMsIGdlb0pTT04sIHpvb219KTtcblxuICAgIHRoaXMuc2V0U3RhdGUoe2NsdXN0ZXJzfSk7XG4gIH1cblxuICBnZXRDb2xvclZhbHVlRG9tYWluKCkge1xuICAgIGNvbnN0IHtcbiAgICAgIGNvbG9yU2NhbGUsXG4gICAgICBnZXRDb2xvclZhbHVlLFxuICAgICAgZ2V0UmFkaXVzVmFsdWUsXG4gICAgICBvblNldENvbG9yRG9tYWluXG4gICAgfSA9IHRoaXMucHJvcHM7XG4gICAgY29uc3Qge2NsdXN0ZXJzfSA9IHRoaXMuc3RhdGU7XG5cbiAgICBjb25zdCByYWRpdXNEb21haW4gPSBbMCwgbWF4KGNsdXN0ZXJzLCBnZXRSYWRpdXNWYWx1ZSldO1xuXG4gICAgY29uc3QgY29sb3JWYWx1ZXMgPSBjbHVzdGVycy5tYXAoZCA9PiBnZXRDb2xvclZhbHVlKGQucHJvcGVydGllcy5wb2ludHMpKTtcblxuICAgIGNvbnN0IGlkZW50aXR5ID0gZCA9PiBkO1xuXG4gICAgY29uc3QgY29sb3JEb21haW4gPVxuICAgICAgY29sb3JTY2FsZSA9PT0gU0NBTEVfVFlQRVMub3JkaW5hbFxuICAgICAgICA/IGdldE9yZGluYWxEb21haW4oY29sb3JWYWx1ZXMsIGlkZW50aXR5KVxuICAgICAgICA6IGNvbG9yU2NhbGUgPT09IFNDQUxFX1RZUEVTLnF1YW50aWxlXG4gICAgICAgICAgPyBnZXRRdWFudGlsZURvbWFpbihjb2xvclZhbHVlcywgaWRlbnRpdHksIGFzY2VuZGluZylcbiAgICAgICAgICA6IGdldExpbmVhckRvbWFpbihjb2xvclZhbHVlcywgaWRlbnRpdHkpO1xuXG4gICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICBjb2xvckRvbWFpbixcbiAgICAgIHJhZGl1c0RvbWFpblxuICAgIH0pO1xuXG4gICAgZ2V0Q29sb3JTY2FsZUZ1bmN0aW9uKHRoaXMpO1xuICAgIGdldFJhZGl1c1NjYWxlRnVuY3Rpb24odGhpcyk7XG5cbiAgICBvblNldENvbG9yRG9tYWluKGNvbG9yRG9tYWluKTtcbiAgfVxuXG4gIGdldFVwZGF0ZVRyaWdnZXJzKCkge1xuICAgIHJldHVybiB7XG4gICAgICBnZXRDb2xvcjoge1xuICAgICAgICBjb2xvclJhbmdlOiB0aGlzLnByb3BzLmNvbG9yUmFuZ2UsXG4gICAgICAgIGNvbG9yRG9tYWluOiB0aGlzLnByb3BzLmNvbG9yRG9tYWluLFxuICAgICAgICBnZXRDb2xvclZhbHVlOiB0aGlzLnByb3BzLmdldENvbG9yVmFsdWUsXG4gICAgICAgIGNvbG9yU2NhbGU6IHRoaXMucHJvcHMuY29sb3JTY2FsZSxcbiAgICAgICAgbG93ZXJQZXJjZW50aWxlOiB0aGlzLnByb3BzLmxvd2VyUGVyY2VudGlsZSxcbiAgICAgICAgdXBwZXJQZXJjZW50aWxlOiB0aGlzLnByb3BzLnVwcGVyUGVyY2VudGlsZVxuICAgICAgfSxcbiAgICAgIGdldFJhZGl1czoge1xuICAgICAgICByYWRpdXNSYW5nZTogdGhpcy5wcm9wcy5yYWRpdXNSYW5nZSxcbiAgICAgICAgcmFkaXVzRG9tYWluOiB0aGlzLnByb3BzLnJhZGl1c0RvbWFpbixcbiAgICAgICAgZ2V0UmFkaXVzVmFsdWU6IHRoaXMucHJvcHMuZ2V0UmFkaXVzVmFsdWVcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgLypcbiAgICogb3ZlcnJpZGUgZGVmYXVsdCBsYXllciBtZXRob2QgdG8gY2FsY3VsYXRlIGNlbGwgY29sb3IgYmFzZWQgb24gY29sb3Igc2NhbGUgZnVuY3Rpb25cbiAgICovXG4gIF9vbkdldFN1YmxheWVyQ29sb3IoY2VsbCkge1xuICAgIGNvbnN0IHtnZXRDb2xvclZhbHVlfSA9IHRoaXMucHJvcHM7XG4gICAgY29uc3Qge2NvbG9yU2NhbGVGdW5jLCBjb2xvckRvbWFpbn0gPSB0aGlzLnN0YXRlO1xuXG4gICAgY29uc3QgY3YgPSBnZXRDb2xvclZhbHVlKGNlbGwucHJvcGVydGllcy5wb2ludHMpO1xuXG4gICAgLy8gaWYgY2VsbCB2YWx1ZSBpcyBvdXRzaWRlIGRvbWFpbiwgc2V0IGFscGhhIHRvIDBcbiAgICBjb25zdCBjb2xvciA9XG4gICAgICBjdiA+PSBjb2xvckRvbWFpblswXSAmJiBjdiA8PSBjb2xvckRvbWFpbltjb2xvckRvbWFpbi5sZW5ndGggLSAxXVxuICAgICAgICA/IGNvbG9yU2NhbGVGdW5jKGN2KVxuICAgICAgICA6IFswLCAwLCAwLCAwXTtcblxuICAgIC8vIGFkZCBmaW5hbCBhbHBoYSB0byBjb2xvclxuICAgIGNvbG9yWzNdID0gTnVtYmVyLmlzRmluaXRlKGNvbG9yWzNdKSA/IGNvbG9yWzNdIDogMjU1O1xuXG4gICAgcmV0dXJuIGNvbG9yO1xuICB9XG5cbiAgX29uR2V0U3VibGF5ZXJSYWRpdXMoY2VsbCkge1xuICAgIGNvbnN0IHtnZXRSYWRpdXNWYWx1ZX0gPSB0aGlzLnByb3BzO1xuICAgIGNvbnN0IHtyYWRpdXNTY2FsZUZ1bmN9ID0gdGhpcy5zdGF0ZTtcbiAgICByZXR1cm4gcmFkaXVzU2NhbGVGdW5jKGdldFJhZGl1c1ZhbHVlKGNlbGwpKTtcbiAgfVxuXG4gIGdldFBpY2tpbmdJbmZvKHtpbmZvfSkge1xuICAgIGNvbnN0IHtjbHVzdGVyc30gPSB0aGlzLnN0YXRlO1xuICAgIGNvbnN0IGlzUGlja2VkID0gaW5mby5waWNrZWQgJiYgaW5mby5pbmRleCA+IC0xO1xuXG4gICAgbGV0IG9iamVjdCA9IG51bGw7XG4gICAgaWYgKGlzUGlja2VkKSB7XG4gICAgICAvLyBhZGQgY2x1c3RlciBjb2xvclZhbHVlIHRvIG9iamVjdFxuICAgICAgY29uc3QgY2x1c3RlciA9IGNsdXN0ZXJzW2luZm8uaW5kZXhdO1xuICAgICAgY29uc3QgY29sb3JWYWx1ZSA9IHRoaXMucHJvcHMuZ2V0Q29sb3JWYWx1ZShjbHVzdGVyLnByb3BlcnRpZXMucG9pbnRzKTtcblxuICAgICAgb2JqZWN0ID0ge1xuICAgICAgICAuLi5jbHVzdGVyLnByb3BlcnRpZXMsXG4gICAgICAgIGNvbG9yVmFsdWUsXG4gICAgICAgIHJhZGl1czogdGhpcy5fb25HZXRTdWJsYXllclJhZGl1cyhjbHVzdGVyKSxcbiAgICAgICAgcG9zaXRpb246IGNsdXN0ZXIuZ2VvbWV0cnkuY29vcmRpbmF0ZXNcbiAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLmluZm8sXG4gICAgICBwaWNrZWQ6IEJvb2xlYW4ob2JqZWN0KSxcbiAgICAgIC8vIG92ZXJyaWRlIG9iamVjdCB3aXRoIHBpY2tlZCBjbHVzdGVyIHByb3BlcnR5XG4gICAgICBvYmplY3RcbiAgICB9O1xuICB9XG5cbiAgcmVuZGVyTGF5ZXJzKCkge1xuICAgIC8vIGZvciBzdWJjbGFzc2luZywgb3ZlcnJpZGUgdGhpcyBtZXRob2QgdG8gcmV0dXJuXG4gICAgLy8gY3VzdG9taXplZCBzdWIgbGF5ZXIgcHJvcHNcbiAgICBjb25zdCB7aWQsIHJhZGl1c1NjYWxlLCBmcDY0fSA9IHRoaXMucHJvcHM7XG5cbiAgICAvLyBiYXNlIGxheWVyIHByb3BzXG4gICAgY29uc3Qge29wYWNpdHksIHBpY2thYmxlLCBhdXRvSGlnaGxpZ2h0LCBoaWdobGlnaHRDb2xvcn0gPSB0aGlzLnByb3BzO1xuXG4gICAgLy8gcmV0dXJuIHByb3BzIHRvIHRoZSBzdWJsYXllciBjb25zdHJ1Y3RvclxuICAgIHJldHVybiBuZXcgU2NhdHRlcnBsb3RMYXllcih7XG4gICAgICBpZDogYCR7aWR9LWNsdXN0ZXJgLFxuICAgICAgZGF0YTogdGhpcy5zdGF0ZS5jbHVzdGVycyxcbiAgICAgIHJhZGl1c1NjYWxlLFxuICAgICAgZnA2NCxcbiAgICAgIG9wYWNpdHksXG4gICAgICBwaWNrYWJsZSxcbiAgICAgIGF1dG9IaWdobGlnaHQsXG4gICAgICBoaWdobGlnaHRDb2xvcixcbiAgICAgIGdldFBvc2l0aW9uOiBkID0+IGQuZ2VvbWV0cnkuY29vcmRpbmF0ZXMsXG4gICAgICBnZXRSYWRpdXM6IHRoaXMuX29uR2V0U3VibGF5ZXJSYWRpdXMuYmluZCh0aGlzKSxcbiAgICAgIGdldENvbG9yOiB0aGlzLl9vbkdldFN1YmxheWVyQ29sb3IuYmluZCh0aGlzKSxcbiAgICAgIHVwZGF0ZVRyaWdnZXJzOiB0aGlzLmdldFVwZGF0ZVRyaWdnZXJzKClcbiAgICB9KTtcbiAgfVxufVxuXG5DbHVzdGVyTGF5ZXIubGF5ZXJOYW1lID0gJ0NsdXN0ZXJMYXllcic7XG5DbHVzdGVyTGF5ZXIuZGVmYXVsdFByb3BzID0gZGVmYXVsdFByb3BzO1xuIl19