kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
254 lines (242 loc) • 34.7 kB
JavaScript
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.assignGpuChannel = assignGpuChannel;
exports.assignGpuChannels = assignGpuChannels;
exports.getDatasetFieldIndexForFilter = getDatasetFieldIndexForFilter;
exports.getGpuFilterProps = getGpuFilterProps;
exports.resetFilterGpuMode = resetFilterGpuMode;
exports.setFilterGpuMode = setFilterGpuMode;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _moment = _interopRequireDefault(require("moment"));
var _constants = require("@kepler.gl/constants");
var _utils = require("@kepler.gl/utils");
var _commonUtils = require("@kepler.gl/common-utils");
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; } // SPDX-License-Identifier: MIT
// Copyright contributors to the kepler.gl project
/**
* Set gpu mode based on current number of gpu filters exists
*/
function setFilterGpuMode(filter, filters) {
// filter can be applied to multiple datasets, hence gpu filter mode should also be
// an array, however, to keep us sane, for now, we only check if there is available channel for every dataId,
// if all of them has, we set gpu mode to true
// TODO: refactor filter so we don't keep an array of everything
filter.dataId.forEach(function (dataId) {
var gpuFilters = filters.filter(function (f) {
return f.dataId.includes(dataId) && f.gpu;
});
if (filter.gpu && gpuFilters.length === _constants.MAX_GPU_FILTERS) {
(0, _utils.set)(['gpu'], false, filter);
}
});
return filter;
}
/**
* Scan though all filters and assign gpu chanel to gpu filter
*/
function assignGpuChannels(allFilters) {
return allFilters.reduce(function (accu, f, index) {
var filters = accu;
// if gpu is true assign and validate gpu Channel
if (f.gpu) {
f = assignGpuChannel(f, accu);
filters = (0, _utils.set)([index], f, accu);
}
return filters;
}, allFilters);
}
/**
* Assign a new gpu filter a channel based on first availability
*/
function assignGpuChannel(filter, filters) {
// find first available channel
if (!filter.gpu) {
return filter;
}
var gpuChannel = filter.gpuChannel || [];
filter.dataId.forEach(function (dataId, datasetIdx) {
var findGpuChannel = function findGpuChannel(channel) {
return function (f) {
var dataIdx = (0, _commonUtils.toArray)(f.dataId).indexOf(dataId);
return f.id !== filter.id && dataIdx > -1 && f.gpu && (0, _commonUtils.toArray)(f.gpuChannel)[dataIdx] === channel;
};
};
if (Number.isFinite(gpuChannel[datasetIdx]) && !filters.find(findGpuChannel(gpuChannel[datasetIdx]))) {
// if value is already assigned and valid
return;
}
var i = 0;
while (i < _constants.MAX_GPU_FILTERS) {
if (!filters.find(findGpuChannel(i))) {
gpuChannel[datasetIdx] = i;
return;
}
i++;
}
});
// if cannot find channel for all dataid, set gpu back to false
// TODO: refactor filter to handle same filter different gpu mode
if (!gpuChannel.length || !gpuChannel.every(Number.isFinite)) {
return _objectSpread(_objectSpread({}, filter), {}, {
gpu: false
});
}
return _objectSpread(_objectSpread({}, filter), {}, {
gpuChannel: gpuChannel
});
}
/**
* Edit filter.gpu to ensure that only
* X number of gpu filers can coexist.
*/
function resetFilterGpuMode(filters) {
var gpuPerDataset = {};
return filters.map(function (f) {
if (f.gpu) {
var gpu = true;
(0, _commonUtils.toArray)(f.dataId).forEach(function (dataId) {
var count = gpuPerDataset[dataId];
if (count === _constants.MAX_GPU_FILTERS) {
gpu = false;
} else {
gpuPerDataset[dataId] = count ? count + 1 : 1;
}
});
if (!gpu) {
return (0, _utils.set)(['gpu'], false, f);
}
}
return f;
});
}
/**
* Initial filter uniform
*/
function getEmptyFilterRange() {
return new Array(_constants.MAX_GPU_FILTERS).fill(0).map(function () {
return [0, 0];
});
}
/**
* Returns index of the data element.
* @param {any} d Data element with row index info.
* @returns number
*/
var defaultGetIndex = function defaultGetIndex(d) {
return d.index;
};
/**
* Returns value at the specified row from the data container.
* @param dc Data container.
* @param d Data element with row index info.
* @param fieldIndex Column index in the data container.
* @returns
*/
var defaultGetData = function defaultGetData(dc, d, fieldIndex) {
return dc.valueAt(d.index, fieldIndex);
};
var getFilterValueAccessor = function getFilterValueAccessor(channels, dataId, fields) {
return function (dc) {
return function () {
var getIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultGetIndex;
var getData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultGetData;
return function (d, objectInfo) {
// for empty channel, value is 0 and min max would be [0, 0]
var channelValues = channels.map(function (filter) {
var _filter$domain2;
if (!filter) {
return 0;
}
var fieldIndex = getDatasetFieldIndexForFilter(dataId, filter);
var field = fields[fieldIndex];
var value;
// d can be undefined when called from attribute updater from deck,
// when data is an ArrowTable, so use objectInfo instead.
var data = getData(dc, d || objectInfo, fieldIndex);
if (typeof data === 'function') {
value = data(field);
} else {
value = filter.type === _constants.FILTER_TYPES.timeRange ? field.filterProps && Array.isArray(field.filterProps.mappedValue) ? field.filterProps.mappedValue[getIndex(d)] : _moment["default"].utc(data).valueOf() : data;
}
return (0, _commonUtils.notNullorUndefined)(value) ? Array.isArray(value) ? value.map(function (v) {
var _filter$domain;
return v - ((_filter$domain = filter.domain) === null || _filter$domain === void 0 ? void 0 : _filter$domain[0]);
}) : value - ((_filter$domain2 = filter.domain) === null || _filter$domain2 === void 0 ? void 0 : _filter$domain2[0]) : Number.MIN_SAFE_INTEGER;
});
// TODO: can we refactor the above to avoid the transformation below?
var arrChannel = channelValues.find(function (v) {
return Array.isArray(v);
});
if (Array.isArray(arrChannel)) {
// Convert info form supported by DataFilterExtension (relevant for TripLayer)
var vals = [];
// if there are multiple arrays, they should have the same length
var _loop = function _loop(i) {
vals.push(channelValues.map(function (v) {
return Array.isArray(v) ? v[i] : v;
}));
};
for (var i = 0; i < arrChannel.length; i++) {
_loop(i);
}
return vals;
}
return channelValues;
};
};
};
};
function isFilterTriggerEqual(a, b) {
return a === b || (a === null || a === void 0 ? void 0 : a.name) === (b === null || b === void 0 ? void 0 : b.name) && (a === null || a === void 0 ? void 0 : a.domain0) === (b === null || b === void 0 ? void 0 : b.domain0);
}
/**
* Get filter properties for gpu filtering
*/
function getGpuFilterProps(filters, dataId, fields, oldGpuFilter) {
var filterRange = getEmptyFilterRange();
var triggers = {};
// array of filter for each channel, undefined, if no filter is assigned to that channel
var channels = [];
var _loop2 = function _loop2(i) {
var _filter$domain3, _filter$domain4, _oldGpuFilter$filterV, _filter$domain5;
var filter = filters.find(function (f) {
return f.gpu && f.dataId.includes(dataId) && f.gpuChannel && f.gpuChannel[f.dataId.indexOf(dataId)] === i;
});
filterRange[i][0] = filter ? filter.value[0] - ((_filter$domain3 = filter.domain) === null || _filter$domain3 === void 0 ? void 0 : _filter$domain3[0]) : 0;
filterRange[i][1] = filter ? filter.value[1] - ((_filter$domain4 = filter.domain) === null || _filter$domain4 === void 0 ? void 0 : _filter$domain4[0]) : 0;
var oldFilterTrigger = (oldGpuFilter === null || oldGpuFilter === void 0 || (_oldGpuFilter$filterV = oldGpuFilter.filterValueUpdateTriggers) === null || _oldGpuFilter$filterV === void 0 ? void 0 : _oldGpuFilter$filterV["gpuFilter_".concat(i)]) || null;
var trigger = filter ? {
name: filter.name[filter.dataId.indexOf(dataId)],
domain0: (_filter$domain5 = filter.domain) === null || _filter$domain5 === void 0 ? void 0 : _filter$domain5[0]
} : null;
// don't create a new object, cause deck.gl use shallow compare
triggers["gpuFilter_".concat(i)] = isFilterTriggerEqual(trigger, oldFilterTrigger) ? oldFilterTrigger : trigger;
channels.push(filter);
};
for (var i = 0; i < _constants.MAX_GPU_FILTERS; i++) {
_loop2(i);
}
var filterValueAccessor = getFilterValueAccessor(channels, dataId, fields);
return {
filterRange: filterRange,
filterValueUpdateTriggers: triggers,
filterValueAccessor: filterValueAccessor
};
}
/**
* Return dataset field index from filter.fieldIdx
* The index matches the same dataset index for filter.dataId
*/
function getDatasetFieldIndexForFilter(dataId, filter) {
var datasetIndex = (0, _commonUtils.toArray)(filter.dataId).indexOf(dataId);
if (datasetIndex < 0) {
return -1;
}
var fieldIndex = filter.fieldIdx[datasetIndex];
return (0, _commonUtils.notNullorUndefined)(fieldIndex) ? fieldIndex : -1;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbW9tZW50IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfY29uc3RhbnRzIiwiX3V0aWxzIiwiX2NvbW1vblV0aWxzIiwib3duS2V5cyIsImUiLCJyIiwidCIsIk9iamVjdCIsImtleXMiLCJnZXRPd25Qcm9wZXJ0eVN5bWJvbHMiLCJvIiwiZmlsdGVyIiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yIiwiZW51bWVyYWJsZSIsInB1c2giLCJhcHBseSIsIl9vYmplY3RTcHJlYWQiLCJhcmd1bWVudHMiLCJsZW5ndGgiLCJmb3JFYWNoIiwiX2RlZmluZVByb3BlcnR5MiIsImdldE93blByb3BlcnR5RGVzY3JpcHRvcnMiLCJkZWZpbmVQcm9wZXJ0aWVzIiwiZGVmaW5lUHJvcGVydHkiLCJzZXRGaWx0ZXJHcHVNb2RlIiwiZmlsdGVycyIsImRhdGFJZCIsImdwdUZpbHRlcnMiLCJmIiwiaW5jbHVkZXMiLCJncHUiLCJNQVhfR1BVX0ZJTFRFUlMiLCJzZXQiLCJhc3NpZ25HcHVDaGFubmVscyIsImFsbEZpbHRlcnMiLCJyZWR1Y2UiLCJhY2N1IiwiaW5kZXgiLCJhc3NpZ25HcHVDaGFubmVsIiwiZ3B1Q2hhbm5lbCIsImRhdGFzZXRJZHgiLCJmaW5kR3B1Q2hhbm5lbCIsImNoYW5uZWwiLCJkYXRhSWR4IiwidG9BcnJheSIsImluZGV4T2YiLCJpZCIsIk51bWJlciIsImlzRmluaXRlIiwiZmluZCIsImkiLCJldmVyeSIsInJlc2V0RmlsdGVyR3B1TW9kZSIsImdwdVBlckRhdGFzZXQiLCJtYXAiLCJjb3VudCIsImdldEVtcHR5RmlsdGVyUmFuZ2UiLCJBcnJheSIsImZpbGwiLCJkZWZhdWx0R2V0SW5kZXgiLCJkIiwiZGVmYXVsdEdldERhdGEiLCJkYyIsImZpZWxkSW5kZXgiLCJ2YWx1ZUF0IiwiZ2V0RmlsdGVyVmFsdWVBY2Nlc3NvciIsImNoYW5uZWxzIiwiZmllbGRzIiwiZ2V0SW5kZXgiLCJ1bmRlZmluZWQiLCJnZXREYXRhIiwib2JqZWN0SW5mbyIsImNoYW5uZWxWYWx1ZXMiLCJfZmlsdGVyJGRvbWFpbjIiLCJnZXREYXRhc2V0RmllbGRJbmRleEZvckZpbHRlciIsImZpZWxkIiwidmFsdWUiLCJkYXRhIiwidHlwZSIsIkZJTFRFUl9UWVBFUyIsInRpbWVSYW5nZSIsImZpbHRlclByb3BzIiwiaXNBcnJheSIsIm1hcHBlZFZhbHVlIiwibW9tZW50IiwidXRjIiwidmFsdWVPZiIsIm5vdE51bGxvclVuZGVmaW5lZCIsInYiLCJfZmlsdGVyJGRvbWFpbiIsImRvbWFpbiIsIk1JTl9TQUZFX0lOVEVHRVIiLCJhcnJDaGFubmVsIiwidmFscyIsIl9sb29wIiwiaXNGaWx0ZXJUcmlnZ2VyRXF1YWwiLCJhIiwiYiIsIm5hbWUiLCJkb21haW4wIiwiZ2V0R3B1RmlsdGVyUHJvcHMiLCJvbGRHcHVGaWx0ZXIiLCJmaWx0ZXJSYW5nZSIsInRyaWdnZXJzIiwiX2xvb3AyIiwiX2ZpbHRlciRkb21haW4zIiwiX2ZpbHRlciRkb21haW40IiwiX29sZEdwdUZpbHRlciRmaWx0ZXJWIiwiX2ZpbHRlciRkb21haW41Iiwib2xkRmlsdGVyVHJpZ2dlciIsImZpbHRlclZhbHVlVXBkYXRlVHJpZ2dlcnMiLCJjb25jYXQiLCJ0cmlnZ2VyIiwiZmlsdGVyVmFsdWVBY2Nlc3NvciIsImRhdGFzZXRJbmRleCIsImZpZWxkSWR4Il0sInNvdXJjZXMiOlsiLi4vc3JjL2dwdS1maWx0ZXItdXRpbHMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVFxuLy8gQ29weXJpZ2h0IGNvbnRyaWJ1dG9ycyB0byB0aGUga2VwbGVyLmdsIHByb2plY3RcblxuaW1wb3J0IG1vbWVudCBmcm9tICdtb21lbnQnO1xuaW1wb3J0IHtNQVhfR1BVX0ZJTFRFUlMsIEZJTFRFUl9UWVBFU30gZnJvbSAnQGtlcGxlci5nbC9jb25zdGFudHMnO1xuaW1wb3J0IHtGaWVsZCwgRmlsdGVyfSBmcm9tICdAa2VwbGVyLmdsL3R5cGVzJztcbmltcG9ydCB7c2V0LCBEYXRhQ29udGFpbmVySW50ZXJmYWNlfSBmcm9tICdAa2VwbGVyLmdsL3V0aWxzJztcbmltcG9ydCB7dG9BcnJheSwgbm90TnVsbG9yVW5kZWZpbmVkfSBmcm9tICdAa2VwbGVyLmdsL2NvbW1vbi11dGlscyc7XG5cbmltcG9ydCB7R3B1RmlsdGVyfSBmcm9tICcuL2tlcGxlci10YWJsZSc7XG5cbi8qKlxuICogU2V0IGdwdSBtb2RlIGJhc2VkIG9uIGN1cnJlbnQgbnVtYmVyIG9mIGdwdSBmaWx0ZXJzIGV4aXN0c1xuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0RmlsdGVyR3B1TW9kZShmaWx0ZXI6IEZpbHRlciwgZmlsdGVyczogRmlsdGVyW10pIHtcbiAgLy8gZmlsdGVyIGNhbiBiZSBhcHBsaWVkIHRvIG11bHRpcGxlIGRhdGFzZXRzLCBoZW5jZSBncHUgZmlsdGVyIG1vZGUgc2hvdWxkIGFsc28gYmVcbiAgLy8gYW4gYXJyYXksIGhvd2V2ZXIsIHRvIGtlZXAgdXMgc2FuZSwgZm9yIG5vdywgd2Ugb25seSBjaGVjayBpZiB0aGVyZSBpcyBhdmFpbGFibGUgY2hhbm5lbCBmb3IgZXZlcnkgZGF0YUlkLFxuICAvLyBpZiBhbGwgb2YgdGhlbSBoYXMsIHdlIHNldCBncHUgbW9kZSB0byB0cnVlXG4gIC8vIFRPRE86IHJlZmFjdG9yIGZpbHRlciBzbyB3ZSBkb24ndCBrZWVwIGFuIGFycmF5IG9mIGV2ZXJ5dGhpbmdcblxuICBmaWx0ZXIuZGF0YUlkLmZvckVhY2goZGF0YUlkID0+IHtcbiAgICBjb25zdCBncHVGaWx0ZXJzID0gZmlsdGVycy5maWx0ZXIoZiA9PiBmLmRhdGFJZC5pbmNsdWRlcyhkYXRhSWQpICYmIGYuZ3B1KTtcblxuICAgIGlmIChmaWx0ZXIuZ3B1ICYmIGdwdUZpbHRlcnMubGVuZ3RoID09PSBNQVhfR1BVX0ZJTFRFUlMpIHtcbiAgICAgIHNldChbJ2dwdSddLCBmYWxzZSwgZmlsdGVyKTtcbiAgICB9XG4gIH0pO1xuXG4gIHJldHVybiBmaWx0ZXI7XG59XG5cbi8qKlxuICogU2NhbiB0aG91Z2ggYWxsIGZpbHRlcnMgYW5kIGFzc2lnbiBncHUgY2hhbmVsIHRvIGdwdSBmaWx0ZXJcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFzc2lnbkdwdUNoYW5uZWxzKGFsbEZpbHRlcnM6IEZpbHRlcltdKSB7XG4gIHJldHVybiBhbGxGaWx0ZXJzLnJlZHVjZSgoYWNjdSwgZiwgaW5kZXgpID0+IHtcbiAgICBsZXQgZmlsdGVycyA9IGFjY3U7XG5cbiAgICAvLyBpZiBncHUgaXMgdHJ1ZSBhc3NpZ24gYW5kIHZhbGlkYXRlIGdwdSBDaGFubmVsXG4gICAgaWYgKGYuZ3B1KSB7XG4gICAgICBmID0gYXNzaWduR3B1Q2hhbm5lbChmLCBhY2N1KTtcbiAgICAgIGZpbHRlcnMgPSBzZXQoW2luZGV4XSwgZiwgYWNjdSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZpbHRlcnM7XG4gIH0sIGFsbEZpbHRlcnMpO1xufVxuLyoqXG4gKiBBc3NpZ24gYSBuZXcgZ3B1IGZpbHRlciBhIGNoYW5uZWwgYmFzZWQgb24gZmlyc3QgYXZhaWxhYmlsaXR5XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhc3NpZ25HcHVDaGFubmVsKGZpbHRlcjogRmlsdGVyLCBmaWx0ZXJzOiBGaWx0ZXJbXSkge1xuICAvLyBmaW5kIGZpcnN0IGF2YWlsYWJsZSBjaGFubmVsXG4gIGlmICghZmlsdGVyLmdwdSkge1xuICAgIHJldHVybiBmaWx0ZXI7XG4gIH1cblxuICBjb25zdCBncHVDaGFubmVsID0gZmlsdGVyLmdwdUNoYW5uZWwgfHwgW107XG5cbiAgZmlsdGVyLmRhdGFJZC5mb3JFYWNoKChkYXRhSWQsIGRhdGFzZXRJZHgpID0+IHtcbiAgICBjb25zdCBmaW5kR3B1Q2hhbm5lbCA9IGNoYW5uZWwgPT4gZiA9PiB7XG4gICAgICBjb25zdCBkYXRhSWR4ID0gdG9BcnJheShmLmRhdGFJZCkuaW5kZXhPZihkYXRhSWQpO1xuICAgICAgcmV0dXJuIChcbiAgICAgICAgZi5pZCAhPT0gZmlsdGVyLmlkICYmIGRhdGFJZHggPiAtMSAmJiBmLmdwdSAmJiB0b0FycmF5KGYuZ3B1Q2hhbm5lbClbZGF0YUlkeF0gPT09IGNoYW5uZWxcbiAgICAgICk7XG4gICAgfTtcblxuICAgIGlmIChcbiAgICAgIE51bWJlci5pc0Zpbml0ZShncHVDaGFubmVsW2RhdGFzZXRJZHhdKSAmJlxuICAgICAgIWZpbHRlcnMuZmluZChmaW5kR3B1Q2hhbm5lbChncHVDaGFubmVsW2RhdGFzZXRJZHhdKSlcbiAgICApIHtcbiAgICAgIC8vIGlmIHZhbHVlIGlzIGFscmVhZHkgYXNzaWduZWQgYW5kIHZhbGlkXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgbGV0IGkgPSAwO1xuXG4gICAgd2hpbGUgKGkgPCBNQVhfR1BVX0ZJTFRFUlMpIHtcbiAgICAgIGlmICghZmlsdGVycy5maW5kKGZpbmRHcHVDaGFubmVsKGkpKSkge1xuICAgICAgICBncHVDaGFubmVsW2RhdGFzZXRJZHhdID0gaTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgaSsrO1xuICAgIH1cbiAgfSk7XG5cbiAgLy8gaWYgY2Fubm90IGZpbmQgY2hhbm5lbCBmb3IgYWxsIGRhdGFpZCwgc2V0IGdwdSBiYWNrIHRvIGZhbHNlXG4gIC8vIFRPRE86IHJlZmFjdG9yIGZpbHRlciB0byBoYW5kbGUgc2FtZSBmaWx0ZXIgZGlmZmVyZW50IGdwdSBtb2RlXG4gIGlmICghZ3B1Q2hhbm5lbC5sZW5ndGggfHwgIWdwdUNoYW5uZWwuZXZlcnkoTnVtYmVyLmlzRmluaXRlKSkge1xuICAgIHJldHVybiB7XG4gICAgICAuLi5maWx0ZXIsXG4gICAgICBncHU6IGZhbHNlXG4gICAgfTtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgLi4uZmlsdGVyLFxuICAgIGdwdUNoYW5uZWxcbiAgfTtcbn1cbi8qKlxuICogRWRpdCBmaWx0ZXIuZ3B1IHRvIGVuc3VyZSB0aGF0IG9ubHlcbiAqIFggbnVtYmVyIG9mIGdwdSBmaWxlcnMgY2FuIGNvZXhpc3QuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNldEZpbHRlckdwdU1vZGUoZmlsdGVyczogRmlsdGVyW10pOiBGaWx0ZXJbXSB7XG4gIGNvbnN0IGdwdVBlckRhdGFzZXQgPSB7fTtcblxuICByZXR1cm4gZmlsdGVycy5tYXAoZiA9PiB7XG4gICAgaWYgKGYuZ3B1KSB7XG4gICAgICBsZXQgZ3B1ID0gdHJ1ZTtcbiAgICAgIHRvQXJyYXkoZi5kYXRhSWQpLmZvckVhY2goZGF0YUlkID0+IHtcbiAgICAgICAgY29uc3QgY291bnQgPSBncHVQZXJEYXRhc2V0W2RhdGFJZF07XG5cbiAgICAgICAgaWYgKGNvdW50ID09PSBNQVhfR1BVX0ZJTFRFUlMpIHtcbiAgICAgICAgICBncHUgPSBmYWxzZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBncHVQZXJEYXRhc2V0W2RhdGFJZF0gPSBjb3VudCA/IGNvdW50ICsgMSA6IDE7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICBpZiAoIWdwdSkge1xuICAgICAgICByZXR1cm4gc2V0KFsnZ3B1J10sIGZhbHNlLCBmKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZjtcbiAgfSk7XG59XG5cbi8qKlxuICogSW5pdGlhbCBmaWx0ZXIgdW5pZm9ybVxuICovXG5mdW5jdGlvbiBnZXRFbXB0eUZpbHRlclJhbmdlKCkge1xuICByZXR1cm4gbmV3IEFycmF5KE1BWF9HUFVfRklMVEVSUykuZmlsbCgwKS5tYXAoKCkgPT4gWzAsIDBdKTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIGluZGV4IG9mIHRoZSBkYXRhIGVsZW1lbnQuXG4gKiBAcGFyYW0ge2FueX0gZCBEYXRhIGVsZW1lbnQgd2l0aCByb3cgaW5kZXggaW5mby5cbiAqIEByZXR1cm5zIG51bWJlclxuICovXG5jb25zdCBkZWZhdWx0R2V0SW5kZXggPSBkID0+IGQuaW5kZXg7XG5cbi8qKlxuICogUmV0dXJucyB2YWx1ZSBhdCB0aGUgc3BlY2lmaWVkIHJvdyBmcm9tIHRoZSBkYXRhIGNvbnRhaW5lci5cbiAqIEBwYXJhbSBkYyBEYXRhIGNvbnRhaW5lci5cbiAqIEBwYXJhbSBkIERhdGEgZWxlbWVudCB3aXRoIHJvdyBpbmRleCBpbmZvLlxuICogQHBhcmFtIGZpZWxkSW5kZXggQ29sdW1uIGluZGV4IGluIHRoZSBkYXRhIGNvbnRhaW5lci5cbiAqIEByZXR1cm5zXG4gKi9cbmNvbnN0IGRlZmF1bHRHZXREYXRhID0gKGRjOiBEYXRhQ29udGFpbmVySW50ZXJmYWNlLCBkOiBhbnksIGZpZWxkSW5kZXg6IG51bWJlcikgPT4ge1xuICByZXR1cm4gZGMudmFsdWVBdChkLmluZGV4LCBmaWVsZEluZGV4KTtcbn07XG5cbmNvbnN0IGdldEZpbHRlclZhbHVlQWNjZXNzb3IgPVxuICAoY2hhbm5lbHM6IChGaWx0ZXIgfCB1bmRlZmluZWQpW10sIGRhdGFJZDogc3RyaW5nLCBmaWVsZHM6IGFueVtdKSA9PlxuICAoZGM6IERhdGFDb250YWluZXJJbnRlcmZhY2UpID0+XG4gIChnZXRJbmRleCA9IGRlZmF1bHRHZXRJbmRleCwgZ2V0RGF0YSA9IGRlZmF1bHRHZXREYXRhKSA9PlxuICAoZCwgb2JqZWN0SW5mbz86IHtpbmRleDogbnVtYmVyfSkgPT4ge1xuICAgIC8vIGZvciBlbXB0eSBjaGFubmVsLCB2YWx1ZSBpcyAwIGFuZCBtaW4gbWF4IHdvdWxkIGJlIFswLCAwXVxuICAgIGNvbnN0IGNoYW5uZWxWYWx1ZXMgPSBjaGFubmVscy5tYXAoZmlsdGVyID0+IHtcbiAgICAgIGlmICghZmlsdGVyKSB7XG4gICAgICAgIHJldHVybiAwO1xuICAgICAgfVxuICAgICAgY29uc3QgZmllbGRJbmRleCA9IGdldERhdGFzZXRGaWVsZEluZGV4Rm9yRmlsdGVyKGRhdGFJZCwgZmlsdGVyKTtcbiAgICAgIGNvbnN0IGZpZWxkID0gZmllbGRzW2ZpZWxkSW5kZXhdO1xuXG4gICAgICBsZXQgdmFsdWU7XG4gICAgICAvLyBkIGNhbiBiZSB1bmRlZmluZWQgd2hlbiBjYWxsZWQgZnJvbSBhdHRyaWJ1dGUgdXBkYXRlciBmcm9tIGRlY2ssXG4gICAgICAvLyB3aGVuIGRhdGEgaXMgYW4gQXJyb3dUYWJsZSwgc28gdXNlIG9iamVjdEluZm8gaW5zdGVhZC5cbiAgICAgIGNvbnN0IGRhdGEgPSBnZXREYXRhKGRjLCBkIHx8IG9iamVjdEluZm8sIGZpZWxkSW5kZXgpO1xuICAgICAgaWYgKHR5cGVvZiBkYXRhID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHZhbHVlID0gZGF0YShmaWVsZCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YWx1ZSA9XG4gICAgICAgICAgZmlsdGVyLnR5cGUgPT09IEZJTFRFUl9UWVBFUy50aW1lUmFuZ2VcbiAgICAgICAgICAgID8gZmllbGQuZmlsdGVyUHJvcHMgJiYgQXJyYXkuaXNBcnJheShmaWVsZC5maWx0ZXJQcm9wcy5tYXBwZWRWYWx1ZSlcbiAgICAgICAgICAgICAgPyBmaWVsZC5maWx0ZXJQcm9wcy5tYXBwZWRWYWx1ZVtnZXRJbmRleChkKV1cbiAgICAgICAgICAgICAgOiBtb21lbnQudXRjKGRhdGEpLnZhbHVlT2YoKVxuICAgICAgICAgICAgOiBkYXRhO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gbm90TnVsbG9yVW5kZWZpbmVkKHZhbHVlKVxuICAgICAgICA/IEFycmF5LmlzQXJyYXkodmFsdWUpXG4gICAgICAgICAgPyB2YWx1ZS5tYXAodiA9PiB2IC0gZmlsdGVyLmRvbWFpbj8uWzBdKVxuICAgICAgICAgIDogdmFsdWUgLSBmaWx0ZXIuZG9tYWluPy5bMF1cbiAgICAgICAgOiBOdW1iZXIuTUlOX1NBRkVfSU5URUdFUjtcbiAgICB9KTtcblxuICAgIC8vIFRPRE86IGNhbiB3ZSByZWZhY3RvciB0aGUgYWJvdmUgdG8gYXZvaWQgdGhlIHRyYW5zZm9ybWF0aW9uIGJlbG93P1xuICAgIGNvbnN0IGFyckNoYW5uZWwgPSBjaGFubmVsVmFsdWVzLmZpbmQodiA9PiBBcnJheS5pc0FycmF5KHYpKTtcbiAgICBpZiAoQXJyYXkuaXNBcnJheShhcnJDaGFubmVsKSkge1xuICAgICAgLy8gQ29udmVydCBpbmZvIGZvcm0gc3VwcG9ydGVkIGJ5IERhdGFGaWx0ZXJFeHRlbnNpb24gKHJlbGV2YW50IGZvciBUcmlwTGF5ZXIpXG4gICAgICBjb25zdCB2YWxzOiBudW1iZXJbXVtdID0gW107XG4gICAgICAvLyBpZiB0aGVyZSBhcmUgbXVsdGlwbGUgYXJyYXlzLCB0aGV5IHNob3VsZCBoYXZlIHRoZSBzYW1lIGxlbmd0aFxuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcnJDaGFubmVsLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhbHMucHVzaChjaGFubmVsVmFsdWVzLm1hcCh2ID0+IChBcnJheS5pc0FycmF5KHYpID8gdltpXSA6IHYpKSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gdmFscztcbiAgICB9XG5cbiAgICByZXR1cm4gY2hhbm5lbFZhbHVlcztcbiAgfTtcblxuZnVuY3Rpb24gaXNGaWx0ZXJUcmlnZ2VyRXF1YWwoYSwgYikge1xuICByZXR1cm4gYSA9PT0gYiB8fCAoYT8ubmFtZSA9PT0gYj8ubmFtZSAmJiBhPy5kb21haW4wID09PSBiPy5kb21haW4wKTtcbn1cblxuLyoqXG4gKiBHZXQgZmlsdGVyIHByb3BlcnRpZXMgZm9yIGdwdSBmaWx0ZXJpbmdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEdwdUZpbHRlclByb3BzKFxuICBmaWx0ZXJzOiBGaWx0ZXJbXSxcbiAgZGF0YUlkOiBzdHJpbmcsXG4gIGZpZWxkczogRmllbGRbXSxcbiAgb2xkR3B1RmlsdGVyPzogR3B1RmlsdGVyXG4pOiBHcHVGaWx0ZXIge1xuICBjb25zdCBmaWx0ZXJSYW5nZSA9IGdldEVtcHR5RmlsdGVyUmFuZ2UoKTtcbiAgY29uc3QgdHJpZ2dlcnM6IEdwdUZpbHRlclsnZmlsdGVyVmFsdWVVcGRhdGVUcmlnZ2VycyddID0ge307XG5cbiAgLy8gYXJyYXkgb2YgZmlsdGVyIGZvciBlYWNoIGNoYW5uZWwsIHVuZGVmaW5lZCwgaWYgbm8gZmlsdGVyIGlzIGFzc2lnbmVkIHRvIHRoYXQgY2hhbm5lbFxuICBjb25zdCBjaGFubmVsczogKEZpbHRlciB8IHVuZGVmaW5lZClbXSA9IFtdO1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgTUFYX0dQVV9GSUxURVJTOyBpKyspIHtcbiAgICBjb25zdCBmaWx0ZXIgPSBmaWx0ZXJzLmZpbmQoXG4gICAgICBmID0+XG4gICAgICAgIGYuZ3B1ICYmXG4gICAgICAgIGYuZGF0YUlkLmluY2x1ZGVzKGRhdGFJZCkgJiZcbiAgICAgICAgZi5ncHVDaGFubmVsICYmXG4gICAgICAgIGYuZ3B1Q2hhbm5lbFtmLmRhdGFJZC5pbmRleE9mKGRhdGFJZCldID09PSBpXG4gICAgKTtcblxuICAgIGZpbHRlclJhbmdlW2ldWzBdID0gZmlsdGVyID8gZmlsdGVyLnZhbHVlWzBdIC0gZmlsdGVyLmRvbWFpbj8uWzBdIDogMDtcbiAgICBmaWx0ZXJSYW5nZVtpXVsxXSA9IGZpbHRlciA/IGZpbHRlci52YWx1ZVsxXSAtIGZpbHRlci5kb21haW4/LlswXSA6IDA7XG4gICAgY29uc3Qgb2xkRmlsdGVyVHJpZ2dlciA9IG9sZEdwdUZpbHRlcj8uZmlsdGVyVmFsdWVVcGRhdGVUcmlnZ2Vycz8uW2BncHVGaWx0ZXJfJHtpfWBdIHx8IG51bGw7XG5cbiAgICBjb25zdCB0cmlnZ2VyID0gZmlsdGVyXG4gICAgICA/IHtcbiAgICAgICAgICBuYW1lOiBmaWx0ZXIubmFtZVtmaWx0ZXIuZGF0YUlkLmluZGV4T2YoZGF0YUlkKV0sXG4gICAgICAgICAgZG9tYWluMDogZmlsdGVyLmRvbWFpbj8uWzBdXG4gICAgICAgIH1cbiAgICAgIDogbnVsbDtcbiAgICAvLyBkb24ndCBjcmVhdGUgYSBuZXcgb2JqZWN0LCBjYXVzZSBkZWNrLmdsIHVzZSBzaGFsbG93IGNvbXBhcmVcbiAgICB0cmlnZ2Vyc1tgZ3B1RmlsdGVyXyR7aX1gXSA9IGlzRmlsdGVyVHJpZ2dlckVxdWFsKHRyaWdnZXIsIG9sZEZpbHRlclRyaWdnZXIpXG4gICAgICA/IG9sZEZpbHRlclRyaWdnZXJcbiAgICAgIDogdHJpZ2dlcjtcbiAgICBjaGFubmVscy5wdXNoKGZpbHRlcik7XG4gIH1cblxuICBjb25zdCBmaWx0ZXJWYWx1ZUFjY2Vzc29yID0gZ2V0RmlsdGVyVmFsdWVBY2Nlc3NvcihjaGFubmVscywgZGF0YUlkLCBmaWVsZHMpO1xuXG4gIHJldHVybiB7XG4gICAgZmlsdGVyUmFuZ2UsXG4gICAgZmlsdGVyVmFsdWVVcGRhdGVUcmlnZ2VyczogdHJpZ2dlcnMsXG4gICAgZmlsdGVyVmFsdWVBY2Nlc3NvclxuICB9O1xufVxuXG4vKipcbiAqIFJldHVybiBkYXRhc2V0IGZpZWxkIGluZGV4IGZyb20gZmlsdGVyLmZpZWxkSWR4XG4gKiBUaGUgaW5kZXggbWF0Y2hlcyB0aGUgc2FtZSBkYXRhc2V0IGluZGV4IGZvciBmaWx0ZXIuZGF0YUlkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXREYXRhc2V0RmllbGRJbmRleEZvckZpbHRlcihkYXRhSWQ6IHN0cmluZywgZmlsdGVyOiBGaWx0ZXIpOiBudW1iZXIge1xuICBjb25zdCBkYXRhc2V0SW5kZXggPSB0b0FycmF5KGZpbHRlci5kYXRhSWQpLmluZGV4T2YoZGF0YUlkKTtcbiAgaWYgKGRhdGFzZXRJbmRleCA8IDApIHtcbiAgICByZXR1cm4gLTE7XG4gIH1cblxuICBjb25zdCBmaWVsZEluZGV4ID0gZmlsdGVyLmZpZWxkSWR4W2RhdGFzZXRJbmRleF07XG5cbiAgcmV0dXJuIG5vdE51bGxvclVuZGVmaW5lZChmaWVsZEluZGV4KSA/IGZpZWxkSW5kZXggOiAtMTtcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7OztBQUdBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLFVBQUEsR0FBQUQsT0FBQTtBQUVBLElBQUFFLE1BQUEsR0FBQUYsT0FBQTtBQUNBLElBQUFHLFlBQUEsR0FBQUgsT0FBQTtBQUFvRSxTQUFBSSxRQUFBQyxDQUFBLEVBQUFDLENBQUEsUUFBQUMsQ0FBQSxHQUFBQyxNQUFBLENBQUFDLElBQUEsQ0FBQUosQ0FBQSxP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QUEsdUJBQXZDQSxxQkFBQSxjQUFBSSxNQUFBLENBQXVEN0QsQ0FBQyxFQUFHLEtBQUksSUFBSTtJQUU1RixJQUFNOEQsT0FBTyxHQUFHckcsTUFBTSxHQUNsQjtNQUNFdUYsSUFBSSxFQUFFdkYsTUFBTSxDQUFDdUYsSUFBSSxDQUFDdkYsTUFBTSxDQUFDZSxNQUFNLENBQUNtQixPQUFPLENBQUNuQixNQUFNLENBQUMsQ0FBQztNQUNoRHlFLE9BQU8sR0FBQVMsZUFBQSxHQUFFakcsTUFBTSxDQUFDK0UsTUFBTSxjQUFBa0IsZUFBQSx1QkFBYkEsZUFBQSxDQUFnQixDQUFDO0lBQzVCLENBQUMsR0FDRCxJQUFJO0lBQ1I7SUFDQUwsUUFBUSxjQUFBUSxNQUFBLENBQWM3RCxDQUFDLEVBQUcsR0FBRzZDLG9CQUFvQixDQUFDaUIsT0FBTyxFQUFFSCxnQkFBZ0IsQ0FBQyxHQUN4RUEsZ0JBQWdCLEdBQ2hCRyxPQUFPO0lBQ1g5QyxRQUFRLENBQUNwRCxJQUFJLENBQUNILE1BQU0sQ0FBQztFQUN2QixDQUFDO0VBeEJELEtBQUssSUFBSXVDLENBQUMsR0FBRyxDQUFDLEVBQUVBLENBQUMsR0FBR25CLDBCQUFlLEVBQUVtQixDQUFDLEVBQUU7SUFBQXNELE1BQUEsQ0FBQXRELENBQUE7RUFBQTtFQTBCeEMsSUFBTStELG1CQUFtQixHQUFHaEQsc0JBQXNCLENBQUNDLFFBQVEsRUFBRXhDLE1BQU0sRUFBRXlDLE1BQU0sQ0FBQztFQUU1RSxPQUFPO0lBQ0xtQyxXQUFXLEVBQVhBLFdBQVc7SUFDWFEseUJBQXlCLEVBQUVQLFFBQVE7SUFDbkNVLG1CQUFtQixFQUFuQkE7RUFDRixDQUFDO0FBQ0g7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDTyxTQUFTdkMsNkJBQTZCQSxDQUFDaEQsTUFBYyxFQUFFZixNQUFjLEVBQVU7RUFDcEYsSUFBTXVHLFlBQVksR0FBRyxJQUFBdEUsb0JBQU8sRUFBQ2pDLE1BQU0sQ0FBQ2UsTUFBTSxDQUFDLENBQUNtQixPQUFPLENBQUNuQixNQUFNLENBQUM7RUFDM0QsSUFBSXdGLFlBQVksR0FBRyxDQUFDLEVBQUU7SUFDcEIsT0FBTyxDQUFDLENBQUM7RUFDWDtFQUVBLElBQU1uRCxVQUFVLEdBQUdwRCxNQUFNLENBQUN3RyxRQUFRLENBQUNELFlBQVksQ0FBQztFQUVoRCxPQUFPLElBQUEzQiwrQkFBa0IsRUFBQ3hCLFVBQVUsQ0FBQyxHQUFHQSxVQUFVLEdBQUcsQ0FBQyxDQUFDO0FBQ3pEIiwiaWdub3JlTGlzdCI6W119
;