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
JavaScript
"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