UNPKG

kepler.gl

Version:

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

1,250 lines (1,201 loc) 154 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.TimestampStepMap = exports.LAYER_FILTERS = exports.FILTER_UPDATER_PROPS = exports.FILTER_ID_LENGTH = exports.FILTER_COMPONENTS = exports.DEFAULT_FILTER_STRUCTURE = void 0; exports.adjustValueToFilterDomain = adjustValueToFilterDomain; exports.applyFilterFieldName = applyFilterFieldName; exports.applyFiltersToDatasets = applyFiltersToDatasets; exports.canApplyFeatureFilter = canApplyFeatureFilter; exports.diffFilters = diffFilters; exports.featureToFilterValue = exports.durationYear = exports.durationWeek = exports.durationSecond = exports.durationMinute = exports.durationHour = exports.durationDay = void 0; exports.filterDataByFilterTypes = filterDataByFilterTypes; exports.filterDatasetCPU = filterDatasetCPU; exports.formatNumberByStep = formatNumberByStep; exports.generatePolygonFilter = generatePolygonFilter; exports.getAnimatableVisibleLayers = getAnimatableVisibleLayers; exports.getAnimatableVisibleLayersByType = getAnimatableVisibleLayersByType; exports.getColumnFilterProps = getColumnFilterProps; exports.getDefaultFilter = getDefaultFilter; exports.getFilterFunction = getFilterFunction; exports.getFilterIdInFeature = void 0; exports.getFilterProps = getFilterProps; exports.getFilterRecord = getFilterRecord; exports.getFilterScaledTimeline = getFilterScaledTimeline; exports.getIntervalBasedAnimationLayers = getIntervalBasedAnimationLayers; exports.getNumericFieldDomain = getNumericFieldDomain; exports.getNumericStepSize = getNumericStepSize; exports.getPolygonFilterFunctor = void 0; exports.getTimeWidgetHintFormatter = getTimeWidgetHintFormatter; exports.getTimeWidgetTitleFormatter = getTimeWidgetTitleFormatter; exports.getTimestampFieldDomain = getTimestampFieldDomain; exports.isFilterValidToSave = isFilterValidToSave; exports.isInPolygon = isInPolygon; exports.isInRange = isInRange; exports.isLayerAnimatable = isLayerAnimatable; exports.isSideFilter = isSideFilter; exports.isValidFilterValue = isValidFilterValue; exports.isValidTimeDomain = isValidTimeDomain; exports.mergeFilterDomain = mergeFilterDomain; exports.mergeFilterDomainStep = mergeFilterDomainStep; exports.mergeFilterWithTimeline = mergeFilterWithTimeline; exports.mergeTimeDomains = mergeTimeDomains; exports.removeFilterPlot = removeFilterPlot; exports.scaleSourceDomainToDestination = scaleSourceDomainToDestination; exports.shouldApplyFilter = shouldApplyFilter; exports.updateFilterDataId = updateFilterDataId; exports.updateFilterPlot = updateFilterPlot; exports.validateFilter = validateFilter; exports.validateFilterWithData = validateFilterWithData; exports.validateFiltersUpdateDatasets = validateFiltersUpdateDatasets; exports.validatePolygonFilter = validatePolygonFilter; var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _keymirror = _interopRequireDefault(require("keymirror")); var _lodash = _interopRequireDefault(require("lodash.get")); var _lodash2 = _interopRequireDefault(require("lodash.isequal")); var _d3Array = require("d3-array"); var _booleanWithin = _interopRequireDefault(require("@turf/boolean-within")); var _helpers = require("@turf/helpers"); var _decimal = require("decimal.js"); var _constants = require("@kepler.gl/constants"); var ScaleUtils = _interopRequireWildcard(require("./data-scale-utils")); var _h3Js = require("h3-js"); var _commonUtils = require("@kepler.gl/common-utils"); var _utils = require("./utils"); var _dataUtils = require("./data-utils"); var _plot = require("./plot"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } 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 // import {VisState} from '@kepler.gl/schemas'; var durationSecond = exports.durationSecond = 1000; var durationMinute = exports.durationMinute = durationSecond * 60; var durationHour = exports.durationHour = durationMinute * 60; var durationDay = exports.durationDay = durationHour * 24; var durationWeek = exports.durationWeek = durationDay * 7; var durationYear = exports.durationYear = durationDay * 365; // TODO isolate types - depends on @kepler.gl/schemas var TimestampStepMap = exports.TimestampStepMap = [{ max: 1, step: 0.05 }, { max: 10, step: 0.1 }, { max: 100, step: 1 }, { max: 500, step: 5 }, { max: 1000, step: 10 }, { max: 5000, step: 50 }, { max: Number.POSITIVE_INFINITY, step: 1000 }]; var FILTER_UPDATER_PROPS = exports.FILTER_UPDATER_PROPS = (0, _keymirror["default"])({ dataId: null, name: null, layerId: null }); var FILTER_COMPONENTS = exports.FILTER_COMPONENTS = (0, _defineProperty2["default"])((0, _defineProperty2["default"])((0, _defineProperty2["default"])((0, _defineProperty2["default"])((0, _defineProperty2["default"])({}, _constants.FILTER_TYPES.select, 'SingleSelectFilter'), _constants.FILTER_TYPES.multiSelect, 'MultiSelectFilter'), _constants.FILTER_TYPES.timeRange, 'TimeRangeFilter'), _constants.FILTER_TYPES.range, 'RangeFilter'), _constants.FILTER_TYPES.polygon, 'PolygonFilter'); var DEFAULT_FILTER_STRUCTURE = exports.DEFAULT_FILTER_STRUCTURE = { dataId: [], // [string] id: null, enabled: true, // time range filter specific fixedDomain: false, view: _constants.FILTER_VIEW_TYPES.side, isAnimating: false, animationWindow: _constants.ANIMATION_WINDOW.free, speed: 1, // field specific name: [], // string type: null, fieldIdx: [], // [integer] domain: null, value: null, // plot plotType: { type: _constants.PLOT_TYPES.histogram }, yAxis: null, // mode gpu: false }; var FILTER_ID_LENGTH = exports.FILTER_ID_LENGTH = 4; var LAYER_FILTERS = exports.LAYER_FILTERS = [_constants.FILTER_TYPES.polygon]; /** * Generates a filter with a dataset id as dataId */ function getDefaultFilter() { var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, dataId = _ref.dataId, id = _ref.id; return _objectSpread(_objectSpread({}, DEFAULT_FILTER_STRUCTURE), {}, { // store it as dataId and it could be one or many dataId: dataId ? (0, _commonUtils.toArray)(dataId) : [], id: id || (0, _commonUtils.generateHashId)(FILTER_ID_LENGTH) }); } /** * Check if a filter is valid based on the given dataId * @param filter to validate * @param datasetId id to validate filter against * @return true if a filter is valid, false otherwise */ function shouldApplyFilter(filter, datasetId) { var dataIds = (0, _commonUtils.toArray)(filter.dataId); return dataIds.includes(datasetId) && filter.value !== null; } /** * Validates and modifies polygon filter structure * @param dataset * @param filter * @param layers * @return - {filter, dataset} */ function validatePolygonFilter(dataset, filter, layers) { var failed = { dataset: dataset, filter: null }; var value = filter.value, layerId = filter.layerId, type = filter.type, dataId = filter.dataId; if (!layerId || !isValidFilterValue(type, value)) { return failed; } var isValidDataset = dataId.includes(dataset.id); if (!isValidDataset) { return failed; } var layer = layers.find(function (l) { return layerId.includes(l.id); }); if (!layer) { return failed; } return { filter: _objectSpread(_objectSpread({}, filter), {}, { fieldIdx: [] }), dataset: dataset }; } /** * Custom filter validators */ var filterValidators = (0, _defineProperty2["default"])({}, _constants.FILTER_TYPES.polygon, validatePolygonFilter); /** * Default validate filter function * @param datasets * @param datasetId * @param filter * @return - {filter, dataset} */ function validateFilter(datasets, datasetId, filter) { var _filter$view; var dataset = datasets[datasetId]; // match filter.dataId var failed = { dataset: dataset, filter: null }; var filterDataId = (0, _commonUtils.toArray)(filter.dataId); var filterDatasetIndex = filterDataId.indexOf(dataset.id); if (filterDatasetIndex < 0 || !(0, _commonUtils.toArray)(filter.name)[filterDatasetIndex]) { // the current filter is not mapped against the current dataset return failed; } var initializeFilter = _objectSpread(_objectSpread(_objectSpread({}, getDefaultFilter({ dataId: filter.dataId })), filter), {}, { dataId: filterDataId, name: (0, _commonUtils.toArray)(filter.name) }); var fieldName = initializeFilter.name[filterDatasetIndex]; var _applyFilterFieldName = applyFilterFieldName(initializeFilter, datasets, datasetId, fieldName, filterDatasetIndex, { mergeDomain: true }), updatedFilter = _applyFilterFieldName.filter, updatedDataset = _applyFilterFieldName.dataset; if (!updatedFilter) { return failed; } // don't adjust value yet before all datasets are loaded updatedFilter.view = (_filter$view = filter.view) !== null && _filter$view !== void 0 ? _filter$view : updatedFilter.view; if (updatedFilter.value === null) { // cannot adjust saved value to filter return failed; } return { filter: validateFilterYAxis(updatedFilter, updatedDataset), dataset: updatedDataset }; } /** * Validate saved filter config with new data * * @param datasets * @param datasetId * @param filter - filter to be validate * @param layers - layers * @return validated filter */ function validateFilterWithData(datasets, datasetId, filter, layers) { return filter.type && Object.prototype.hasOwnProperty.call(filterValidators, filter.type) ? filterValidators[filter.type](datasets[datasetId], filter, layers) : validateFilter(datasets, datasetId, filter); } /** * Validate YAxis * @param filter * @param dataset * @return {*} */ function validateFilterYAxis(filter, dataset) { // TODO: validate yAxis against other datasets var fields = dataset.fields; var _filter = filter, yAxis = _filter.yAxis; // TODO: validate yAxis against other datasets if (yAxis) { var matchedAxis = fields.find(function (_ref2) { var name = _ref2.name, type = _ref2.type; return name === yAxis.name && type === yAxis.type; }); filter = matchedAxis ? _objectSpread(_objectSpread({}, filter), {}, { yAxis: matchedAxis }) : filter; } return filter; } /** * Get default filter prop based on field type * * @param field * @param fieldDomain * @returns default filter */ function getFilterProps(field, fieldDomain) { var filterProps = _objectSpread(_objectSpread({}, fieldDomain), {}, { fieldType: field.type, view: _constants.FILTER_VIEW_TYPES.side }); switch (field.type) { case _constants.ALL_FIELD_TYPES.real: case _constants.ALL_FIELD_TYPES.integer: return _objectSpread(_objectSpread({}, filterProps), {}, { value: fieldDomain.domain, type: _constants.FILTER_TYPES.range, // @ts-expect-error typeOptions: [_constants.FILTER_TYPES.range], gpu: true }); case _constants.ALL_FIELD_TYPES["boolean"]: // @ts-expect-error return _objectSpread(_objectSpread({}, filterProps), {}, { type: _constants.FILTER_TYPES.select, value: true, gpu: false }); case _constants.ALL_FIELD_TYPES.string: case _constants.ALL_FIELD_TYPES.h3: case _constants.ALL_FIELD_TYPES.date: // @ts-expect-error return _objectSpread(_objectSpread({}, filterProps), {}, { type: _constants.FILTER_TYPES.multiSelect, value: [], gpu: false }); case _constants.ALL_FIELD_TYPES.timestamp: // @ts-expect-error return _objectSpread(_objectSpread({}, filterProps), {}, { type: _constants.FILTER_TYPES.timeRange, view: _constants.FILTER_VIEW_TYPES.enlarged, fixedDomain: true, value: filterProps.domain, gpu: true, plotType: {} }); default: // @ts-expect-error return {}; } } var getPolygonFilterFunctor = exports.getPolygonFilterFunctor = function getPolygonFilterFunctor(layer, filter, dataContainer) { var getPosition = layer.getPositionAccessor(dataContainer); switch (layer.type) { case _constants.LAYER_TYPES.point: case _constants.LAYER_TYPES.icon: return function (data) { var pos = getPosition(data); return pos.every(Number.isFinite) && isInPolygon(pos, filter.value); }; case _constants.LAYER_TYPES.arc: case _constants.LAYER_TYPES.line: return function (data) { var pos = getPosition(data); return pos.every(Number.isFinite) && [[pos[0], pos[1]], [pos[3], pos[4]]].every(function (point) { return isInPolygon(point, filter.value); }); }; case _constants.LAYER_TYPES.hexagonId: if (layer.dataToFeature && layer.dataToFeature.centroids) { return function (data) { // null or getCentroid({id}) var centroid = layer.dataToFeature.centroids[data.index]; return centroid && isInPolygon(centroid, filter.value); }; } return function (data) { var id = getPosition(data); if (!(0, _h3Js.h3IsValid)(id)) { return false; } var pos = (0, _commonUtils.getCentroid)({ id: id }); return pos.every(Number.isFinite) && isInPolygon(pos, filter.value); }; case _constants.LAYER_TYPES.geojson: return function (data) { return layer.isInPolygon(data, data.index, filter.value); }; default: return function () { return true; }; } }; /** * Check if a GeoJSON feature filter can be applied to a layer */ function canApplyFeatureFilter(feature) { return Boolean((feature === null || feature === void 0 ? void 0 : feature.geometry) && ['Polygon', 'MultiPolygon'].includes(feature.geometry.type)); } /** * @param param An object that represents a row record. * @param param.index Index of the row in data container. * @returns Returns true to keep the element, or false otherwise. */ /** * @param field dataset Field * @param dataId Dataset id * @param filter Filter object * @param layers list of layers to filter upon * @param dataContainer Data container * @return filterFunction */ /* eslint-disable complexity */ function getFilterFunction(field, dataId, filter, layers, dataContainer) { // field could be null in polygon filter var valueAccessor = field ? field.valueAccessor : function () { return null; }; var defaultFunc = function defaultFunc() { return true; }; if (filter.enabled === false) { return defaultFunc; } switch (filter.type) { case _constants.FILTER_TYPES.range: return function (data) { return isInRange(valueAccessor(data), filter.value); }; case _constants.FILTER_TYPES.multiSelect: return function (data) { return filter.value.includes(valueAccessor(data)); }; case _constants.FILTER_TYPES.select: return function (data) { return valueAccessor(data) === filter.value; }; case _constants.FILTER_TYPES.timeRange: { if (!field) { return defaultFunc; } var mappedValue = (0, _lodash["default"])(field, ['filterProps', 'mappedValue']); var accessor = Array.isArray(mappedValue) ? function (data) { return mappedValue[data.index]; } : function (data) { return (0, _dataUtils.timeToUnixMilli)(valueAccessor(data), field.format); }; return function (data) { return isInRange(accessor(data), filter.value); }; } case _constants.FILTER_TYPES.polygon: { if (!layers || !layers.length || !filter.layerId) { return defaultFunc; } var layerFilterFunctions = filter.layerId.map(function (id) { return layers.find(function (l) { return l.id === id; }); }).filter(function (l) { return l && l.config.dataId === dataId; }).map(function (layer) { return getPolygonFilterFunctor(layer, filter, dataContainer); }); return function (data) { return layerFilterFunctions.every(function (filterFunc) { return filterFunc(data); }); }; } default: return defaultFunc; } } function updateFilterDataId(dataId) { return getDefaultFilter({ dataId: dataId }); } function filterDataByFilterTypes(_ref3, dataContainer) { var dynamicDomainFilters = _ref3.dynamicDomainFilters, cpuFilters = _ref3.cpuFilters, filterFuncs = _ref3.filterFuncs; var filteredIndexForDomain = []; var filteredIndex = []; var filterContext = { index: -1, dataContainer: dataContainer }; var filterFuncCaller = function filterFuncCaller(filter) { return filterFuncs[filter.id](filterContext); }; var numRows = dataContainer.numRows(); for (var i = 0; i < numRows; ++i) { filterContext.index = i; var matchForDomain = dynamicDomainFilters && dynamicDomainFilters.every(filterFuncCaller); if (matchForDomain) { filteredIndexForDomain.push(filterContext.index); } var matchForRender = cpuFilters && cpuFilters.every(filterFuncCaller); if (matchForRender) { filteredIndex.push(filterContext.index); } } return _objectSpread(_objectSpread({}, dynamicDomainFilters ? { filteredIndexForDomain: filteredIndexForDomain } : {}), cpuFilters ? { filteredIndex: filteredIndex } : {}); } /** * Get a record of filters based on domain type and gpu / cpu */ function getFilterRecord(dataId, filters) { var opt = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var filterRecord = { dynamicDomain: [], fixedDomain: [], cpu: [], gpu: [] }; filters.forEach(function (f) { if (isValidFilterValue(f.type, f.value) && (0, _commonUtils.toArray)(f.dataId).includes(dataId)) { (f.fixedDomain || opt.ignoreDomain ? filterRecord.fixedDomain : filterRecord.dynamicDomain).push(f); (f.gpu && !opt.cpuOnly ? filterRecord.gpu : filterRecord.cpu).push(f); } }); return filterRecord; } /** * Compare filter records to get what has changed */ function diffFilters(filterRecord) { var oldFilterRecord = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var filterChanged = {}; Object.entries(filterRecord).forEach(function (_ref4) { var _ref5 = (0, _slicedToArray2["default"])(_ref4, 2), record = _ref5[0], items = _ref5[1]; items.forEach(function (filter) { var oldFilter = (oldFilterRecord[record] || []).find(function (f) { return f.id === filter.id; }); if (!oldFilter) { // added filterChanged = (0, _utils.set)([record, filter.id], 'added', filterChanged); } else { // check what has changed ['name', 'value', 'dataId'].forEach(function (prop) { if (filter[prop] !== oldFilter[prop]) { filterChanged = (0, _utils.set)([record, filter.id], "".concat(prop, "_changed"), filterChanged); } }); } }); (oldFilterRecord[record] || []).forEach(function (oldFilter) { // deleted if (!items.find(function (f) { return f.id === oldFilter.id; })) { filterChanged = (0, _utils.set)([record, oldFilter.id], 'deleted', filterChanged); } }); }); return _objectSpread(_objectSpread({}, { dynamicDomain: null, fixedDomain: null, cpu: null, gpu: null }), filterChanged); } /** * Call by parsing filters from URL * Check if value of filter within filter domain, if not adjust it to match * filter domain * * @returns value - adjusted value to match filter or null to remove filter */ // eslint-disable-next-line complexity function adjustValueToFilterDomain(value, _ref6) { var domain = _ref6.domain, type = _ref6.type; if (!type) { return false; } // if the current filter is a polygon it will not have any domain // all other filter types require domain if (type !== _constants.FILTER_TYPES.polygon && !domain) { return false; } switch (type) { case _constants.FILTER_TYPES.range: case _constants.FILTER_TYPES.timeRange: if (!Array.isArray(value) || value.length !== 2) { return domain.map(function (d) { return d; }); } return value.map(function (d, i) { return (0, _commonUtils.notNullorUndefined)(d) && isInRange(d, domain) ? d : domain[i]; }); case _constants.FILTER_TYPES.multiSelect: { if (!Array.isArray(value)) { return []; } var filteredValue = value.filter(function (d) { return domain.includes(d); }); return filteredValue.length ? filteredValue : []; } case _constants.FILTER_TYPES.select: return domain.includes(value) ? value : true; case _constants.FILTER_TYPES.polygon: return value; default: return null; } } /** * Calculate numeric domain and suitable step */ function getNumericFieldDomain(dataContainer, valueAccessor) { var domain = [0, 1]; var step = 0.1; var mappedValue = dataContainer.mapIndex(valueAccessor); if (dataContainer.numRows() > 1) { domain = ScaleUtils.getLinearDomain(mappedValue); var diff = domain[1] - domain[0]; // in case equal domain, [96, 96], which will break quantize scale if (!diff) { domain[1] = domain[0] + 1; } step = getNumericStepSize(diff) || step; domain[0] = formatNumberByStep(domain[0], step, 'floor'); domain[1] = formatNumberByStep(domain[1], step, 'ceil'); } return { domain: domain, step: step }; } /** * Calculate step size for range and timerange filter */ function getNumericStepSize(diff) { diff = Math.abs(diff); if (diff > 100) { return 1; } else if (diff > 3) { return 0.01; } else if (diff > 1) { return 0.001; } // Try to get at least 1000 steps - and keep the step size below that of // the (diff > 1) case. var x = diff / 1000; // Find the exponent and truncate to 10 to the power of that exponent var exponentialForm = x.toExponential(); var exponent = parseFloat(exponentialForm.split('e')[1]); // Getting ready for node 12 // this is why we need decimal.js // Math.pow(10, -5) = 0.000009999999999999999 // the above result shows in browser and node 10 // node 12 behaves correctly return new _decimal.Decimal(10).pow(exponent).toNumber(); } /** * Calculate timestamp domain and suitable step */ function getTimestampFieldDomain(dataContainer, valueAccessor) { // to avoid converting string format time to epoch // every time we compare we store a value mapped to int in filter domain var mappedValue = dataContainer.mapIndex(valueAccessor); var domain = ScaleUtils.getLinearDomain(mappedValue); var defaultTimeFormat = getTimeWidgetTitleFormatter(domain); var step = 0.01; var diff = domain[1] - domain[0]; // in case equal timestamp add 1 second padding to prevent break if (!diff) { domain[1] = domain[0] + 1000; } var entry = TimestampStepMap.find(function (f) { return f.max >= diff; }); if (entry) { step = entry.step; } return { domain: domain, step: step, mappedValue: mappedValue, defaultTimeFormat: defaultTimeFormat }; } /** * round number based on step * * @param {Number} val * @param {Number} step * @param {string} bound * @returns {Number} rounded number */ function formatNumberByStep(val, step, bound) { if (bound === 'floor') { return Math.floor(val * (1 / step)) / (1 / step); } return Math.ceil(val * (1 / step)) / (1 / step); } function isInRange(val, domain) { if (!Array.isArray(domain)) { return false; } if (Array.isArray(val)) { return domain[0] <= val[0] && val[1] <= domain[1]; } return val >= domain[0] && val <= domain[1]; } /** * Determines whether a point is within the provided polygon * * @param point as input search [lat, lng] * @param polygon Points must be within these (Multi)Polygon(s) * @return {boolean} */ function isInPolygon(point, polygon) { return (0, _booleanWithin["default"])((0, _helpers.point)(point), polygon); } function getTimeWidgetTitleFormatter(domain) { if (!isValidTimeDomain(domain)) { return null; } var diff = domain[1] - domain[0]; // Local aware formats // https://momentjs.com/docs/#/parsing/string-format return diff > durationYear ? 'L' : diff > durationDay ? 'L LT' : 'L LTS'; } /** * Sanity check on filters to prepare for save * @type {typeof import('./filter-utils').isFilterValidToSave} */ function isFilterValidToSave(filter) { return (filter === null || filter === void 0 ? void 0 : filter.type) && Array.isArray(filter === null || filter === void 0 ? void 0 : filter.name) && ((filter === null || filter === void 0 ? void 0 : filter.name.length) || (filter === null || filter === void 0 ? void 0 : filter.layerId.length)); } /** * Sanity check on filters to prepare for save * @type {typeof import('./filter-utils').isValidFilterValue} */ /* eslint-disable complexity */ function isValidFilterValue(type, value) { if (!type) { return false; } switch (type) { case _constants.FILTER_TYPES.select: return value === true || value === false; case _constants.FILTER_TYPES.range: case _constants.FILTER_TYPES.timeRange: return Array.isArray(value) && value.every(function (v) { return v !== null && !isNaN(v); }); case _constants.FILTER_TYPES.multiSelect: return Array.isArray(value) && Boolean(value.length); case _constants.FILTER_TYPES.input: return Boolean(value.length); case _constants.FILTER_TYPES.polygon: { var coordinates = (0, _lodash["default"])(value, ['geometry', 'coordinates']); return Boolean(value && value.id && coordinates); } default: return true; } } function getColumnFilterProps(filter, dataset) { var _filter$plotType; if (((_filter$plotType = filter.plotType) === null || _filter$plotType === void 0 ? void 0 : _filter$plotType.type) === _constants.PLOT_TYPES.histogram || !filter.yAxis) { // histogram should be calculated when create filter return {}; } var _filter$mappedValue = filter.mappedValue, mappedValue = _filter$mappedValue === void 0 ? [] : _filter$mappedValue; var yAxis = filter.yAxis; var fieldIdx = dataset.getColumnFieldIdx(yAxis.name); if (fieldIdx < 0) { // Console.warn(`yAxis ${yAxis.name} does not exist in dataset`); return { lineChart: {}, yAxis: yAxis }; } // return lineChart var series = dataset.dataContainer.map(function (row, rowIndex) { return { x: mappedValue[rowIndex], y: row.valueAt(fieldIdx) }; }, true).filter(function (_ref7) { var x = _ref7.x, y = _ref7.y; return Number.isFinite(x) && Number.isFinite(y); }).sort(function (a, b) { return (0, _d3Array.ascending)(a.x, b.x); }); var yDomain = (0, _d3Array.extent)(series, function (d) { return d.y; }); var xDomain = [series[0].x, series[series.length - 1].x]; return { lineChart: { series: series, yDomain: yDomain, xDomain: xDomain }, yAxis: yAxis }; } function updateFilterPlot(datasets, filter) { var dataId = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined; if (dataId) { filter = removeFilterPlot(filter, dataId); } if (filter.type === _constants.FILTER_TYPES.timeRange) { return (0, _plot.updateTimeFilterPlotType)(filter, filter.plotType, datasets); } else if (filter.type === _constants.FILTER_TYPES.range) { return (0, _plot.updateRangeFilterPlotType)(filter, filter.plotType, datasets); } return filter; } /** * * @param datasetIds list of dataset ids to be filtered * @param datasets all datasets * @param filters all filters to be applied to datasets * @return datasets - new updated datasets */ function applyFiltersToDatasets(datasetIds, datasets, filters, layers) { var dataIds = (0, _commonUtils.toArray)(datasetIds); return dataIds.reduce(function (acc, dataId) { var layersToFilter = (layers || []).filter(function (l) { return l.config.dataId === dataId; }); var appliedFilters = filters.filter(function (d) { return shouldApplyFilter(d, dataId); }); var table = datasets[dataId]; return _objectSpread(_objectSpread({}, acc), {}, (0, _defineProperty2["default"])({}, dataId, table.filterTable(appliedFilters, layersToFilter, {}))); }, datasets); } /** * Applies a new field name value to filter and update both filter and dataset * @param filter - to be applied the new field name on * @param datasets - All datasets * @param datasetId - Id of the dataset the field belongs to * @param fieldName - field.name * @param filterDatasetIndex - field.name * @param option * @return - {filter, datasets} */ function applyFilterFieldName(filter, datasets, datasetId, fieldName) { var filterDatasetIndex = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0; var option = arguments.length > 5 ? arguments[5] : undefined; // using filterDatasetIndex we can filter only the specified dataset var mergeDomain = option && Object.prototype.hasOwnProperty.call(option, 'mergeDomain') ? option.mergeDomain : false; var dataset = datasets[datasetId]; var fieldIndex = dataset === null || dataset === void 0 ? void 0 : dataset.getColumnFieldIdx(fieldName); // if no field with same name is found, move to the next datasets if (!dataset || fieldIndex === -1) { // throw new Error(`fieldIndex not found. Dataset must contain a property with name: ${fieldName}`); return { filter: null, dataset: dataset }; } // TODO: validate field type var filterProps = dataset.getColumnFilterProps(fieldName); var newFilter = _objectSpread(_objectSpread(_objectSpread({}, filter), filterProps), {}, { name: Object.assign((0, _toConsumableArray2["default"])((0, _commonUtils.toArray)(filter.name)), (0, _defineProperty2["default"])({}, filterDatasetIndex, fieldName)), fieldIdx: Object.assign((0, _toConsumableArray2["default"])((0, _commonUtils.toArray)(filter.fieldIdx)), (0, _defineProperty2["default"])({}, filterDatasetIndex, fieldIndex)) }, filter.plotType ? { plotType: filter.plotType } : {}); if (mergeDomain) { var _mergeFilterDomain; var domainSteps = (_mergeFilterDomain = mergeFilterDomain(newFilter, datasets)) !== null && _mergeFilterDomain !== void 0 ? _mergeFilterDomain : {}; if (domainSteps) { var domain = domainSteps.domain, step = domainSteps.step; newFilter.domain = domain; if (newFilter.step !== step) { newFilter.step = step; } } } // TODO: if we don't set filter value in filterProps, we don't need to do this if (filterDatasetIndex > 0) { // don't reset the filter value if we are just adding a synced dataset newFilter = _objectSpread(_objectSpread({}, newFilter), {}, { value: filter.value }); } return { filter: newFilter, dataset: dataset }; } /** * Merge the domains of a filter in case it applies to multiple datasets */ function mergeFilterDomain(filter, datasets) { var _filter$dataId; var domainSteps = null; if (!(filter !== null && filter !== void 0 && (_filter$dataId = filter.dataId) !== null && _filter$dataId !== void 0 && _filter$dataId.length)) { return filter; } filter.dataId.forEach(function (filterDataId, idx) { var _domainSteps; var dataset = datasets[filterDataId]; var filterProps = dataset.getColumnFilterProps(filter.name[idx]); domainSteps = mergeFilterDomainStep((_domainSteps = domainSteps) !== null && _domainSteps !== void 0 ? _domainSteps : {}, filterProps); }); return domainSteps; } /** * Merge one filter with other filter prop domain */ /* eslint-disable complexity */ function mergeFilterDomainStep(filter, filterProps) { if (!filter) { return null; } if (!filterProps) { return filter; } if (filter.fieldType && filter.fieldType !== filterProps.fieldType || !filterProps.domain) { return filter; } var sortedDomain = !filter.domain ? filterProps.domain : [].concat((0, _toConsumableArray2["default"])(filter.domain || []), (0, _toConsumableArray2["default"])(filterProps.domain || [])).sort(function (a, b) { return a - b; }); var newFilter = _objectSpread(_objectSpread(_objectSpread({}, filter), filterProps), {}, { // use min max as default domain domain: [sortedDomain[0], sortedDomain[sortedDomain.length - 1]] }); switch (filterProps.fieldType) { case _constants.ALL_FIELD_TYPES.string: case _constants.ALL_FIELD_TYPES.h3: case _constants.ALL_FIELD_TYPES.date: return _objectSpread(_objectSpread({}, newFilter), {}, { domain: (0, _dataUtils.unique)(sortedDomain) }); case _constants.ALL_FIELD_TYPES.timestamp: { var step = filter.step < filterProps.step ? filter.step : filterProps.step; return _objectSpread(_objectSpread({}, newFilter), {}, { step: step }); } case _constants.ALL_FIELD_TYPES.real: case _constants.ALL_FIELD_TYPES.integer: default: return newFilter; } } /* eslint-enable complexity */ /** * Generates polygon filter */ var featureToFilterValue = exports.featureToFilterValue = function featureToFilterValue(feature, filterId, properties) { return _objectSpread(_objectSpread({}, feature), {}, { id: feature.id, properties: _objectSpread(_objectSpread(_objectSpread({}, feature.properties), properties), {}, { filterId: filterId }) }); }; var getFilterIdInFeature = exports.getFilterIdInFeature = function getFilterIdInFeature(f) { return (0, _lodash["default"])(f, ['properties', 'filterId']); }; /** * Generates polygon filter */ function generatePolygonFilter(layers, feature) { var dataId = layers.map(function (l) { return l.config.dataId; }).filter(_commonUtils.notNullorUndefined); var layerId = layers.map(function (l) { return l.id; }); var name = layers.map(function (l) { return l.config.label; }); var filter = getDefaultFilter({ dataId: dataId }); return _objectSpread(_objectSpread({}, filter), {}, { fixedDomain: true, type: _constants.FILTER_TYPES.polygon, name: name, layerId: layerId, value: featureToFilterValue(feature, filter.id, { isVisible: true }) }); } /** * Run filter entirely on CPU */ function filterDatasetCPU(state, dataId) { var datasetFilters = state.filters.filter(function (f) { return f.dataId.includes(dataId); }); var dataset = state.datasets[dataId]; if (!dataset) { return state; } var cpuFilteredDataset = dataset.filterTableCPU(datasetFilters, state.layers); return (0, _utils.set)(['datasets', dataId], cpuFilteredDataset, state); } /** * Validate parsed filters with datasets and add filterProps to field */ function validateFiltersUpdateDatasets(state) { var filtersToValidate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; // TODO Better Typings here var validated = []; var failed = []; var datasets = state.datasets, layers = state.layers; var updatedDatasets = datasets; // merge filters filtersToValidate.forEach(function (filterToValidate) { // we can only look for datasets define in the filter dataId var datasetIds = (0, _commonUtils.toArray)(filterToValidate.dataId); // we can merge a filter only if all datasets in filter.dataId are loaded if (datasetIds.every(function (d) { return datasets[d] && !state.isMergingDatasets[d]; })) { // all datasetIds in filter must be present the state datasets var _datasetIds$reduce = datasetIds.reduce(function (acc, datasetId) { var dataset = updatedDatasets[datasetId]; var datasetLayers = layers.filter(function (l) { return l.config.dataId === dataset.id; }); var toValidate = acc.validatedFilter || filterToValidate; var _validateFilterWithDa = validateFilterWithData(_objectSpread(_objectSpread(_objectSpread({}, updatedDatasets), acc.augmentedDatasets), {}, (0, _defineProperty2["default"])({}, datasetId, acc.augmentedDatasets[datasetId] || dataset)), datasetId, toValidate, datasetLayers), updatedFilter = _validateFilterWithDa.filter, updatedDataset = _validateFilterWithDa.dataset; if (updatedFilter) { // merge filter domain step return { validatedFilter: updatedFilter, applyToDatasets: [].concat((0, _toConsumableArray2["default"])(acc.applyToDatasets), [datasetId]), augmentedDatasets: _objectSpread(_objectSpread({}, acc.augmentedDatasets), {}, (0, _defineProperty2["default"])({}, datasetId, updatedDataset)) }; } return acc; }, { validatedFilter: null, applyToDatasets: [], augmentedDatasets: {} }), validatedFilter = _datasetIds$reduce.validatedFilter, applyToDatasets = _datasetIds$reduce.applyToDatasets, augmentedDatasets = _datasetIds$reduce.augmentedDatasets; if (validatedFilter && (0, _lodash2["default"])(datasetIds, applyToDatasets)) { var domain = validatedFilter.domain; if (validatedFilter.syncedWithLayerTimeline) { var animatableLayers = getAnimatableVisibleLayers(layers); domain = mergeTimeDomains([].concat((0, _toConsumableArray2["default"])(animatableLayers.map(function (l) { return l.config.animation.domain || [0, 0]; })), [validatedFilter.domain])); } validatedFilter.value = adjustValueToFilterDomain(filterToValidate.value, _objectSpread(_objectSpread({}, validatedFilter), {}, { domain: domain })); validated.push(updateFilterPlot(datasets, validatedFilter)); updatedDatasets = _objectSpread(_objectSpread({}, updatedDatasets), augmentedDatasets); } else { failed.push(filterToValidate); } } else { failed.push(filterToValidate); } }); return { validated: validated, failed: failed, updatedDatasets: updatedDatasets }; } function removeFilterPlot(filter, dataId) { var nextFilter = filter; var rangeFilter = filter; if (rangeFilter.bins && rangeFilter.bins[dataId]) { var _rangeFilter$bins = rangeFilter.bins, _delete = _rangeFilter$bins[dataId], nextBins = (0, _objectWithoutProperties2["default"])(_rangeFilter$bins, [dataId].map(_toPropertyKey)); nextFilter = _objectSpread(_objectSpread({}, rangeFilter), {}, { bins: nextBins }); } var timeFilter = filter; if (timeFilter.timeBins && timeFilter.timeBins[dataId]) { var _timeFilter$timeBins = timeFilter.timeBins, __delete = _timeFilter$timeBins[dataId], nextTimeBins = (0, _objectWithoutProperties2["default"])(_timeFilter$timeBins, [dataId].map(_toPropertyKey)); nextFilter = _objectSpread(_objectSpread({}, nextFilter), {}, { timeBins: nextTimeBins }); } return nextFilter; } function isValidTimeDomain(domain) { return Array.isArray(domain) && domain.every(Number.isFinite); } function getTimeWidgetHintFormatter(domain) { if (!isValidTimeDomain(domain)) { return undefined; } var diff = domain[1] - domain[0]; return diff > durationWeek ? 'L' : diff > durationDay ? 'L LT' : diff > durationHour ? 'LT' : 'LTS'; } function isSideFilter(filter) { return filter.view === _constants.FILTER_VIEW_TYPES.side; } function mergeTimeDomains(domains) { return domains.reduce(function (acc, domain) { var _domain$, _domain$2; return [Math.min(acc[0], (_domain$ = domain === null || domain === void 0 ? void 0 : domain[0]) !== null && _domain$ !== void 0 ? _domain$ : Infinity), Math.max(acc[1], (_domain$2 = domain === null || domain === void 0 ? void 0 : domain[1]) !== null && _domain$2 !== void 0 ? _domain$2 : -Infinity)]; }, [Number(Infinity), -Infinity]); } /** * @param {Layer} layer */ function isLayerAnimatable(layer) { var _layer$config$animati; return ((_layer$config$animati = layer.config.animation) === null || _layer$config$animati === void 0 ? void 0 : _layer$config$animati.enabled) && Array.isArray(layer.config.animation.domain); } /** * @param {Layer[]} layers * @returns {Layer[]} */ function getAnimatableVisibleLayers(layers) { return layers.filter(function (l) { return isLayerAnimatable(l) && l.config.isVisible; }); } /** * @param {Layer[]} layers * @param {string} type * @returns {Layer[]} */ function getAnimatableVisibleLayersByType(layers, type) { return getAnimatableVisibleLayers(layers).filter(function (l) { return l.type === type; }); } /** * @param {Layer[]} layers * @returns {Layer[]} */ function getIntervalBasedAnimationLayers(layers) { // @ts-ignore return getAnimatableVisibleLayers(layers).filter(function (l) { var _l$config$animation; return (_l$config$animation = l.config.animation) === null || _l$config$animation === void 0 ? void 0 : _l$config$animation.timeSteps; }); } function mergeFilterWithTimeline(filter, animationConfig) { if ((filter === null || filter === void 0 ? void 0 : filter.type) === _constants.FILTER_TYPES.timeRange && filter.syncedWithLayerTimeline && animationConfig && Array.isArray(animationConfig.domain)) { var domain = mergeTimeDomains([filter.domain, animationConfig.domain]); return { filter: _objectSpread(_objectSpread({}, filter), {}, { domain: domain }), animationConfig: _objectSpread(_objectSpread({}, animationConfig), {}, { domain: domain }) }; } return { filter: filter, animationConfig: animationConfig }; } function scaleSourceDomainToDestination(sourceDomain, destinationDomain) { // 0 -> 100: merged domains t1 - t0 === 100% filter may already have this info which is good var sourceDomainSize = sourceDomain[1] - sourceDomain[0]; // 10 -> 20: animationConfig domain d1 - d0 === animationConfig size var destinationDomainSize = destinationDomain[1] - destinationDomain[0]; // scale animationConfig size using domain size var scaledSourceDomainSize = sourceDomainSize / destinationDomainSize * 100; // scale d0 - t0 using domain size to find starting point var offset = sourceDomain[0] - destinationDomain[0]; var scaledOffset = offset / destinationDomainSize * 100; return [scaledOffset, scaledSourceDomainSize + scaledOffset]; } function getFilterScaledTimeline(filter, animationConfig) { if (!(filter.syncedWithLayerTimeline && animationConfig !== null && animationConfig !== void 0 && animationConfig.domain)) { return []; } return scaleSourceDomainToDestination(animationConfig.domain, filter.domain); } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfa2V5bWlycm9yIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfbG9kYXNoIiwiX2xvZGFzaDIiLCJfZDNBcnJheSIsIl9ib29sZWFuV2l0aGluIiwiX2hlbHBlcnMiLCJfZGVjaW1hbCIsIl9jb25zdGFudHMiLCJTY2FsZVV0aWxzIiwiX2ludGVyb3BSZXF1aXJlV2lsZGNhcmQiLCJfaDNKcyIsIl9jb21tb25VdGlscyIsIl91dGlscyIsIl9kYXRhVXRpbHMiLCJfcGxvdCIsIl9nZXRSZXF1aXJlV2lsZGNhcmRDYWNoZSIsImUiLCJXZWFrTWFwIiwiciIsInQiLCJfX2VzTW9kdWxlIiwiX3R5cGVvZiIsImhhcyIsImdldCIsIm4iLCJfX3Byb3RvX18iLCJhIiwiT2JqZWN0IiwiZGVmaW5lUHJvcGVydHkiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJ1IiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiaSIsInNldCIsIl90b1Byb3BlcnR5S2V5IiwiX3RvUHJpbWl0aXZlIiwiU3ltYm9sIiwidG9QcmltaXRpdmUiLCJUeXBlRXJyb3IiLCJTdHJpbmciLCJOdW1iZXIiLCJvd25LZXlzIiwia2V5cyIsImdldE93blByb3BlcnR5U3ltYm9scyIsIm8iLCJmaWx0ZXIiLCJlbnVtZXJhYmxlIiwicHVzaCIsImFwcGx5IiwiX29iamVjdFNwcmVhZCIsImFyZ3VtZW50cyIsImxlbmd0aCIsImZvckVhY2giLCJfZGVmaW5lUHJvcGVydHkyIiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9ycyIsImRlZmluZVByb3BlcnRpZXMiLCJkdXJhdGlvblNlY29uZCIsImV4cG9ydHMiLCJkdXJhdGlvbk1pbnV0ZSIsImR1cmF0aW9uSG91ciIsImR1cmF0aW9uRGF5IiwiZHVyYXRpb25XZWVrIiwiZHVyYXRpb25ZZWFyIiwiVGltZXN0YW1wU3RlcE1hcCIsIm1heCIsInN0ZXAiLCJQT1NJVElWRV9JTkZJTklUWSIsIkZJTFRFUl9VUERBVEVSX1BST1BTIiwia2V5TWlycm9yIiwiZGF0YUlkIiwibmFtZSIsImxheWVySWQiLCJGSUxURVJfQ09NUE9ORU5UUyIsIkZJTFRFUl9UWVBFUyIsInNlbGVjdCIsIm11bHRpU2VsZWN0IiwidGltZVJhbmdlIiwicmFuZ2UiLCJwb2x5Z29uIiwiREVGQVVMVF9GSUxURVJfU1RSVUNUVVJFIiwiaWQiLCJlbmFibGVkIiwiZml4ZWREb21haW4iLCJ2aWV3IiwiRklMVEVSX1ZJRVdfVFlQRVMiLCJzaWRlIiwiaXNBbmltYXRpbmciLCJhbmltYXRpb25XaW5kb3ciLCJBTklNQVRJT05fV0lORE9XIiwiZnJlZSIsInNwZWVkIiwidHlwZSIsImZpZWxkSWR4IiwiZG9tYWluIiwidmFsdWUiLCJwbG90VHlwZSIsIlBMT1RfVFlQRVMiLCJoaXN0b2dyYW0iLCJ5QXhpcyIsImdwdSIsIkZJTFRFUl9JRF9MRU5HVEgiLCJMQVlFUl9GSUxURVJTIiwiZ2V0RGVmYXVsdEZpbHRlciIsIl9yZWYiLCJ1bmRlZmluZWQiLCJ0b0FycmF5IiwiZ2VuZXJhdGVIYXNoSWQiLCJzaG91bGRBcHBseUZpbHRlciIsImRhdGFzZXRJZCIsImRhdGFJZHMiLCJpbmNsdWRlcyIsInZhbGlkYXRlUG9seWdvbkZpbHRlciIsImRhdGFzZXQiLCJsYXllcnMiLCJmYWlsZWQiLCJpc1ZhbGlkRmlsdGVyVmFsdWUiLCJpc1ZhbGlkRGF0YXNldCIsImxheWVyIiwiZmluZCIsImwiLCJmaWx0ZXJWYWxpZGF0b3JzIiwidmFsaWRhdGVGaWx0ZXIiLCJkYXRhc2V0cyIsIl9maWx0ZXIkdmlldyIsImZpbHRlckRhdGFJZCIsImZpbHRlckRhdGFzZXRJbmRleCIsImluZGV4T2YiLCJpbml0aWFsaXplRmlsdGVyIiwiZmllbGROYW1lIiwiX2FwcGx5RmlsdGVyRmllbGROYW1lIiwiYXBwbHlGaWx0ZXJGaWVsZE5hbWUiLCJtZXJnZURvbWFpbiIsInVwZGF0ZWRGaWx0ZXIiLCJ1cGRhdGVkRGF0YXNldCIsInZhbGlkYXRlRmlsdGVyWUF4aXMiLCJ2YWxpZGF0ZUZpbHRlcldpdGhEYXRhIiwicHJvdG90eXBlIiwiZmllbGRzIiwiX2ZpbHRlciIsIm1hdGNoZWRBeGlzIiwiX3JlZjIiLCJnZXRGaWx0ZXJQcm9wcyIsImZpZWxkIiwiZmllbGREb21haW4iLCJmaWx0ZXJQcm9wcyIsImZpZWxkVHlwZSIsIkFMTF9GSUVMRF9UWVBFUyIsInJlYWwiLCJpbnRlZ2VyIiwidHlwZU9wdGlvbnMiLCJzdHJpbmciLCJoMyIsImRhdGUiLCJ0aW1lc3RhbXAiLCJlbmxhcmdlZCIsImdldFBvbHlnb25GaWx0ZXJGdW5jdG9yIiwiZGF0YUNvbnRhaW5lciIsImdldFBvc2l0aW9uIiwiZ2V0UG9zaXRpb25BY2Nlc3NvciIsIkxBWUVSX1RZUEVTIiwicG9pbnQiLCJpY29uIiwiZGF0YSIsInBvcyIsImV2ZXJ5IiwiaXNGaW5pdGUiLCJpc0luUG9seWdvbiIsImFyYyIsImxpbmUiLCJoZXhhZ29uSWQiLCJkYXRhVG9GZWF0dXJlIiwiY2VudHJvaWRzIiwiY2VudHJvaWQiLCJpbmRleCIsImgzSXNWYWxpZCIsImdldENlbnRyb2lkIiwiZ2VvanNvbiIsImNhbkFwcGx5RmVhdHVyZUZpbHRlciIsImZlYXR1cmUiLCJCb29sZWFuIiwiZ2VvbWV0cnkiLCJnZXRGaWx0ZXJGdW5jdGlvbiIsInZhbHVlQWNjZXNzb3IiLCJkZWZhdWx0RnVuYyIsImlzSW5SYW5nZSIsIm1hcHBlZFZhbHVlIiwiYWNjZXNzb3IiLCJBcnJheSIsImlzQXJyYXkiLCJ0aW1lVG9Vbml4TWlsbGkiLCJmb3JtYXQiLCJsYXllckZpbHRlckZ1bmN0aW9ucyIsIm1hcCIsImNvbmZpZyIsImZpbHRlckZ1bmMiLCJ1cGRhdGVGaWx0ZXJEYXRhSWQiLCJmaWx0ZXJEYXRhQnlGaWx0ZXJUeXBlcyIsIl9yZWYzIiwiZHluYW1pY0RvbWFpbkZpbHRlcnMiLCJjcHVGaWx0ZXJzIiwiZmlsdGVyRnVuY3MiLCJmaWx0ZXJlZEluZGV4Rm9yRG9tYWluIiwiZmlsdGVyZWRJbmRleCIsImZpbHRlckNvbnRleHQiLCJmaWx0ZXJGdW5jQ2FsbGVyIiwibnVtUm93cyIsIm1hdGNoRm9yRG9tYWluIiwibWF0Y2hGb3JSZW5kZXIiLCJnZXRGaWx0ZXJSZWNvcmQiLCJmaWx0ZXJzIiwib3B0IiwiZmlsdGVyUmVjb3JkIiwiZHluYW1pY0RvbWFpbiIsImNwdSIsImYiLCJpZ25vcmVEb21haW4iLCJjcHVPbmx5IiwiZGlmZkZpbHRlcnMiLCJvbGRGaWx0ZXJSZWNvcmQiLCJmaWx0ZXJDaGFuZ2VkIiwiZW50cmllcyIsIl9yZWY0IiwiX3JlZjUiLCJfc2xpY2VkVG9BcnJheTIiLCJyZWNvcmQiLCJpdGVtcyIsIm9sZEZpbHRlciIsInByb3AiLCJjb25jYXQiLCJhZGp1c3RWYWx1ZVRvRmlsdGVyRG9tYWluIiwiX3JlZjYiLCJkIiwibm90TnVsbG9yVW5kZWZpbmVkIiwiZmlsdGVyZWRWYWx1ZSIsImdldE51bWVyaWNGaWVsZERvbWFpbiIsIm1hcEluZGV4IiwiZ2V0TGluZWFyRG9tYWluIiwiZGlmZiIsImdldE51bWVyaWNTdGVwU2l6ZSIsImZvcm1hdE51bWJlckJ5U3RlcCIsIk1hdGgiLCJhYnMiLCJ4IiwiZXhwb25lbnRpYWxGb3JtIiwidG9FeHBvbmVudGlhbCIsImV4cG9uZW50IiwicGFyc2VGbG9hdCIsInNwbGl0IiwiRGVjaW1hbCIsInBvdyIsInRvTnVtYmVyIiwiZ2V0VGltZXN0YW1wRmllbGREb21haW4iLCJkZWZhdWx0VGltZUZvcm1hdCIsImdldFRpbWVXaWRnZXRUaXRsZUZvcm1hdHRlciIsImVudHJ5IiwidmFsIiwiYm91bmQiLCJmbG9vciIsImNlaWwiLCJib29sZWFuV2l0aGluIiwidHVyZlBvaW50IiwiaXNWYWxpZFRpbWVEb21haW4iLCJpc0ZpbHRlclZhb