kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
798 lines (791 loc) • 106 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.defaultElevationDimension = exports.defaultDimensions = exports.defaultColorDimension = exports.defaultAggregation = exports["default"] = exports.DECK_AGGREGATION_MAP = void 0;
exports.getAggregatedData = getAggregatedData;
exports.getDimensionScale = getDimensionScale;
exports.getDimensionSortedBins = getDimensionSortedBins;
exports.getDimensionValueDomain = getDimensionValueDomain;
exports.getGetValue = getGetValue;
exports.getScaleFunctor = getScaleFunctor;
exports.getValueFunc = getValueFunc;
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _window = require("global/window");
var _utils = require("@kepler.gl/utils");
var _constants = require("@kepler.gl/constants");
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 _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } // SPDX-License-Identifier: MIT
// Copyright contributors to the kepler.gl project
/* eslint-disable guard-for-in */
var AGGREGATION_OPERATION = {
SUM: 'SUM',
MEAN: 'MEAN',
MIN: 'MIN',
MAX: 'MAX',
COUNT: 'COUNT'
};
var MAX_32_BIT_FLOAT = 3.402823466e38;
var defaultGetValue = function defaultGetValue(points) {
return points.length;
};
var defaultGetPoints = function defaultGetPoints(bin) {
return bin.points;
};
var defaultGetIndex = function defaultGetIndex(bin) {
return bin.index;
};
var ascending = function ascending(a, b) {
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
};
function clamp(value, min, max) {
return Math.max(min, Math.min(max, value));
}
function getQuantileDomain(data, valueAccessor) {
return data.map(valueAccessor).sort(ascending);
}
function getOrdinalDomain(data, valueAccessor) {
return (0, _toConsumableArray2["default"])(new Set(data.map(valueAccessor)));
}
var BinSorter = /*#__PURE__*/function () {
function BinSorter() {
var bins = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
(0, _classCallCheck2["default"])(this, BinSorter);
(0, _defineProperty2["default"])(this, "maxCount", void 0);
(0, _defineProperty2["default"])(this, "maxValue", void 0);
(0, _defineProperty2["default"])(this, "minValue", void 0);
(0, _defineProperty2["default"])(this, "totalCount", void 0);
(0, _defineProperty2["default"])(this, "aggregatedBins", void 0);
(0, _defineProperty2["default"])(this, "sortedBins", void 0);
(0, _defineProperty2["default"])(this, "binMap", void 0);
this.aggregatedBins = this._getAggregatedBins(bins, props);
this._updateMinMaxValues();
this.binMap = this._getBinMap();
}
return (0, _createClass2["default"])(BinSorter, [{
key: "_getAggregatedBins",
value: function _getAggregatedBins(bins, props) {
var _props$getValue = props.getValue,
getValue = _props$getValue === void 0 ? defaultGetValue : _props$getValue,
_props$getPoints = props.getPoints,
getPoints = _props$getPoints === void 0 ? defaultGetPoints : _props$getPoints,
_props$getIndex = props.getIndex,
getIndex = _props$getIndex === void 0 ? defaultGetIndex : _props$getIndex,
filterData = props.filterData;
var hasFilter = typeof filterData === 'function';
var aggregatedBins = [];
var index = 0;
for (var binIndex = 0; binIndex < bins.length; binIndex++) {
var bin = bins[binIndex];
var points = getPoints(bin);
var i = getIndex(bin);
var filteredPoints = hasFilter ? points.filter(filterData) : points;
bin.filteredPoints = hasFilter ? filteredPoints : null;
var value = filteredPoints.length ? getValue(filteredPoints) : null;
if (value !== null && value !== undefined) {
aggregatedBins[index] = {
i: Number.isFinite(i) ? i : binIndex,
value: value,
counts: filteredPoints.length
};
index++;
}
}
return aggregatedBins;
}
}, {
key: "_updateMinMaxValues",
value: function _updateMinMaxValues() {
var maxCount = 0;
var maxValue = -MAX_32_BIT_FLOAT;
var minValue = MAX_32_BIT_FLOAT;
var totalCount = 0;
var _iterator = _createForOfIteratorHelper(this.aggregatedBins),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var x = _step.value;
maxCount = maxCount > x.counts ? maxCount : x.counts;
maxValue = maxValue > x.value ? maxValue : x.value;
minValue = minValue < x.value ? minValue : x.value;
totalCount += x.counts;
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
if (this.aggregatedBins.length === 0) {
maxValue = 0;
minValue = 0;
}
this.maxCount = maxCount;
this.maxValue = maxValue;
this.minValue = minValue;
this.totalCount = totalCount;
}
}, {
key: "_getBinMap",
value: function _getBinMap() {
var binMap = {};
var _iterator2 = _createForOfIteratorHelper(this.aggregatedBins),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var bin = _step2.value;
binMap[bin.i] = bin;
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
return binMap;
}
}, {
key: "_percentileToIndex",
value: function _percentileToIndex(percentileRange) {
var len = this.sortedBins.length;
if (len < 2) return [0, 0];
var _percentileRange$map = percentileRange.map(function (n) {
return clamp(n, 0, 100);
}),
_percentileRange$map2 = (0, _slicedToArray2["default"])(_percentileRange$map, 2),
lower = _percentileRange$map2[0],
upper = _percentileRange$map2[1];
return [Math.ceil(lower / 100 * (len - 1)), Math.floor(upper / 100 * (len - 1))];
}
}, {
key: "getValueDomainByScale",
value: function getValueDomainByScale(scale) {
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [],
_ref2 = (0, _slicedToArray2["default"])(_ref, 2),
_ref2$ = _ref2[0],
lower = _ref2$ === void 0 ? 0 : _ref2$,
_ref2$2 = _ref2[1],
upper = _ref2$2 === void 0 ? 100 : _ref2$2;
if (!this.sortedBins) {
this.sortedBins = this.aggregatedBins.sort(function (a, b) {
return ascending(a.value, b.value);
});
}
if (!this.sortedBins.length) return [];
var indexEdge = this._percentileToIndex([lower, upper]);
return this._getScaleDomain(scale, indexEdge);
}
}, {
key: "_getScaleDomain",
value: function _getScaleDomain(scaleType, _ref3) {
var _ref4 = (0, _slicedToArray2["default"])(_ref3, 2),
lowerIdx = _ref4[0],
upperIdx = _ref4[1];
var bins = this.sortedBins;
switch (scaleType) {
case 'quantize':
case 'linear':
return [bins[lowerIdx].value, bins[upperIdx].value];
case 'quantile':
return getQuantileDomain(bins.slice(lowerIdx, upperIdx + 1), function (d) {
return d.value;
});
case 'ordinal':
return getOrdinalDomain(bins, function (d) {
return d.value;
});
default:
return [bins[lowerIdx].value, bins[upperIdx].value];
}
}
}, {
key: "getValueRange",
value: function getValueRange(percentileRange) {
if (!this.sortedBins) {
this.sortedBins = this.aggregatedBins.sort(function (a, b) {
return ascending(a.value, b.value);
});
}
if (!this.sortedBins.length) return [];
var lowerIdx = 0;
var upperIdx = this.sortedBins.length - 1;
if (Array.isArray(percentileRange)) {
var idxRange = this._percentileToIndex(percentileRange);
lowerIdx = idxRange[0];
upperIdx = idxRange[1];
}
return [this.sortedBins[lowerIdx].value, this.sortedBins[upperIdx].value];
}
}]);
}();
var DECK_AGGREGATION_MAP = exports.DECK_AGGREGATION_MAP = (0, _defineProperty2["default"])((0, _defineProperty2["default"])((0, _defineProperty2["default"])((0, _defineProperty2["default"])({}, AGGREGATION_OPERATION.SUM, _constants.AGGREGATION_TYPES.sum), AGGREGATION_OPERATION.MEAN, _constants.AGGREGATION_TYPES.average), AGGREGATION_OPERATION.MIN, _constants.AGGREGATION_TYPES.minimum), AGGREGATION_OPERATION.MAX, _constants.AGGREGATION_TYPES.maximum);
function getValueFunc(aggregation, accessor) {
if (!aggregation || !AGGREGATION_OPERATION[aggregation.toUpperCase()]) {
_window.console.warn("Aggregation ".concat(aggregation, " is not supported"));
}
var op = AGGREGATION_OPERATION[aggregation.toUpperCase()] || AGGREGATION_OPERATION.SUM;
var keplerOp = DECK_AGGREGATION_MAP[op];
return function (pts) {
return (0, _utils.aggregate)(pts.map(accessor), keplerOp);
};
}
function getScaleFunctor(scaleType) {
if (!scaleType || !_constants.SCALE_FUNC[scaleType]) {
_window.console.warn("Scale ".concat(scaleType, " is not supported"));
}
return _constants.SCALE_FUNC[scaleType] || _constants.SCALE_FUNC.quantize;
}
function nop() {
return;
}
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 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;
}
var valueDomain =
// for log and sqrt scale, returns linear domain by default
// TODO: support other scale function domain in bin sorter
this.state.dimensions[key].sortedBins.getValueDomainByScale(props[scaleType.prop], [props[lowerPercentile.prop], props[upperPercentile.prop]]);
if (props.colorScaleType === 'custom' && props.colorMap) {
// for custom scale, return custom breaks as value domain directly
valueDomain = props.colorMap.reduce(function (prev, cur) {
return Number.isFinite(cur[0]) ? prev.concat(cur[0]) : prev;
}, []);
}
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,
fixed = _step$triggers3.fixed;
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 dimensionFixed = Boolean(fixed && props[fixed.prop]);
var scaleFunctor = getScaleFunctor(scaleType && props[scaleType.prop])();
var scaleFunc = scaleFunctor.domain(dimensionDomain).range(dimensionFixed ? dimensionDomain : dimensionRange);
scaleFunc.scaleType = props.colorScaleType;
if ((0, _typeof2["default"])(onSet) === 'object' && typeof props[onSet.props] === 'function') {
var sortedBins = this.state.dimensions[key].sortedBins;
if (sortedBins) {
props[onSet.props]({
domain: scaleFunc.domain(),
aggregatedBins: sortedBins.binMap
});
}
}
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 = exports.defaultAggregation = {
key: 'position',
updateSteps: [{
key: 'aggregate',
triggers: {
cellSize: {
prop: 'cellSize'
},
position: {
prop: 'getPosition',
updateTrigger: 'getPosition'
},
aggregator: {
prop: 'gridAggregator'
}
},
updater: getAggregatedData
}]
};
function getSubLayerAccessor(dimensionState, dimension) {
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 = scaleFunc.scaleType === 'custom' ? cv >= sortedBins.minValue && cv <= sortedBins.maxValue : 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 = exports.defaultColorDimension = {
key: 'fillColor',
accessor: 'getFillColor',
getPickingInfo: function getPickingInfo(dimensionState, cell) {
if (!cell) {
return {};
}
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
};
var defaultElevationDimension = exports.defaultElevationDimension = {
key: 'elevation',
accessor: 'getElevation',
getPickingInfo: function getPickingInfo(dimensionState, cell) {
if (!cell) {
return {};
}
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: {
fixed: {
prop: 'elevationFixed'
},
domain: {
prop: 'elevationDomain'
},
range: {
prop: 'elevationRange'
},
scaleType: {
prop: 'elevationScaleType'
}
},
onSet: {
props: 'onSetElevationDomain'
},
updater: getDimensionScale
}],
getSubLayerAccessor: getSubLayerAccessor
};
var _defaultDimensions = exports.defaultDimensions = [defaultColorDimension, defaultElevationDimension];
var CPUAggregator = exports["default"] = /*#__PURE__*/function () {
function CPUAggregator() {
var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
(0, _classCallCheck2["default"])(this, CPUAggregator);
(0, _defineProperty2["default"])(this, "state", void 0);
(0, _defineProperty2["default"])(this, "dimensionUpdaters", void 0);
(0, _defineProperty2["default"])(this, "aggregationUpdater", void 0);
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 = opts.aggregation || defaultAggregation;
this._addDimension(opts.dimensions || _defaultDimensions);
}
return (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++) {
var updater = dimension.updateSteps[i].updater;
if (typeof updater === 'function') {
updaters.push(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() {
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 (_ref5) {
var prop = _ref5.prop,
updateTrigger = _ref5.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();
}
return updateTriggers;
}
}, {
key: "getPickingInfo",
value: function getPickingInfo(_ref6, layerProps) {
var _this$state$layerData;
var info = _ref6.info;
var isPicked = info.picked && info.index > -1;
var object = null;
var cell = isPicked ? (_this$state$layerData = this.state.layerData.data) === null || _this$state$layerData === void 0 ? void 0 : _this$state$layerData[info.index] : null;
if (cell) {
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 (!Object.prototype.hasOwnProperty.call(this.dimensionUpdaters, dimensionKey)) {
return nop;
}
return this.dimensionUpdaters[dimensionKey].getSubLayerAccessor(this.state.dimensions[dimensionKey], this.dimensionUpdaters[dimensionKey], layerProps);
}
}], [{
key: "defaultDimensions",
value: function defaultDimensions() {
return _defaultDimensions;
}
}]);
}();
(0, _defineProperty2["default"])(CPUAggregator, "getDimensionScale", void 0);
CPUAggregator.getDimensionScale = getDimensionScale;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfd2luZG93IiwicmVxdWlyZSIsIl91dGlscyIsIl9jb25zdGFudHMiLCJvd25LZXlzIiwiZSIsInIiLCJ0IiwiT2JqZWN0Iiwia2V5cyIsImdldE93blByb3BlcnR5U3ltYm9scyIsIm8iLCJmaWx0ZXIiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJlbnVtZXJhYmxlIiwicHVzaCIsImFwcGx5IiwiX29iamVjdFNwcmVhZCIsImFyZ3VtZW50cyIsImxlbmd0aCIsImZvckVhY2giLCJfZGVmaW5lUHJvcGVydHkyIiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9ycyIsImRlZmluZVByb3BlcnRpZXMiLCJkZWZpbmVQcm9wZXJ0eSIsIl9jcmVhdGVGb3JPZkl0ZXJhdG9ySGVscGVyIiwiU3ltYm9sIiwiaXRlcmF0b3IiLCJBcnJheSIsImlzQXJyYXkiLCJfdW5zdXBwb3J0ZWRJdGVyYWJsZVRvQXJyYXkiLCJfbiIsIkYiLCJzIiwibiIsImRvbmUiLCJ2YWx1ZSIsImYiLCJUeXBlRXJyb3IiLCJhIiwidSIsImNhbGwiLCJuZXh0IiwiX2FycmF5TGlrZVRvQXJyYXkiLCJ0b1N0cmluZyIsInNsaWNlIiwiY29uc3RydWN0b3IiLCJuYW1lIiwiZnJvbSIsInRlc3QiLCJBR0dSRUdBVElPTl9PUEVSQVRJT04iLCJTVU0iLCJNRUFOIiwiTUlOIiwiTUFYIiwiQ09VTlQiLCJNQVhfMzJfQklUX0ZMT0FUIiwiZGVmYXVsdEdldFZhbHVlIiwicG9pbnRzIiwiZGVmYXVsdEdldFBvaW50cyIsImJpbiIsImRlZmF1bHRHZXRJbmRleCIsImluZGV4IiwiYXNjZW5kaW5nIiwiYiIsIk5hTiIsImNsYW1wIiwibWluIiwibWF4IiwiTWF0aCIsImdldFF1YW50aWxlRG9tYWluIiwiZGF0YSIsInZhbHVlQWNjZXNzb3IiLCJtYXAiLCJzb3J0IiwiZ2V0T3JkaW5hbERvbWFpbiIsIl90b0NvbnN1bWFibGVBcnJheTIiLCJTZXQiLCJCaW5Tb3J0ZXIiLCJiaW5zIiwidW5kZWZpbmVkIiwicHJvcHMiLCJfY2xhc3NDYWxsQ2hlY2syIiwiYWdncmVnYXRlZEJpbnMiLCJfZ2V0QWdncmVnYXRlZEJpbnMiLCJfdXBkYXRlTWluTWF4VmFsdWVzIiwiYmluTWFwIiwiX2dldEJpbk1hcCIsIl9jcmVhdGVDbGFzczIiLCJrZXkiLCJfcHJvcHMkZ2V0VmFsdWUiLCJnZXRWYWx1ZSIsIl9wcm9wcyRnZXRQb2ludHMiLCJnZXRQb2ludHMiLCJfcHJvcHMkZ2V0SW5kZXgiLCJnZXRJbmRleCIsImZpbHRlckRhdGEiLCJoYXNGaWx0ZXIiLCJiaW5JbmRleCIsImkiLCJmaWx0ZXJlZFBvaW50cyIsIk51bWJlciIsImlzRmluaXRlIiwiY291bnRzIiwibWF4Q291bnQiLCJtYXhWYWx1ZSIsIm1pblZhbHVlIiwidG90YWxDb3VudCIsIl9pdGVyYXRvciIsIl9zdGVwIiwieCIsImVyciIsIl9pdGVyYXRvcjIiLCJfc3RlcDIiLCJfcGVyY2VudGlsZVRvSW5kZXgiLCJwZXJjZW50aWxlUmFuZ2UiLCJsZW4iLCJzb3J0ZWRCaW5zIiwiX3BlcmNlbnRpbGVSYW5nZSRtYXAiLCJfcGVyY2VudGlsZVJhbmdlJG1hcDIiLCJfc2xpY2VkVG9BcnJheTIiLCJsb3dlciIsInVwcGVyIiwiY2VpbCIsImZsb29yIiwiZ2V0VmFsdWVEb21haW5CeVNjYWxlIiwic2NhbGUiLCJfcmVmIiwiX3JlZjIiLCJfcmVmMiQiLCJfcmVmMiQyIiwiaW5kZXhFZGdlIiwiX2dldFNjYWxlRG9tYWluIiwic2NhbGVUeXBlIiwiX3JlZjMiLCJfcmVmNCIsImxvd2VySWR4IiwidXBwZXJJZHgiLCJkIiwiZ2V0VmFsdWVSYW5nZSIsImlkeFJhbmdlIiwiREVDS19BR0dSRUdBVElPTl9NQVAiLCJleHBvcnRzIiwiQUdHUkVHQVRJT05fVFlQRVMiLCJzdW0iLCJhdmVyYWdlIiwibWluaW11bSIsIm1heGltdW0iLCJnZXRWYWx1ZUZ1bmMiLCJhZ2dyZWdhdGlvbiIsImFjY2Vzc29yIiwidG9VcHBlckNhc2UiLCJDb25zb2xlIiwid2FybiIsImNvbmNhdCIsIm9wIiwia2VwbGVyT3AiLCJwdHMiLCJhZ2dyZWdhdGUiLCJnZXRTY2FsZUZ1bmN0b3IiLCJTQ0FMRV9GVU5DIiwicXVhbnRpemUiLCJub3AiLCJnZXRHZXRWYWx1ZSIsInN0ZXAiLCJkaW1lbnNpb25VcGRhdGVyIiwiX3N0ZXAkdHJpZ2dlcnMiLCJ0cmlnZ2VycyIsIndlaWdodCIsInByb3AiLCJfc2V0RGltZW5zaW9uU3RhdGUiLCJnZXREaW1lbnNpb25Tb3J0ZWRCaW5zIiwic3RhdGUiLCJkaW1lbnNpb25zIiwibGF5ZXJEYXRhIiwiX2ZpbHRlckRhdGEiLCJnZXREaW1lbnNpb25WYWx1ZURvbWFpbiIsIl9zdGVwJHRyaWdnZXJzMiIsImxvd2VyUGVyY2VudGlsZSIsInVwcGVyUGVyY2VudGlsZSIsInZhbHVlRG9tYWluIiwiY29sb3JTY2FsZVR5cGUiLCJjb2xvck1hcCIsInJlZHVjZSIsInByZXYiLCJjdXIiLCJnZXREaW1lbnNpb25TY2FsZSIsIl9zdGVwJHRyaWdnZXJzMyIsImRvbWFpbiIsInJhbmdlIiwiZml4ZWQiLCJvblNldCIsImRpbWVuc2lvblJhbmdlIiwiZGltZW5zaW9uRG9tYWluIiwiZGltZW5zaW9uRml4ZWQiLCJCb29sZWFuIiwic2NhbGVGdW5jdG9yIiwic2NhbGVGdW5jIiwiX3R5cGVvZjIiLCJub3JtYWxpemVSZXN1bHQiLCJyZXN1bHQiLCJoZXhhZ29ucyIsImFzc2lnbiIsImdldEFnZ3JlZ2F0ZWREYXRhIiwiYWdncmVnYXRpb25QYXJhbXMiLCJhZ2dyIiwiYWdncmVnYXRvciIsInNldFN0YXRlIiwiZGVmYXVsdEFnZ3JlZ2F0aW9uIiwidXBkYXRlU3RlcHMiLCJjZWxsU2l6ZSIsInBvc2l0aW9uIiwidXBkYXRlVHJpZ2dlciIsInVwZGF0ZXIiLCJnZXRTdWJMYXllckFjY2Vzc29yIiwiZGltZW5zaW9uU3RhdGUiLCJkaW1lbnNpb24iLCJjZWxsIiwibnVsbFZhbHVlIiwiY3YiLCJpc1ZhbHVlSW5Eb21haW4iLCJkZWZhdWx0Q29sb3JEaW1lbnNpb24iLCJnZXRQaWNraW5nSW5mbyIsImNvbG9yVmFsdWUiLCJkZWZhdWx0RWxldmF0aW9uRGltZW5zaW9uIiwiZWxldmF0aW9uVmFsdWUiLCJkZWZhdWx0RGltZW5zaW9ucyIsIkNQVUFnZ3JlZ2F0b3IiLCJvcHRzIiwiaW5pdGlhbFN0YXRlIiwiZGltZW5zaW9uVXBkYXRlcnMiLCJhZ2dyZWdhdGlvblVwZGF0ZXIiLCJfYWRkRGltZW5zaW9uIiwidXBkYXRlQWxsRGltZW5zaW9ucyIsImRpbWVuc2lvbkNoYW5nZXMiLCJkaW0iLCJ1cGRhdGVycyIsIl9hY2N1bXVsYXRlVXBkYXRlcnMiLCJ1cGRhdGVBZ2dyZWdhdGlvbiIsInVwZGF0ZVN0YXRlIiwib2xkUHJvcHMiLCJjaGFuZ2VGbGFncyIsImRhdGFDaGFuZ2VkIiwiYWdncmVnYXRpb25DaGFuZ2VzIiwiX2dldEFnZ3JlZ2F0aW9uQ2hhbmdlcyIsIl9nZXREaW1lbnNpb25DaGFuZ2VzIiwidXBkYXRlT2JqZWN0IiwiX2FkZEFnZ3JlZ2F0aW9uIiwiX3RoaXMiLCJfbmVlZFVwZGF0ZVN0ZXAiLCJkaW1lbnNpb25TdGVwIiwidmFsdWVzIiwic29tZSIsIml0ZW0iLCJ1cGRhdGVUcmlnZ2Vyc0NoYW5nZWQiLCJhbGwiLCJiaW5kIiwiX2dldEFsbFVwZGF0ZXJzIiwiX3RoaXMyIiwibmVlZFVwZGF0ZVN0ZXAiLCJmaW5kSW5kZXgiLCJnZXRVcGRhdGVUcmlnZ2VycyIsIl90aGlzMyIsIl91cGRhdGVUcmlnZ2VycyIsInVwZGF0ZVRyaWdnZXJzIiwiX2xvb3AiLCJfdGhpczMkZGltZW5zaW9uVXBkYXQiLCJfcmVmNSIsImZyb21Qcm9wIiwiX3JlZjYiLCJsYXllclByb3BzIiwiX3RoaXMkc3RhdGUkbGF5ZXJEYXRhIiwiaW5mbyIsImlzUGlja2VkIiwicGlja2VkIiwib2JqZWN0IiwiYmluSW5mbyIsImdldEFjY2Vzc29yIiwiZGltZW5zaW9uS2V5IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvbGF5ZXItdXRpbHMvY3B1LWFnZ3JlZ2F0b3IudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVFxuLy8gQ29weXJpZ2h0IGNvbnRyaWJ1dG9ycyB0byB0aGUga2VwbGVyLmdsIHByb2plY3RcblxuLyogZXNsaW50LWRpc2FibGUgZ3VhcmQtZm9yLWluICovXG5pbXBvcnQge2NvbnNvbGUgYXMgQ29uc29sZX0gZnJvbSAnZ2xvYmFsL3dpbmRvdyc7XG5cbmltcG9ydCB7YWdncmVnYXRlfSBmcm9tICdAa2VwbGVyLmdsL3V0aWxzJztcbmltcG9ydCB7QUdHUkVHQVRJT05fVFlQRVMsIFNDQUxFX0ZVTkN9IGZyb20gJ0BrZXBsZXIuZ2wvY29uc3RhbnRzJztcbmltcG9ydCB7UkdCQUNvbG9yfSBmcm9tICdAa2VwbGVyLmdsL3R5cGVzJztcbmltcG9ydCB0eXBlIENsdXN0ZXJCdWlsZGVyIGZyb20gJy4vY2x1c3Rlci11dGlscyc7XG5cbmNvbnN0IEFHR1JFR0FUSU9OX09QRVJBVElPTiA9IHtcbiAgU1VNOiAnU1VNJyBhcyBjb25zdCxcbiAgTUVBTjogJ01FQU4nIGFzIGNvbnN0LFxuICBNSU46ICdNSU4nIGFzIGNvbnN0LFxuICBNQVg6ICdNQVgnIGFzIGNvbnN0LFxuICBDT1VOVDogJ0NPVU5UJyBhcyBjb25zdFxufTtcblxuY29uc3QgTUFYXzMyX0JJVF9GTE9BVCA9IDMuNDAyODIzNDY2ZTM4O1xuXG5pbnRlcmZhY2UgQmluIHtcbiAgcG9pbnRzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdO1xuICBmaWx0ZXJlZFBvaW50cz86IFJlY29yZDxzdHJpbmcsIHVua25vd24+W10gfCBudWxsO1xuICBpbmRleD86IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIEFnZ3JlZ2F0ZWRCaW4ge1xuICBpOiBudW1iZXI7XG4gIHZhbHVlOiBudW1iZXI7XG4gIGNvdW50czogbnVtYmVyO1xufVxuXG5jb25zdCBkZWZhdWx0R2V0VmFsdWUgPSAocG9pbnRzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdKSA9PiBwb2ludHMubGVuZ3RoO1xuY29uc3QgZGVmYXVsdEdldFBvaW50cyA9IChiaW46IEJpbikgPT4gYmluLnBvaW50cztcbmNvbnN0IGRlZmF1bHRHZXRJbmRleCA9IChiaW46IEJpbikgPT4gYmluLmluZGV4O1xuY29uc3QgYXNjZW5kaW5nID0gKGE6IG51bWJlciwgYjogbnVtYmVyKSA9PiAoYSA8IGIgPyAtMSA6IGEgPiBiID8gMSA6IGEgPj0gYiA/IDAgOiBOYU4pO1xuXG5mdW5jdGlvbiBjbGFtcCh2YWx1ZTogbnVtYmVyLCBtaW46IG51bWJlciwgbWF4OiBudW1iZXIpIHtcbiAgcmV0dXJuIE1hdGgubWF4KG1pbiwgTWF0aC5taW4obWF4LCB2YWx1ZSkpO1xufVxuXG5mdW5jdGlvbiBnZXRRdWFudGlsZURvbWFpbihkYXRhOiBBZ2dyZWdhdGVkQmluW10sIHZhbHVlQWNjZXNzb3I6IChkOiBBZ2dyZWdhdGVkQmluKSA9PiBudW1iZXIpIHtcbiAgcmV0dXJuIGRhdGEubWFwKHZhbHVlQWNjZXNzb3IpLnNvcnQoYXNjZW5kaW5nKTtcbn1cblxuZnVuY3Rpb24gZ2V0T3JkaW5hbERvbWFpbihkYXRhOiBBZ2dyZWdhdGVkQmluW10sIHZhbHVlQWNjZXNzb3I6IChkOiBBZ2dyZWdhdGVkQmluKSA9PiBudW1iZXIpIHtcbiAgcmV0dXJuIFsuLi5uZXcgU2V0KGRhdGEubWFwKHZhbHVlQWNjZXNzb3IpKV07XG59XG5cbmNsYXNzIEJpblNvcnRlciB7XG4gIG1heENvdW50ITogbnVtYmVyO1xuICBtYXhWYWx1ZSE6IG51bWJlcjtcbiAgbWluVmFsdWUhOiBudW1iZXI7XG4gIHRvdGFsQ291bnQhOiBudW1iZXI7XG4gIGFnZ3JlZ2F0ZWRCaW5zOiBBZ2dyZWdhdGVkQmluW107XG4gIHNvcnRlZEJpbnMhOiBBZ2dyZWdhdGVkQmluW107XG4gIGJpbk1hcDogUmVjb3JkPG51bWJlciwgQWdncmVnYXRlZEJpbj47XG5cbiAgY29uc3RydWN0b3IoYmluczogQmluW10gPSBbXSwgcHJvcHM6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fSkge1xuICAgIHRoaXMuYWdncmVnYXRlZEJpbnMgPSB0aGlzLl9nZXRBZ2dyZWdhdGVkQmlucyhiaW5zLCBwcm9wcyk7XG4gICAgdGhpcy5fdXBkYXRlTWluTWF4VmFsdWVzKCk7XG4gICAgdGhpcy5iaW5NYXAgPSB0aGlzLl9nZXRCaW5NYXAoKTtcbiAgfVxuXG4gIF9nZXRBZ2dyZWdhdGVkQmlucyhiaW5zOiBCaW5bXSwgcHJvcHM6IFJlY29yZDxzdHJpbmcsIGFueT4pOiBBZ2dyZWdhdGVkQmluW10ge1xuICAgIGNvbnN0IHtcbiAgICAgIGdldFZhbHVlID0gZGVmYXVsdEdldFZhbHVlLFxuICAgICAgZ2V0UG9pbnRzID0gZGVmYXVsdEdldFBvaW50cyxcbiAgICAgIGdldEluZGV4ID0gZGVmYXVsdEdldEluZGV4LFxuICAgICAgZmlsdGVyRGF0YVxuICAgIH0gPSBwcm9wcztcbiAgICBjb25zdCBoYXNGaWx0ZXIgPSB0eXBlb2YgZmlsdGVyRGF0YSA9PT0gJ2Z1bmN0aW9uJztcbiAgICBjb25zdCBhZ2dyZWdhdGVkQmluczogQWdncmVnYXRlZEJpbltdID0gW107XG4gICAgbGV0IGluZGV4ID0gMDtcbiAgICBmb3IgKGxldCBiaW5JbmRleCA9IDA7IGJpbkluZGV4IDwgYmlucy5sZW5ndGg7IGJpbkluZGV4KyspIHtcbiAgICAgIGNvbnN0IGJpbiA9IGJpbnNbYmluSW5kZXhdO1xuICAgICAgY29uc3QgcG9pbnRzID0gZ2V0UG9pbnRzKGJpbik7XG4gICAgICBjb25zdCBpID0gZ2V0SW5kZXgoYmluKTtcbiAgICAgIGNvbnN0IGZpbHRlcmVkUG9pbnRzID0gaGFzRmlsdGVyID8gcG9pbnRzLmZpbHRlcihmaWx0ZXJEYXRhKSA6IHBvaW50cztcbiAgICAgIGJpbi5maWx0ZXJlZFBvaW50cyA9IGhhc0ZpbHRlciA/IGZpbHRlcmVkUG9pbnRzIDogbnVsbDtcbiAgICAgIGNvbnN0IHZhbHVlID0gZmlsdGVyZWRQb2ludHMubGVuZ3RoID8gZ2V0VmFsdWUoZmlsdGVyZWRQb2ludHMpIDogbnVsbDtcbiAgICAgIGlmICh2YWx1ZSAhPT0gbnVsbCAmJiB2YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGFnZ3JlZ2F0ZWRCaW5zW2luZGV4XSA9IHtcbiAgICAgICAgICBpOiBOdW1iZXIuaXNGaW5pdGUoaSkgPyBpIDogYmluSW5kZXgsXG4gICAgICAgICAgdmFsdWUsXG4gICAgICAgICAgY291bnRzOiBmaWx0ZXJlZFBvaW50cy5sZW5ndGhcbiAgICAgICAgfTtcbiAgICAgICAgaW5kZXgrKztcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGFnZ3JlZ2F0ZWRCaW5zO1xuICB9XG5cbiAgX3VwZGF0ZU1pbk1heFZhbHVlcygpIHtcbiAgICBsZXQgbWF4Q291bnQgPSAwO1xuICAgIGxldCBtYXhWYWx1ZSA9IC1NQVhfMzJfQklUX0ZMT0FUO1xuICAgIGxldCBtaW5WYWx1ZSA9IE1BWF8zMl9CSVRfRkxPQVQ7XG4gICAgbGV0IHRvdGFsQ291bnQgPSAwO1xuICAgIGZvciAoY29uc3QgeCBvZiB0aGlzLmFnZ3JlZ2F0ZWRCaW5zKSB7XG4gICAgICBtYXhDb3VudCA9IG1heENvdW50ID4geC5jb3VudHMgPyBtYXhDb3VudCA6IHguY291bnRzO1xuICAgICAgbWF4VmFsdWUgPSBtYXhWYWx1ZSA+IHgudmFsdWUgPyBtYXhWYWx1ZSA6IHgudmFsdWU7XG4gICAgICBtaW5WYWx1ZSA9IG1pblZhbHVlIDwgeC52YWx1ZSA/IG1pblZhbHVlIDogeC52YWx1ZTtcbiAgICAgIHRvdGFsQ291bnQgKz0geC5jb3VudHM7XG4gICAgfVxuICAgIGlmICh0aGlzLmFnZ3JlZ2F0ZWRCaW5zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgbWF4VmFsdWUgPSAwO1xuICAgICAgbWluVmFsdWUgPSAwO1xuICAgIH1cbiAgICB0aGlzLm1heENvdW50ID0gbWF4Q291bnQ7XG4gICAgdGhpcy5tYXhWYWx1ZSA9IG1heFZhbHVlO1xuICAgIHRoaXMubWluVmFsdWUgPSBtaW5WYWx1ZTtcbiAgICB0aGlzLnRvdGFsQ291bnQgPSB0b3RhbENvdW50O1xuICB9XG5cbiAgX2dldEJpbk1hcCgpIHtcbiAgICBjb25zdCBiaW5NYXAgPSB7fTtcbiAgICBmb3IgKGNvbnN0IGJpbiBvZiB0aGlzLmFnZ3JlZ2F0ZWRCaW5zKSB7XG4gICAgICBiaW5NYXBbYmluLmldID0gYmluO1xuICAgIH1cbiAgICByZXR1cm4gYmluTWFwO1xuICB9XG5cbiAgX3BlcmNlbnRpbGVUb0luZGV4KHBlcmNlbnRpbGVSYW5nZTogbnVtYmVyW10pIHtcbiAgICBjb25zdCBsZW4gPSB0aGlzLnNvcnRlZEJpbnMubGVuZ3RoO1xuICAgIGlmIChsZW4gPCAyKSByZXR1cm4gWzAsIDBdO1xuICAgIGNvbnN0IFtsb3dlciwgdXBwZXJdID0gcGVyY2VudGlsZVJhbmdlLm1hcChuID0+IGNsYW1wKG4sIDAsIDEwMCkpO1xuICAgIHJldHVybiBbTWF0aC5jZWlsKChsb3dlciAvIDEwMCkgKiAobGVuIC0gMSkpLCBNYXRoLmZsb29yKCh1cHBlciAvIDEwMCkgKiAobGVuIC0gMSkpXTtcbiAgfVxuXG4gIGdldFZhbHVlRG9tYWluQnlTY2FsZShzY2FsZTogc3RyaW5nLCBbbG93ZXIgPSAwLCB1cHBlciA9IDEwMF06IG51bWJlcltdID0gW10pIHtcbiAgICBpZiAoIXRoaXMuc29ydGVkQmlucykge1xuICAgICAgdGhpcy5zb3J0ZWRCaW5zID0gdGhpcy5hZ2dyZWdhdGVkQmlucy5zb3J0KChhLCBiKSA9PiBhc2NlbmRpbmcoYS52YWx1ZSwgYi52YWx1ZSkpO1xuICAgIH1cbiAgICBpZiAoIXRoaXMuc29ydGVkQmlucy5sZW5ndGgpIHJldHVybiBbXTtcbiAgICBjb25zdCBpbmRleEVkZ2UgPSB0aGlzLl9wZXJjZW50aWxlVG9JbmRleChbbG93ZXIsIHVwcGVyXSk7XG4gICAgcmV0dXJuIHRoaXMuX2dldFNjYWxlRG9tYWluKHNjYWxlLCBpbmRleEVkZ2UpO1xuICB9XG5cbiAgX2dldFNjYWxlRG9tYWluKHNjYWxlVHlwZTogc3RyaW5nLCBbbG93ZXJJZHgsIHVwcGVySWR4XTogbnVtYmVyW10pIHtcbiAgICBjb25zdCBiaW5zID0gdGhpcy5zb3J0ZWRCaW5zO1xuICAgIHN3aXRjaCAoc2NhbGVUeXBlKSB7XG4gICAgICBjYXNlICdxdWFudGl6ZSc6XG4gICAgICBjYXNlICdsaW5lYXInOlxuICAgICAgICByZXR1cm4gW2JpbnNbbG93ZXJJZHhdLnZhbHVlLCBiaW5zW3VwcGVySWR4XS52YWx1ZV07XG4gICAgICBjYXNlICdxdWFudGlsZSc6XG4gICAgICAgIHJldHVybiBnZXRRdWFudGlsZURvbWFpbihiaW5zLnNsaWNlKGxvd2VySWR4LCB1cHBlcklkeCArIDEpLCBkID0+IGQudmFsdWUpO1xuICAgICAgY2FzZSAnb3JkaW5hbCc6XG4gICAgICAgIHJldHVybiBnZXRPcmRpbmFsRG9tYWluKGJpbnMsIGQgPT4gZC52YWx1ZSk7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICByZXR1cm4gW2JpbnNbbG93ZXJJZHhdLnZhbHVlLCBiaW5zW3VwcGVySWR4XS52YWx1ZV07XG4gICAgfVxuICB9XG5cbiAgZ2V0VmFsdWVSYW5nZShwZXJjZW50aWxlUmFuZ2U/OiBudW1iZXJbXSkge1xuICAgIGlmICghdGhpcy5zb3J0ZWRCaW5zKSB7XG4gICAgICB0aGlzLnNvcnRlZEJpbnMgPSB0aGlzLmFnZ3JlZ2F0ZWRCaW5zLnNvcnQoKGEsIGIpID0+IGFzY2VuZGluZyhhLnZhbHVlLCBiLnZhbHVlKSk7XG4gICAgfVxuICAgIGlmICghdGhpcy5zb3J0ZWRCaW5zLmxlbmd0aCkgcmV0dXJuIFtdO1xuICAgIGxldCBsb3dlcklkeCA9IDA7XG4gICAgbGV0IHVwcGVySWR4ID0gdGhpcy5zb3J0ZWRCaW5zLmxlbmd0aCAtIDE7XG4gICAgaWYgKEFycmF5LmlzQXJyYXkocGVyY2VudGlsZVJhbmdlKSkge1xuICAgICAgY29uc3QgaWR4UmFuZ2UgPSB0aGlzLl9wZXJjZW50aWxlVG9JbmRleChwZXJjZW50aWxlUmFuZ2UpO1xuICAgICAgbG93ZXJJZHggPSBpZHhSYW5nZVswXTtcbiAgICAgIHVwcGVySWR4ID0gaWR4UmFuZ2VbMV07XG4gICAgfVxuICAgIHJldHVybiBbdGhpcy5zb3J0ZWRCaW5zW2xvd2VySWR4XS52YWx1ZSwgdGhpcy5zb3J0ZWRCaW5zW3VwcGVySWR4XS52YWx1ZV07XG4gIH1cbn1cblxuZXhwb3J0IHR5cGUgVXBkYXRlclR5cGUgPSAodGhpczogQ1BVQWdncmVnYXRvciwgc3RlcCwgcHJvcHMsIGRpbWVuc2lvblVwZGF0ZXIpID0+IHZvaWQ7XG5leHBvcnQgdHlwZSBCaW5kZWRVcGRhdGVyVHlwZSA9ICgpID0+IHZvaWQ7XG5leHBvcnQgdHlwZSBBZ2dyZWdhdGVkVXBkYXRlclR5cGUgPSAoXG4gIHRoaXM6IENQVUFnZ3JlZ2F0b3IsXG4gIHN0ZXAsXG4gIHByb3BzLFxuICBhZ2dyZWdhdGlvbixcbiAgYWdncmVnYXRpb25QYXJhbXNcbikgPT4gdm9pZDtcbmV4cG9ydCB0eXBlIEJpbmRlZEFnZ3JlZ2F0ZWRVcGRhdGVyVHlwZSA9IChhZ2dyZWdhdGlvblBhcmFtcykgPT4gdm9pZDtcblxuZXhwb3J0IHR5cGUgVXBkYXRlU3RlcHNUeXBlID0ge1xuICBrZXk6IHN0cmluZztcbiAgdHJpZ2dlcnM6IHtcbiAgICBba2V5OiBzdHJpbmddOiB7XG4gICAgICBwcm9wOiBzdHJpbmc7XG4gICAgICB1cGRhdGVUcmlnZ2VyPzogc3RyaW5nO1xuICAgIH07XG4gIH07XG4gIG9uU2V0Pzoge1xuICAgIHByb3BzOiBzdHJpbmc7XG4gIH07XG4gIHVwZGF0ZXI6IFVwZGF0ZXJUeXBlO1xufTtcblxuZXhwb3J0IHR5cGUgRGltZW5zaW9uVHlwZTxWYWx1ZVR5cGUgPSBhbnk+ID0ge1xuICBrZXk6IHN0cmluZztcbiAgYWNjZXNzb3I6IHN0cmluZztcbiAgZ2V0UGlja2luZ0luZm86IChkaW1lbnNpb25TdGF0ZSwgY2VsbCwgbGF5ZXJQcm9wcz8pID0+IGFueTtcbiAgbnVsbFZhbHVlOiBWYWx1ZVR5cGU7XG4gIHVwZGF0ZVN0ZXBzOiBVcGRhdGVTdGVwc1R5cGVbXTtcbiAgZ2V0U3ViTGF5ZXJBY2Nlc3Nvcjtcbn07XG5cbmV4cG9ydCB0eXBlIEFnZ3JlZ2F0aW9uVXBkYXRlU3RlcHNUeXBlID0ge1xuICBrZXk6IHN0cmluZztcbiAgdHJpZ2dlcnM6IHtcbiAgICBba2V5OiBzdHJpbmddOiB7XG4gICAgICBwcm9wOiBzdHJpbmc7XG4gICAgICB1cGRhdGVUcmlnZ2VyPzogc3RyaW5nO1xuICAgIH07XG4gIH07XG4gIHVwZGF0ZXI6IEFnZ3JlZ2F0ZWRVcGRhdGVyVHlwZTtcbn07XG5cbmV4cG9ydCB0eXBlIEFnZ3JlZ2F0aW9uVHlwZSA9IHtcbiAga2V5OiBzdHJpbmc7XG4gIHVwZGF0ZVN0ZXBzOiBBZ2dyZWdhdGlvblVwZGF0ZVN0ZXBzVHlwZVtdO1xufTtcblxuZXhwb3J0IGNvbnN0IERFQ0tfQUdHUkVHQVRJT05fTUFQID0ge1xuICBbQUdHUkVHQVRJT05fT1BFUkFUSU9OLlNVTV06IEFHR1JFR0FUSU9OX1RZUEVTLnN1bSxcbiAgW0FHR1JFR0FUSU9OX09QRVJBVElPTi5NRUFOXTogQUdHUkVHQVRJT05fVFlQRVMuYXZlcmFnZSxcbiAgW0FHR1JFR0FUSU9OX09QRVJBVElPTi5NSU5dOiBBR0dSRUdBVElPTl9UWVBFUy5taW5pbXVtLFxuICBbQUdHUkVHQVRJT05fT1BFUkFUSU9OLk1BWF06IEFHR1JFR0FUSU9OX1RZUEVTLm1heGltdW1cbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRWYWx1ZUZ1bmMoXG4gIGFnZ3JlZ2F0aW9uOiBzdHJpbmcsXG4gIGFjY2Vzc29yOiAoZDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pID0+IG51bWJlclxuKSB7XG4gIGlmICghYWdncmVnYXRpb24gfHwgIUFHR1JFR0FUSU9OX09QRVJBVElPTlthZ2dyZWdhdGlvbi50b1VwcGVyQ2FzZSgpXSkge1xuICAgIENvbnNvbGUud2FybihgQWdncmVnYXRpb24gJHthZ2dyZWdhdGlvbn0gaXMgbm90IHN1cHBvcnRlZGApO1xuICB9XG5cbiAgY29uc3Qgb3AgPSBBR0dSRUdBVElPTl9PUEVSQVRJT05bYWdncmVnYXRpb24udG9VcHBlckNhc2UoKV0gfHwgQUdHUkVHQVRJT05fT1BFUkFUSU9OLlNVTTtcbiAgY29uc3Qga2VwbGVyT3AgPSBERUNLX0FHR1JFR0FUSU9OX01BUFtvcF07XG5cbiAgcmV0dXJuIHB0cyA9PiBhZ2dyZWdhdGUocHRzLm1hcChhY2Nlc3NvciksIGtlcGxlck9wKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFNjYWxlRnVuY3RvcihzY2FsZVR5cGU6IHN0cmluZykge1xuICBpZiAoIXNjYWxlVHlwZSB8fCAhU0NBTEVfRlVOQ1tzY2FsZVR5cGVdKSB7XG4gICAgQ29uc29sZS53YXJuKGBTY2FsZSAke3NjYWxlVHlwZX0gaXMgbm90IHN1cHBvcnRlZGApO1xuICB9XG4gIHJldHVybiBTQ0FMRV9GVU5DW3NjYWxlVHlwZV0gfHwgU0NBTEVfRlVOQy5xdWFudGl6ZTtcbn1cblxuZnVuY3Rpb24gbm9wKCkge1xuICByZXR1cm47XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRHZXRWYWx1ZSh0aGlzOiBDUFVBZ2dyZWdhdG9yLCBzdGVwLCBwcm9wcywgZGltZW5zaW9uVXBkYXRlcikge1xuICBjb25zdCB7a2V5fSA9IGRpbWVuc2lvblVwZGF0ZXI7XG4gIGNvbnN0IHt2YWx1ZSwgd2VpZ2h0LCBhZ2dyZWdhdGlvbn0gPSBzdGVwLnRyaWdnZXJzO1xuXG4gIGxldCBnZXRWYWx1ZSA9IHByb3BzW3ZhbHVlLnByb3BdO1xuXG4gIGlmIChnZXRWYWx1ZSA9PT0gbnVsbCkge1xuICAgIC8vIElmIGBnZXRWYWx1ZWAgaXMgbm90IHByb3ZpZGVkIGZyb20gcHJvcHMsIGJ1aWxkIGl0IHdpdGggYWdncmVnYXRpb24gYW5kIHdlaWdodC5cbiAgICBnZXRWYWx1ZSA9IGdldFZhbHVlRnVuYyhwcm9wc1thZ2dyZWdhdGlvbi5wcm9wXSwgcHJvcHNbd2VpZ2h0LnByb3BdKTtcbiAgfVxuXG4gIGlmIChnZXRWYWx1ZSkge1xuICAgIHRoaXMuX3NldERpbWVuc2lvblN0YXRlKGtleSwge2dldFZhbHVlfSk7XG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldERpbWVuc2lvblNvcnRlZEJpbnModGhpczogQ1BVQWdncmVnYXRvciwgc3RlcCwgcHJvcHMsIGRpbWVuc2lvblVwZGF0ZXIpIHtcbiAgY29uc3Qge2tleX0gPSBkaW1lbnNpb25VcGRhdGVyO1xuICBjb25zdCB7Z2V0VmFsdWV9ID0gdGhpcy5zdGF0ZS5kaW1lbnNpb25zW2tleV07XG4gIGNvbnN0IHNvcnRlZEJpbnMgPSBuZXcgQmluU29ydGVyKCh0aGlzLnN0YXRlLmxheWVyRGF0YS5kYXRhIHx8IFtdKSBhcyB1bmtub3duIGFzIEJpbltdLCB7XG4gICAgZ2V0VmFsdWUsXG4gICAgZmlsdGVyRGF0YTogcHJvcHMuX2ZpbHRlckRhdGFcbiAgfSk7XG4gIHRoaXMuX3NldERpbWVuc2lvblN0YXRlKGtleSwge3NvcnRlZEJpbnN9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldERpbWVuc2lvblZhbHVlRG9tYWluKHRoaXM6IENQVUFnZ3JlZ2F0b3IsIHN0ZXAsIHByb3BzLCBkaW1lbnNpb25VcGRhdGVyKSB7XG4gIGNvbnN0IHtrZXl9ID0gZGltZW5zaW9uVXBkYXRlcjtcbiAgY29uc3Qge1xuICAgIHRyaWdnZXJzOiB7bG93ZXJQZXJjZW50aWxlLCB1cHBlclBlcmNlbnRpbGUsIHNjYWxlVHlwZX1cbiAgfSA9IHN0ZXA7XG5cbiAgaWYgKCF0aGlzLnN0YXRlLmRpbWVuc2lvbnNba2V5XS5zb3J0ZWRCaW5zKSB7XG4gICAgLy8gdGhlIHByZXZpb3VzIHN0ZXAgc2hvdWxkIHNldCBzb3J0ZWRCaW5zLCBpZiBub3QsIHNvbWV0aGluZyB3ZW50IHdyb25nXG4gICAgcmV0dXJuO1xuICB9XG5cbiAgbGV0IHZhbHVlRG9tYWluID1cbiAgICAvLyBmb3IgbG9nIGFuZCBzcXJ0IHNjYWxlLCByZXR1cm5zIGxpbmVhciBkb21haW4gYnkgZGVmYXVsdFxuICAgIC8vIFRPRE86IHN1cHBvcnQgb3RoZXIgc2NhbGUgZnVuY3Rpb24gZG9tYWluIGluIGJpbiBzb3J0ZXJcbiAgICB0aGlzLnN0YXRlLmRpbWVuc2lvbnNba2V5XS5zb3J0ZWRCaW5zLmdldFZhbHVlRG9tYWluQnlTY2FsZShwcm9wc1tzY2FsZVR5cGUucHJvcF0sIFtcbiAgICAgIHByb3BzW2xvd2VyUGVyY2VudGlsZS5wcm9wXSxcbiAgICAgIHByb3BzW3VwcGVyUGVyY2VudGlsZS5wcm9wXVxuICAgIF0pO1xuXG4gIGlmIChwcm9wcy5jb2xvclNjYWxlVHlwZSA9PT0gJ2N1c3RvbScgJiYgcHJvcHMuY29sb3JNYXApIHtcbiAgICAvLyBmb3IgY3VzdG9tIHNjYWxlLCByZXR1cm4gY3VzdG9tIGJyZWFrcyBhcyB2YWx1ZSBkb21haW4gZGlyZWN0bHlcbiAgICB2YWx1ZURvbWFpbiA9IHByb3BzLmNvbG9yTWFwLnJlZHVjZShcbiAgICAgIChwcmV2LCBjdXIpID0+IChOdW1iZXIuaXNGaW5pdGUoY3VyWzBdKSA/IHByZXYuY29uY2F0KGN1clswXSkgOiBwcmV2KSxcbiAgICAgIFtdXG4gICAgKTtcbiAgfVxuXG4gIHRoaXMuX3NldERpbWVuc2lvblN0YXRlKGtleSwge3ZhbHVlRG9tYWlufSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXREaW1lbnNpb25TY2FsZSh0aGlzOiBDUFVBZ2dyZWdhdG9yLCBzdGVwLCBwcm9wcywgZGltZW5zaW9uVXBkYXRlcikge1xuICBjb25zdCB7a2V5fSA9IGRpbWVuc2lvblVwZGF0ZXI7XG4gIGNvbnN0IHtkb21haW4sIHJhbmdlLCBzY2FsZVR5cGUsIGZpeGVkfSA9IHN0ZXAudHJpZ2dlcnM7XG4gIGNvbnN0IHtvblNldH0gPSBzdGVwO1xuICBpZiAoIXRoaXMuc3RhdGUuZGltZW5zaW9uc1trZXldLnZhbHVlRG9tYWluKSB7XG4gICAgLy8gdGhlIHByZXZpb3VzIHN0ZXAgc2hvdWxkIHNldCB2YWx1ZURvbWFpbiwgaWYgbm90LCBzb21ldGhpbmcgd2VudCB3cm9uZ1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IGRpbWVuc2lvblJhbmdlID0gcHJvcHNbcmFuZ2UucHJvcF07XG4gIGNvbnN0IGRpbWVuc2lvbkRvbWFpbiA9IHByb3BzW2RvbWFpbi5wcm9wXSB8fCB0aGlzLnN0YXRlLmRpbWVuc2lvbnNba2V5XS52YWx1ZURvbWFpbjtcbiAgY29uc3QgZGltZW5zaW9uRml4ZWQgPSBCb29sZWFuKGZpeGVkICYmIHByb3BzW2ZpeGVkLnByb3BdKTtcblxuICBjb25zdCBzY2FsZUZ1bmN0b3IgPSBnZXRTY2FsZUZ1bmN0b3Ioc2NhbGVUeXBlICYmIHByb3BzW3NjYWxlVHlwZS5wcm9wXSkoKTtcblxuICBjb25zdCBzY2FsZUZ1bmMgPSBzY2FsZUZ1bmN0b3JcbiAgICAuZG9tYWluKGRpbWVuc2lvbkRvbWFpbilcbiAgICAucmFuZ2UoZGltZW5zaW9uRml4ZWQgPyBkaW1lbnNpb25Eb21haW4gOiBkaW1lbnNpb25SYW5nZSk7XG4gIHNjYWxlRnVuYy5zY2FsZVR5cGUgPSBwcm9wcy5jb2xvclNjYWxlVHlwZTtcblxuICBpZiAodHlwZW9mIG9uU2V0ID09PSAnb2JqZWN0JyAmJiB0eXBlb2YgcHJvcHNbb25TZXQucHJvcHNdID09PSAnZnVuY3Rpb24nKSB7XG4gICAgY29uc3Qgc29ydGVkQmlucyA9IHRoaXMuc3RhdGUuZGltZW5zaW9uc1trZXldLnNvcnRlZEJpbnM7XG4gICAgaWYgKHNvcnRlZEJpbnMpIHtcbiAgICAgIHByb3BzW29uU2V0LnByb3BzXSh7ZG9tYWluOiBzY2FsZUZ1bmMuZG9tYWluKCksIGFnZ3JlZ2F0ZWRCaW5zOiBzb3J0ZWRCaW5zLmJpbk1hcH0pO1xuICAgIH1cbiAgfVxuICB0aGlzLl9zZXREaW1lbnNpb25TdGF0ZShrZXksIHtzY2FsZUZ1bmN9KTtcbn1cblxuZnVuY3Rpb24gbm9ybWFsaXplUmVzdWx0KFxuICByZXN1bHQ6IHtcbiAgICBoZXhhZ29ucz86IFJlY29yZDxzdHJpbmcsIHVua25vd24+W107XG4gICAgbGF5ZXJEYXRhPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXTtcbiAgICBkYXRhPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXTtcbiAgfSA9IHt9XG4pIHtcbiAgLy8gc3VwcG9ydCBwcmV2aW91cyBoZXhhZ29uQWdncmVnYXRvciBBUElcbiAgaWYgKHJlc3VsdC5oZXhhZ29ucykge1xuICAgIHJldHVybiBPYmplY3QuYXNzaWduKHtkYXRhOiByZXN1bHQuaGV4YWdvbnN9LCByZXN1bHQpO1xuICB9IGVsc2UgaWYgKHJlc3VsdC5sYXllckRhdGEpIHtcbiAgICByZXR1cm4gT2JqZWN0LmFzc2lnbih7ZGF0YTogcmVzdWx0LmxheWVyRGF0YX0sIHJlc3VsdCk7XG4gIH1cblxuICByZXR1cm4gcmVzdWx0O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0QWdncmVnYXRlZERhdGEoXG4gIHRoaXM6IENQVUFnZ3JlZ2F0b3IsXG4gIHN0ZXAsXG4gIHByb3B