UNPKG

kepler.gl

Version:

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

642 lines (553 loc) 67.4 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.getValueFunc = getValueFunc; exports.getScaleFunctor = getScaleFunctor; exports.getGetValue = getGetValue; exports.getDimensionSortedBins = getDimensionSortedBins; exports.getDimensionValueDomain = getDimensionValueDomain; exports.getDimensionScale = getDimensionScale; exports.getAggregatedData = getAggregatedData; exports["default"] = exports.defaultDimensions = exports.defaultElevationDimension = exports.defaultColorDimension = exports.defaultAggregation = exports.DECK_AGGREGATION_MAP = void 0; var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _aggregationLayers = require("@deck.gl/aggregation-layers"); var _window = require("global/window"); var _aggregateUtils = require("../../utils/aggregate-utils"); var _defaultSettings = require("../../constants/default-settings"); var _DECK_AGGREGATION_MAP; 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 DECK_AGGREGATION_MAP = (_DECK_AGGREGATION_MAP = {}, (0, _defineProperty2["default"])(_DECK_AGGREGATION_MAP, _aggregationLayers.AGGREGATION_OPERATION.SUM, _defaultSettings.AGGREGATION_TYPES.sum), (0, _defineProperty2["default"])(_DECK_AGGREGATION_MAP, _aggregationLayers.AGGREGATION_OPERATION.MEAN, _defaultSettings.AGGREGATION_TYPES.average), (0, _defineProperty2["default"])(_DECK_AGGREGATION_MAP, _aggregationLayers.AGGREGATION_OPERATION.MIN, _defaultSettings.AGGREGATION_TYPES.minimum), (0, _defineProperty2["default"])(_DECK_AGGREGATION_MAP, _aggregationLayers.AGGREGATION_OPERATION.MAX, _defaultSettings.AGGREGATION_TYPES.maximum), _DECK_AGGREGATION_MAP); exports.DECK_AGGREGATION_MAP = DECK_AGGREGATION_MAP; function getValueFunc(aggregation, accessor) { if (!aggregation || !_aggregationLayers.AGGREGATION_OPERATION[aggregation.toUpperCase()]) { _window.console.warn("Aggregation ".concat(aggregation, " is not supported")); } var op = _aggregationLayers.AGGREGATION_OPERATION[aggregation.toUpperCase()] || _aggregationLayers.AGGREGATION_OPERATION.SUM; var keplerOp = DECK_AGGREGATION_MAP[op]; return function (pts) { return (0, _aggregateUtils.aggregate)(pts.map(accessor), keplerOp); }; } function getScaleFunctor(scaleType) { if (!scaleType || !_defaultSettings.SCALE_FUNC[scaleType]) { _window.console.warn("Scale ".concat(scaleType, " is not supported")); } return _defaultSettings.SCALE_FUNC[scaleType] || _defaultSettings.SCALE_FUNC.quantize; } function nop() {} function getGetValue(step, props, dimensionUpdater) { var key = dimensionUpdater.key; var _step$triggers = step.triggers, value = _step$triggers.value, weight = _step$triggers.weight, aggregation = _step$triggers.aggregation; var getValue = props[value.prop]; if (getValue === null) { // If `getValue` is not provided from props, build it with aggregation and weight. getValue = getValueFunc(props[aggregation.prop], props[weight.prop]); } if (getValue) { this._setDimensionState(key, { getValue: getValue }); } } function getDimensionSortedBins(step, props, dimensionUpdater) { var key = dimensionUpdater.key; var getValue = this.state.dimensions[key].getValue; var sortedBins = new _aggregationLayers._BinSorter(this.state.layerData.data || [], { getValue: getValue, filterData: props._filterData }); this._setDimensionState(key, { sortedBins: sortedBins }); } function getDimensionValueDomain(step, props, dimensionUpdater) { var key = dimensionUpdater.key; var _step$triggers2 = step.triggers, lowerPercentile = _step$triggers2.lowerPercentile, upperPercentile = _step$triggers2.upperPercentile, scaleType = _step$triggers2.scaleType; if (!this.state.dimensions[key].sortedBins) { // the previous step should set sortedBins, if not, something went wrong return; } // for log and sqrt scale, returns linear domain by default // TODO: support other scale function domain in bin sorter var valueDomain = this.state.dimensions[key].sortedBins.getValueDomainByScale(props[scaleType.prop], [props[lowerPercentile.prop], props[upperPercentile.prop]]); this._setDimensionState(key, { valueDomain: valueDomain }); } function getDimensionScale(step, props, dimensionUpdater) { var key = dimensionUpdater.key; var _step$triggers3 = step.triggers, domain = _step$triggers3.domain, range = _step$triggers3.range, scaleType = _step$triggers3.scaleType; var onSet = step.onSet; if (!this.state.dimensions[key].valueDomain) { // the previous step should set valueDomain, if not, something went wrong return; } var dimensionRange = props[range.prop]; var dimensionDomain = props[domain.prop] || this.state.dimensions[key].valueDomain; var scaleFunctor = getScaleFunctor(scaleType && props[scaleType.prop])(); var scaleFunc = scaleFunctor.domain(dimensionDomain).range(dimensionRange); if ((0, _typeof2["default"])(onSet) === 'object' && typeof props[onSet.props] === 'function') { props[onSet.props](scaleFunc.domain()); } this._setDimensionState(key, { scaleFunc: scaleFunc }); } function normalizeResult() { var result = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; // support previous hexagonAggregator API if (result.hexagons) { return Object.assign({ data: result.hexagons }, result); } else if (result.layerData) { return Object.assign({ data: result.layerData }, result); } return result; } function getAggregatedData(step, props, aggregation, aggregationParams) { var aggr = step.triggers.aggregator; var aggregator = props[aggr.prop]; // result should contain a data array and other props // result = {data: [], ...other props} var result = aggregator(props, aggregationParams); this.setState({ layerData: normalizeResult(result) }); } var defaultAggregation = { key: 'position', updateSteps: [{ key: 'aggregate', triggers: { cellSize: { prop: 'cellSize' }, position: { prop: 'getPosition', updateTrigger: 'getPosition' }, aggregator: { prop: 'gridAggregator' } }, updater: getAggregatedData }] }; exports.defaultAggregation = defaultAggregation; function getSubLayerAccessor(dimensionState, dimension, layerProps) { return function (cell) { var sortedBins = dimensionState.sortedBins, scaleFunc = dimensionState.scaleFunc; var bin = sortedBins.binMap[cell.index]; if (bin && bin.counts === 0) { // no points left in bin after filtering return dimension.nullValue; } var cv = bin && bin.value; var domain = scaleFunc.domain(); var isValueInDomain = cv >= domain[0] && cv <= domain[domain.length - 1]; // if cell value is outside domain, set alpha to 0 return isValueInDomain ? scaleFunc(cv) : dimension.nullValue; }; } var defaultColorDimension = { key: 'fillColor', accessor: 'getFillColor', getPickingInfo: function getPickingInfo(dimensionState, cell) { var sortedBins = dimensionState.sortedBins; var colorValue = sortedBins.binMap[cell.index] && sortedBins.binMap[cell.index].value; return { colorValue: colorValue }; }, nullValue: [0, 0, 0, 0], updateSteps: [{ key: 'getValue', triggers: { value: { prop: 'getColorValue', updateTrigger: 'getColorValue' }, weight: { prop: 'getColorWeight', updateTrigger: 'getColorWeight' }, aggregation: { prop: 'colorAggregation' } }, updater: getGetValue }, { key: 'getBins', triggers: { _filterData: { prop: '_filterData', updateTrigger: '_filterData' } }, updater: getDimensionSortedBins }, { key: 'getDomain', triggers: { lowerPercentile: { prop: 'lowerPercentile' }, upperPercentile: { prop: 'upperPercentile' }, scaleType: { prop: 'colorScaleType' } }, updater: getDimensionValueDomain }, { key: 'getScaleFunc', triggers: { domain: { prop: 'colorDomain' }, range: { prop: 'colorRange' }, scaleType: { prop: 'colorScaleType' } }, onSet: { props: 'onSetColorDomain' }, updater: getDimensionScale }], getSubLayerAccessor: getSubLayerAccessor }; exports.defaultColorDimension = defaultColorDimension; var defaultElevationDimension = { key: 'elevation', accessor: 'getElevation', getPickingInfo: function getPickingInfo(dimensionState, cell) { var sortedBins = dimensionState.sortedBins; var elevationValue = sortedBins.binMap[cell.index] && sortedBins.binMap[cell.index].value; return { elevationValue: elevationValue }; }, nullValue: -1, updateSteps: [{ key: 'getValue', triggers: { value: { prop: 'getElevationValue', updateTrigger: 'getElevationValue' }, weight: { prop: 'getElevationWeight', updateTrigger: 'getElevationWeight' }, aggregation: { prop: 'elevationAggregation' } }, updater: getGetValue }, { key: 'getBins', triggers: { _filterData: { prop: '_filterData', updateTrigger: '_filterData' } }, updater: getDimensionSortedBins }, { key: 'getDomain', triggers: { lowerPercentile: { prop: 'elevationLowerPercentile' }, upperPercentile: { prop: 'elevationUpperPercentile' }, scaleType: { prop: 'elevationScaleType' } }, updater: getDimensionValueDomain }, { key: 'getScaleFunc', triggers: { domain: { prop: 'elevationDomain' }, range: { prop: 'elevationRange' }, scaleType: { prop: 'elevationScaleType' } }, onSet: { props: 'onSetElevationDomain' }, updater: getDimensionScale }], getSubLayerAccessor: getSubLayerAccessor }; exports.defaultElevationDimension = defaultElevationDimension; var _defaultDimensions = [defaultColorDimension, defaultElevationDimension]; exports.defaultDimensions = _defaultDimensions; var CPUAggregator = /*#__PURE__*/ function () { function CPUAggregator() { var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; (0, _classCallCheck2["default"])(this, CPUAggregator); this.state = _objectSpread({ layerData: {}, dimensions: {// color: { // getValue: null, // domain: null, // sortedBins: null, // scaleFunc: nop // }, // elevation: { // getValue: null, // domain: null, // sortedBins: null, // scaleFunc: nop // } } }, opts.initialState); this.dimensionUpdaters = {}; this.aggregationUpdater = {}; this._addDimension(opts.dimensions || _defaultDimensions); this._addAggregation(opts.aggregation || defaultAggregation); } (0, _createClass2["default"])(CPUAggregator, [{ key: "updateAllDimensions", value: function updateAllDimensions(props) { var dimensionChanges = []; // update all dimensions for (var dim in this.dimensionUpdaters) { var updaters = this._accumulateUpdaters(0, props, this.dimensionUpdaters[dim]); dimensionChanges = dimensionChanges.concat(updaters); } dimensionChanges.forEach(function (f) { return typeof f === 'function' && f(); }); } }, { key: "updateAggregation", value: function updateAggregation(props, aggregationParams) { var updaters = this._accumulateUpdaters(0, props, this.aggregationUpdater); updaters.forEach(function (f) { return typeof f === 'function' && f(aggregationParams); }); } }, { key: "updateState", value: function updateState(opts, aggregationParams) { var oldProps = opts.oldProps, props = opts.props, changeFlags = opts.changeFlags; var dimensionChanges = []; if (changeFlags.dataChanged) { // if data changed update everything this.updateAggregation(props, aggregationParams); this.updateAllDimensions(props); return this.state; } var aggregationChanges = this._getAggregationChanges(oldProps, props, changeFlags); if (aggregationChanges && aggregationChanges.length) { // get aggregatedData aggregationChanges.forEach(function (f) { return typeof f === 'function' && f(aggregationParams); }); this.updateAllDimensions(props); } else { // only update dimensions dimensionChanges = this._getDimensionChanges(oldProps, props, changeFlags) || []; dimensionChanges.forEach(function (f) { return typeof f === 'function' && f(); }); } return this.state; } // Update private state }, { key: "setState", value: function setState(updateObject) { this.state = Object.assign({}, this.state, updateObject); } // Update private state.dimensions }, { key: "_setDimensionState", value: function _setDimensionState(key, updateObject) { this.setState({ dimensions: Object.assign({}, this.state.dimensions, (0, _defineProperty2["default"])({}, key, Object.assign({}, this.state.dimensions[key], updateObject))) }); } }, { key: "_addAggregation", value: function _addAggregation(aggregation) { this.aggregationUpdater = aggregation; } }, { key: "_addDimension", value: function _addDimension() { var _this = this; var dimensions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; dimensions.forEach(function (dimension) { var key = dimension.key; _this.dimensionUpdaters[key] = dimension; }); } }, { key: "_needUpdateStep", value: function _needUpdateStep(dimensionStep, oldProps, props, changeFlags) { // whether need to update current dimension step // dimension step is the value, domain, scaleFunction of each dimension // each step is an object with properties links to layer prop and whether the prop is // controlled by updateTriggers return Object.values(dimensionStep.triggers).some(function (item) { if (item.updateTrigger) { // check based on updateTriggers change first return changeFlags.updateTriggersChanged && (changeFlags.updateTriggersChanged.all || changeFlags.updateTriggersChanged[item.updateTrigger]); } // fallback to direct comparison return oldProps[item.prop] !== props[item.prop]; }); } }, { key: "_accumulateUpdaters", value: function _accumulateUpdaters(step, props, dimension) { var updaters = []; for (var i = step; i < dimension.updateSteps.length; i++) { if (typeof dimension.updateSteps[i].updater === 'function') { updaters.push(dimension.updateSteps[i].updater.bind(this, dimension.updateSteps[i], props, dimension)); } } return updaters; } }, { key: "_getAllUpdaters", value: function _getAllUpdaters(dimension, oldProps, props, changeFlags) { var _this2 = this; var updaters = []; var needUpdateStep = dimension.updateSteps.findIndex(function (step) { return _this2._needUpdateStep(step, oldProps, props, changeFlags); }); if (needUpdateStep > -1) { updaters = updaters.concat(this._accumulateUpdaters(needUpdateStep, props, dimension)); } return updaters; } }, { key: "_getAggregationChanges", value: function _getAggregationChanges(oldProps, props, changeFlags) { var updaters = this._getAllUpdaters(this.aggregationUpdater, oldProps, props, changeFlags); return updaters.length ? updaters : null; } }, { key: "_getDimensionChanges", value: function _getDimensionChanges(oldProps, props, changeFlags) { var updaters = []; // get dimension to be updated for (var key in this.dimensionUpdaters) { // return the first triggered updater for each dimension var dimension = this.dimensionUpdaters[key]; var dimensionUpdaters = this._getAllUpdaters(dimension, oldProps, props, changeFlags); updaters = updaters.concat(dimensionUpdaters); } return updaters.length ? updaters : null; } }, { key: "getUpdateTriggers", value: function getUpdateTriggers(props) { var _this3 = this; var _updateTriggers = props.updateTriggers || {}; var updateTriggers = {}; var _loop = function _loop(key) { var _this3$dimensionUpdat = _this3.dimensionUpdaters[key], accessor = _this3$dimensionUpdat.accessor, updateSteps = _this3$dimensionUpdat.updateSteps; // fold dimension triggers into each accessor updateTriggers[accessor] = {}; updateSteps.forEach(function (step) { Object.values(step.triggers || []).forEach(function (_ref) { var prop = _ref.prop, updateTrigger = _ref.updateTrigger; if (updateTrigger) { // if prop is based on updateTrigger e.g. getColorValue, getColorWeight // and updateTriggers is passed in from layer prop // fold the updateTriggers into accessor var fromProp = _updateTriggers[updateTrigger]; if ((0, _typeof2["default"])(fromProp) === 'object' && !Array.isArray(fromProp)) { // if updateTrigger is an object spread it Object.assign(updateTriggers[accessor], fromProp); } else if (fromProp !== undefined) { updateTriggers[accessor][prop] = fromProp; } } else { // if prop is not based on updateTrigger updateTriggers[accessor][prop] = props[prop]; } }); }); }; for (var key in this.dimensionUpdaters) { _loop(key); } return updateTriggers; } }, { key: "getPickingInfo", value: function getPickingInfo(_ref2, layerProps) { var info = _ref2.info; var isPicked = info.picked && info.index > -1; var object = null; if (isPicked) { var cell = this.state.layerData.data[info.index]; var binInfo = {}; for (var key in this.dimensionUpdaters) { var getPickingInfo = this.dimensionUpdaters[key].getPickingInfo; if (typeof getPickingInfo === 'function') { binInfo = Object.assign({}, binInfo, getPickingInfo(this.state.dimensions[key], cell, layerProps)); } } object = Object.assign(binInfo, cell, { points: cell.filteredPoints || cell.points }); } // add bin and to info return Object.assign(info, { picked: Boolean(object), // override object with picked cell object: object }); } }, { key: "getAccessor", value: function getAccessor(dimensionKey, layerProps) { if (!this.dimensionUpdaters.hasOwnProperty(dimensionKey)) { return nop; } return this.dimensionUpdaters[dimensionKey].getSubLayerAccessor(this.state.dimensions[dimensionKey], this.dimensionUpdaters[dimensionKey], layerProps); } }], [{ key: "defaultDimensions", value: function defaultDimensions() { return _defaultDimensions; } }]); return CPUAggregator; }(); exports["default"] = CPUAggregator; CPUAggregator.getDimensionScale = getDimensionScale; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9kZWNrZ2wtbGF5ZXJzL2xheWVyLXV0aWxzL2NwdS1hZ2dyZWdhdG9yLmpzIl0sIm5hbWVzIjpbIkRFQ0tfQUdHUkVHQVRJT05fTUFQIiwiQUdHUkVHQVRJT05fT1BFUkFUSU9OIiwiU1VNIiwiQUdHUkVHQVRJT05fVFlQRVMiLCJzdW0iLCJNRUFOIiwiYXZlcmFnZSIsIk1JTiIsIm1pbmltdW0iLCJNQVgiLCJtYXhpbXVtIiwiZ2V0VmFsdWVGdW5jIiwiYWdncmVnYXRpb24iLCJhY2Nlc3NvciIsInRvVXBwZXJDYXNlIiwiQ29uc29sZSIsIndhcm4iLCJvcCIsImtlcGxlck9wIiwicHRzIiwibWFwIiwiZ2V0U2NhbGVGdW5jdG9yIiwic2NhbGVUeXBlIiwiU0NBTEVfRlVOQyIsInF1YW50aXplIiwibm9wIiwiZ2V0R2V0VmFsdWUiLCJzdGVwIiwicHJvcHMiLCJkaW1lbnNpb25VcGRhdGVyIiwia2V5IiwidHJpZ2dlcnMiLCJ2YWx1ZSIsIndlaWdodCIsImdldFZhbHVlIiwicHJvcCIsIl9zZXREaW1lbnNpb25TdGF0ZSIsImdldERpbWVuc2lvblNvcnRlZEJpbnMiLCJzdGF0ZSIsImRpbWVuc2lvbnMiLCJzb3J0ZWRCaW5zIiwiQmluU29ydGVyIiwibGF5ZXJEYXRhIiwiZGF0YSIsImZpbHRlckRhdGEiLCJfZmlsdGVyRGF0YSIsImdldERpbWVuc2lvblZhbHVlRG9tYWluIiwibG93ZXJQZXJjZW50aWxlIiwidXBwZXJQZXJjZW50aWxlIiwidmFsdWVEb21haW4iLCJnZXRWYWx1ZURvbWFpbkJ5U2NhbGUiLCJnZXREaW1lbnNpb25TY2FsZSIsImRvbWFpbiIsInJhbmdlIiwib25TZXQiLCJkaW1lbnNpb25SYW5nZSIsImRpbWVuc2lvbkRvbWFpbiIsInNjYWxlRnVuY3RvciIsInNjYWxlRnVuYyIsIm5vcm1hbGl6ZVJlc3VsdCIsInJlc3VsdCIsImhleGFnb25zIiwiT2JqZWN0IiwiYXNzaWduIiwiZ2V0QWdncmVnYXRlZERhdGEiLCJhZ2dyZWdhdGlvblBhcmFtcyIsImFnZ3IiLCJhZ2dyZWdhdG9yIiwic2V0U3RhdGUiLCJkZWZhdWx0QWdncmVnYXRpb24iLCJ1cGRhdGVTdGVwcyIsImNlbGxTaXplIiwicG9zaXRpb24iLCJ1cGRhdGVUcmlnZ2VyIiwidXBkYXRlciIsImdldFN1YkxheWVyQWNjZXNzb3IiLCJkaW1lbnNpb25TdGF0ZSIsImRpbWVuc2lvbiIsImxheWVyUHJvcHMiLCJjZWxsIiwiYmluIiwiYmluTWFwIiwiaW5kZXgiLCJjb3VudHMiLCJudWxsVmFsdWUiLCJjdiIsImlzVmFsdWVJbkRvbWFpbiIsImxlbmd0aCIsImRlZmF1bHRDb2xvckRpbWVuc2lvbiIsImdldFBpY2tpbmdJbmZvIiwiY29sb3JWYWx1ZSIsImRlZmF1bHRFbGV2YXRpb25EaW1lbnNpb24iLCJlbGV2YXRpb25WYWx1ZSIsImRlZmF1bHREaW1lbnNpb25zIiwiQ1BVQWdncmVnYXRvciIsIm9wdHMiLCJpbml0aWFsU3RhdGUiLCJkaW1lbnNpb25VcGRhdGVycyIsImFnZ3JlZ2F0aW9uVXBkYXRlciIsIl9hZGREaW1lbnNpb24iLCJfYWRkQWdncmVnYXRpb24iLCJkaW1lbnNpb25DaGFuZ2VzIiwiZGltIiwidXBkYXRlcnMiLCJfYWNjdW11bGF0ZVVwZGF0ZXJzIiwiY29uY2F0IiwiZm9yRWFjaCIsImYiLCJvbGRQcm9wcyIsImNoYW5nZUZsYWdzIiwiZGF0YUNoYW5nZWQiLCJ1cGRhdGVBZ2dyZWdhdGlvbiIsInVwZGF0ZUFsbERpbWVuc2lvbnMiLCJhZ2dyZWdhdGlvbkNoYW5nZXMiLCJfZ2V0QWdncmVnYXRpb25DaGFuZ2VzIiwiX2dldERpbWVuc2lvbkNoYW5nZXMiLCJ1cGRhdGVPYmplY3QiLCJkaW1lbnNpb25TdGVwIiwidmFsdWVzIiwic29tZSIsIml0ZW0iLCJ1cGRhdGVUcmlnZ2Vyc0NoYW5nZWQiLCJhbGwiLCJpIiwicHVzaCIsImJpbmQiLCJuZWVkVXBkYXRlU3RlcCIsImZpbmRJbmRleCIsIl9uZWVkVXBkYXRlU3RlcCIsIl9nZXRBbGxVcGRhdGVycyIsIl91cGRhdGVUcmlnZ2VycyIsInVwZGF0ZVRyaWdnZXJzIiwiZnJvbVByb3AiLCJBcnJheSIsImlzQXJyYXkiLCJ1bmRlZmluZWQiLCJpbmZvIiwiaXNQaWNrZWQiLCJwaWNrZWQiLCJvYmplY3QiLCJiaW5JbmZvIiwicG9pbnRzIiwiZmlsdGVyZWRQb2ludHMiLCJCb29sZWFuIiwiZGltZW5zaW9uS2V5IiwiaGFzT3duUHJvcGVydHkiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQXFCQTs7QUFDQTs7QUFFQTs7QUFDQTs7Ozs7Ozs7QUFFTyxJQUFNQSxvQkFBb0Isd0ZBQzlCQyx5Q0FBc0JDLEdBRFEsRUFDRkMsbUNBQWtCQyxHQURoQiwyREFFOUJILHlDQUFzQkksSUFGUSxFQUVERixtQ0FBa0JHLE9BRmpCLDJEQUc5QkwseUNBQXNCTSxHQUhRLEVBR0ZKLG1DQUFrQkssT0FIaEIsMkRBSTlCUCx5Q0FBc0JRLEdBSlEsRUFJRk4sbUNBQWtCTyxPQUpoQix5QkFBMUI7OztBQU9BLFNBQVNDLFlBQVQsQ0FBc0JDLFdBQXRCLEVBQW1DQyxRQUFuQyxFQUE2QztBQUNsRCxNQUFJLENBQUNELFdBQUQsSUFBZ0IsQ0FBQ1gseUNBQXNCVyxXQUFXLENBQUNFLFdBQVosRUFBdEIsQ0FBckIsRUFBdUU7QUFDckVDLG9CQUFRQyxJQUFSLHVCQUE0QkosV0FBNUI7QUFDRDs7QUFFRCxNQUFNSyxFQUFFLEdBQUdoQix5Q0FBc0JXLFdBQVcsQ0FBQ0UsV0FBWixFQUF0QixLQUFvRGIseUNBQXNCQyxHQUFyRjs7QUFDQSxNQUFNZ0IsUUFBUSxHQUFHbEIsb0JBQW9CLENBQUNpQixFQUFELENBQXJDO0FBRUEsU0FBTyxVQUFBRSxHQUFHO0FBQUEsV0FBSSwrQkFBVUEsR0FBRyxDQUFDQyxHQUFKLENBQVFQLFFBQVIsQ0FBVixFQUE2QkssUUFBN0IsQ0FBSjtBQUFBLEdBQVY7QUFDRDs7QUFFTSxTQUFTRyxlQUFULENBQXlCQyxTQUF6QixFQUFvQztBQUN6QyxNQUFJLENB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QkFBTCxDQUF1QitDLFlBQXZCLEVBQXFDckUsbUJBQXJDLENBQ0wsS0FBS3JDLEtBQUwsQ0FBV0MsVUFBWCxDQUFzQnlHLFlBQXRCLENBREssRUFFTCxLQUFLL0MsaUJBQUwsQ0FBdUIrQyxZQUF2QixDQUZLLEVBR0xsRSxVQUhLLENBQVA7QUFLRDs7O3dDQWxOMEI7QUFDekIsYUFBT2Usa0JBQVA7QUFDRDs7Ozs7O0FBbU5IQyxhQUFhLENBQUMzQyxpQkFBZCxHQUFrQ0EsaUJBQWxDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IChjKSAyMDIwIFViZXIgVGVjaG5vbG9naWVzLCBJbmMuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuLy8gb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbFxuLy8gaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0c1xuLy8gdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbFxuLy8gY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzXG4vLyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4vLyBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSxcbi8vIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuLy8gQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuLy8gTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSxcbi8vIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbi8vIFRIRSBTT0ZUV0FSRS5cblxuLyogZXNsaW50LWRpc2FibGUgZ3VhcmQtZm9yLWluICovXG5pbXBvcnQge19CaW5Tb3J0ZXIgYXMgQmluU29ydGVyLCBBR0dSRUdBVElPTl9PUEVSQVRJT059IGZyb20gJ0BkZWNrLmdsL2FnZ3JlZ2F0aW9uLWxheWVycyc7XG5pbXBvcnQge2NvbnNvbGUgYXMgQ29uc29sZX0gZnJvbSAnZ2xvYmFsL3dpbmRvdyc7XG5cbmltcG9ydCB7YWdncmVnYXRlfSBmcm9tICd1dGlscy9hZ2dyZWdhdGUtdXRpbHMnO1xuaW1wb3J0IHtBR0dSRUdBVElPTl9UWVBFUywgU0NBTEVfRlVOQ30gZnJvbSAnY29uc3RhbnRzL2RlZmF1bHQtc2V0dGluZ3MnO1xuXG5leHBvcnQgY29uc3QgREVDS19BR0dSRUdBVElPTl9NQVAgPSB7XG4gIFtBR0dSRUdBVElPTl9PUEVSQVRJT04uU1VNXTogQUdHUkVHQVRJT05fVFlQRVMuc3VtLFxuICBbQUdHUkVHQVRJT05fT1BFUkFUSU9OLk1FQU5dOiBBR0dSRUdBVElPTl9UWVBFUy5hdmVyYWdlLFxuICBbQUdHUkVHQVRJT05fT1BFUkFUSU9OLk1JTl06IEFHR1JFR0FUSU9OX1RZUEVTLm1pbmltdW0sXG4gIFtBR0dSRUdBVElPTl9PUEVSQVRJT04uTUFYXTogQUdHUkVHQVRJT05fVFlQRVMubWF4aW11bVxufTtcblxuZXhwb3J0IGZ1bmN0aW9uIGdldFZhbHVlRnVuYyhhZ2dyZWdhdGlvbiwgYWNjZXNzb3IpIHtcbiAgaWYgKCFhZ2dyZWdhdGlvbiB8fCAhQUdHUkVHQVRJT05fT1BFUkFUSU9OW2FnZ3JlZ2F0aW9uLnRvVXBwZXJDYXNlKCldKSB7XG4gICAgQ29uc29sZS53YXJuKGBBZ2dyZWdhdGlvbiAke2FnZ3JlZ2F0aW9ufSBpcyBub3Qgc3VwcG9ydGVkYCk7XG4gIH1cblxuICBjb25zdCBvcCA9IEFHR1JFR0FUSU9OX09QRVJBVElPTlthZ2dyZWdhdGlvbi50b1VwcGVyQ2FzZSgpXSB8fCBBR0dSRUdBVElPTl9PUEVSQVRJT04uU1VNO1xuICBjb25zdCBrZXBsZXJPcCA9IERFQ0tfQUdHUkVHQVRJT05fTUFQW29wXTtcblxuICByZXR1cm4gcHRzID0+IGFnZ3JlZ2F0ZShwdHMubWFwKGFjY2Vzc29yKSwga2VwbGVyT3ApO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0U2NhbGVGdW5jdG9yKHNjYWxlVHlwZSkge1xuICBpZiAoIXNjYWxlVHlwZSB8fCAhU0NBTEVfRlVOQ1tzY2FsZVR5cGVdKSB7XG4gICAgQ29uc29sZS53YXJuKGBTY2FsZSAke3NjYWxlVHlwZX0gaXMgbm90IHN1cHBvcnRlZGApO1xuICB9XG4gIHJldHVybiBTQ0FMRV9GVU5DW3NjYWxlVHlwZV0gfHwgU0NBTEVfRlVOQy5xdWFudGl6ZTtcbn1cblxuZnVuY3Rpb24gbm9wKCkge31cblxuZXhwb3J0IGZ1bmN0aW9uIGdldEdldFZhbHVlKHN0ZXAsIHByb3BzLCBkaW1lbnNpb25VcGRhdGVyKSB7XG4gIGNvbnN0IHtrZXl9ID0gZGltZW5zaW9uVXBkYXRlcjtcbiAgY29uc3Qge3ZhbHVlLCB3ZWlnaHQsIGFnZ3JlZ2F0aW9ufSA9IHN0ZXAudHJpZ2dlcnM7XG5cbiAgbGV0IGdldFZhbHVlID0gcHJvcHNbdmFsdWUucHJvcF07XG5cbiAgaWYgKGdldFZhbHVlID09PSBudWxsKSB7XG4gICAgLy8gSWYgYGdldFZhbHVlYCBpcyBub3QgcHJvdmlkZWQgZnJvbSBwcm9wcywgYnVpbGQgaXQgd2l0aCBhZ2dyZWdhdGlvbiBhbmQgd2VpZ2h0LlxuICAgIGdldFZhbHVlID0gZ2V0VmFsdWVGdW5jKHByb3BzW2FnZ3JlZ2F0aW9uLnByb3BdLCBwcm9wc1t3ZWlnaHQucHJvcF0pO1xuICB9XG5cbiAgaWYgKGdldFZhbHVlKSB7XG4gICAgdGhpcy5fc2V0RGltZW5zaW9uU3RhdGUoa2V5LCB7Z2V0VmFsdWV9KTtcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0RGltZW5zaW9uU29ydGVkQmlucyhzdGVwLCBwcm9wcywgZGltZW5zaW9uVXBkYXRlcikge1xuICBjb25zdCB7a2V5fSA9IGRpbWVuc2lvblVwZGF0ZXI7XG4gIGNvbnN0IHtnZXRWYWx1ZX0gPSB0aGlzLnN0YXRlLmRpbWVuc2lvbnNba2V5XTtcblxuICBjb25zdCBzb3J0ZWRCaW5zID0gbmV3IEJpblNvcnRlcih0aGlzLnN0YXRlLmxheWVyRGF0YS5kYXRhIHx8IFtdLCB7XG4gICAgZ2V0VmFsdWUsXG4gICAgZmlsdGVyRGF0YTogcHJvcHMuX2ZpbHRlckRhdGFcbiAgfSk7XG4gIHRoaXMuX3NldERpbWVuc2lvblN0YXRlKGtleSwge3NvcnRlZEJpbnN9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldERpbWVuc2lvblZhbHVlRG9tYWluKHN0ZXAsIHByb3BzLCBkaW1lbnNpb25VcGRhdGVyKSB7XG4gIGNvbnN0IHtrZXl9ID0gZGltZW5zaW9uVXBkYXRlcjtcbiAgY29uc3Qge1xuICAgIHRyaWdnZXJzOiB7bG93ZXJQZXJjZW50aWxlLCB1cHBlclBlcmNlbnRpbGUsIHNjYWxlVHlwZX1cbiAgfSA9IHN0ZXA7XG5cbiAgaWYgKCF0aGlzLnN0YXRlLmRpbWVuc2lvbnNba2V5XS5zb3J0ZWRCaW5zKSB7XG4gICAgLy8gdGhlIHByZXZpb3VzIHN0ZXAgc2hvdWxkIHNldCBzb3J0ZWRCaW5zLCBpZiBub3QsIHNvbWV0aGluZyB3ZW50IHdyb25nXG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gZm9yIGxvZyBhbmQgc3FydCBzY2FsZSwgcmV0dXJucyBsaW5lYXIgZG9tYWluIGJ5IGRlZmF1bHRcbiAgLy8gVE9ETzogc3VwcG9ydCBvdGhlciBzY2FsZSBmdW5jdGlvbiBkb21haW4gaW4gYmluIHNvcnRlclxuICBjb25zdCB2YWx1ZURvbWFpbiA9IHRoaXMuc3RhdGUuZGltZW5zaW9uc1trZXldLnNvcnRlZEJpbnMuZ2V0VmFsdWVEb21haW5CeVNjYWxlKFxuICAgIHByb3BzW3NjYWxlVHlwZS5wcm9wXSxcbiAgICBbcHJvcHNbbG93ZXJQZXJjZW50aWxlLnByb3BdLCBwcm9wc1t1cHBlclBlcmNlbnRpbGUucHJvcF1dXG4gICk7XG5cbiAgdGhpcy5fc2V0RGltZW5zaW9uU3RhdGUoa2V5LCB7dmFsdWVEb21haW59KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldERpbWVuc2lvblNjYWxlKHN0ZXAsIHByb3BzLCBkaW1lbnNpb25VcGRhdGVyKSB7XG4gIGNvbnN0IHtrZXl9ID0gZGltZW5zaW9uVXBkYXRlcjtcbiAgY29uc3Qge2RvbWFpbiwgcmFuZ2UsIHNjYWxlVHlwZX0gPSBzdGVwLnRyaWdnZXJzO1xuICBjb25zdCB7b25TZXR9ID0gc3RlcDtcbiAgaWYgKCF0aGlzLnN0YXRlLmRpbWVuc2lvbnNba2V5XS52YWx1ZURvbWFpbikge1xuICAgIC8vIHRoZSBwcmV2aW91cyBzdGVwIHNob3VsZCBzZXQgdmFsdWVEb21haW4sIGlmIG5vdCwgc29tZXRoaW5nIHdlbnQgd3JvbmdcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCBkaW1lbnNpb25SYW5nZSA9IHByb3BzW3JhbmdlLnByb3BdO1xuICBjb25zdCBkaW1lbnNpb25Eb21haW4gPSBwcm9wc1tkb21haW4ucHJvcF0gfHwgdGhpcy5zdGF0ZS5kaW1lbnNpb25zW2tleV0udmFsdWVEb21haW47XG5cbiAgY29uc3Qgc2NhbGVGdW5jdG9yID0gZ2V0U2NhbGVGdW5jdG9yK