kepler.gl.geoiq
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
1,283 lines (1,073 loc) • 131 kB
JavaScript
"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.PLOT_TYPES = exports.LIMITED_FILTER_EFFECT_PROPS = exports.LAYER_FILTERS = exports.FILTER_UPDATER_PROPS = exports.FILTER_TYPES = exports.FILTER_ID_LENGTH = exports.FILTER_COMPONENTS = exports.DEFAULT_FILTER_STRUCTURE = void 0;
exports.adjustValueToFilterDomain = adjustValueToFilterDomain;
exports.applyFilterApiFieldName = applyFilterApiFieldName;
exports.applyFilterFieldName = applyFilterFieldName;
exports.applyFilterToDataset = applyFilterToDataset;
exports.applyFiltersToDatasets = applyFiltersToDatasets;
exports.featureToFilterValue = exports.enlargedHistogramBins = void 0;
exports.filterData = filterData;
exports.filterTileLayerData = filterTileLayerData;
exports.formatNumberByStep = formatNumberByStep;
exports.generatePolygonFilter = generatePolygonFilter;
exports.getDatasetFieldIndexForFilter = getDatasetFieldIndexForFilter;
exports.getDatasetIndexForFilter = getDatasetIndexForFilter;
exports.getDefaultFilter = getDefaultFilter;
exports.getDefaultFilterPlotType = getDefaultFilterPlotType;
exports.getFieldDomain = getFieldDomain;
exports.getFilterApiProps = getFilterApiProps;
exports.getFilterIdInFeature = void 0;
exports.getFilterPlot = getFilterPlot;
exports.getFilterProps = getFilterProps;
exports.getNumericFieldDomain = getNumericFieldDomain;
exports.getTimeWidgetHintFormatter = getTimeWidgetHintFormatter;
exports.getTimeWidgetTitleFormatter = getTimeWidgetTitleFormatter;
exports.getTimestampFieldDomain = getTimestampFieldDomain;
exports.histogramBins = void 0;
exports.histogramConstruct = histogramConstruct;
exports.isDataMatchFilter = isDataMatchFilter;
exports.isInPolygon = isInPolygon;
exports.isInRange = isInRange;
exports.isValidFilterValue = isValidFilterValue;
exports.mergeFilterProps = mergeFilterProps;
exports.shouldApplyfilter = shouldApplyfilter;
exports.updatePolygonFilter = updatePolygonFilter;
exports.validateFilter = validateFilter;
exports.validateFilterWithData = validateFilterWithData;
exports.validatePolygonFilter = validatePolygonFilter;
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _moment = _interopRequireDefault(require("moment"));
var _d3Array = require("d3-array");
var _keymirror = _interopRequireDefault(require("keymirror"));
var _lodash = _interopRequireDefault(require("lodash.get"));
var _booleanWithin = _interopRequireDefault(require("@turf/boolean-within"));
var _helpers = require("@turf/helpers");
var _defaultSettings = require("../constants/default-settings");
var _dataUtils = require("./data-utils");
var ScaleUtils = _interopRequireWildcard(require("./data-scale-utils"));
var _utils = require("./utils");
var _FILTER_TYPES$timeRan, _FILTER_TYPES$range, _SupportedPlotType, _FILTER_COMPONENTS, _filterDataMatchers;
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
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; }
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 histogramBins = exports.histogramBins = 30;
var enlargedHistogramBins = exports.enlargedHistogramBins = 100;
var durationSecond = 1000;
var durationMinute = durationSecond * 60;
var durationHour = durationMinute * 60;
var durationDay = durationHour * 24;
var durationWeek = durationDay * 7;
var durationYear = durationDay * 365;
var FILTER_TYPES = exports.FILTER_TYPES = (0, _keymirror["default"])({
range: null,
select: null,
timeRange: null,
multiSelect: null,
polygon: null
});
var PLOT_TYPES = exports.PLOT_TYPES = (0, _keymirror["default"])({
histogram: null,
lineChart: null
});
var FILTER_UPDATER_PROPS = exports.FILTER_UPDATER_PROPS = (0, _keymirror["default"])({
dataId: null,
name: null,
layerId: null
});
var LIMITED_FILTER_EFFECT_PROPS = exports.LIMITED_FILTER_EFFECT_PROPS = (0, _keymirror["default"])((0, _defineProperty2["default"])({}, FILTER_UPDATER_PROPS.name, null));
var SupportedPlotType = (_SupportedPlotType = {}, (0, _defineProperty2["default"])(_SupportedPlotType, FILTER_TYPES.timeRange, (_FILTER_TYPES$timeRan = {
"default": 'histogram'
}, (0, _defineProperty2["default"])(_FILTER_TYPES$timeRan, _defaultSettings.ALL_FIELD_TYPES.integer, 'lineChart'), (0, _defineProperty2["default"])(_FILTER_TYPES$timeRan, _defaultSettings.ALL_FIELD_TYPES.real, 'lineChart'), _FILTER_TYPES$timeRan)), (0, _defineProperty2["default"])(_SupportedPlotType, FILTER_TYPES.range, (_FILTER_TYPES$range = {
"default": 'histogram'
}, (0, _defineProperty2["default"])(_FILTER_TYPES$range, _defaultSettings.ALL_FIELD_TYPES.integer, 'lineChart'), (0, _defineProperty2["default"])(_FILTER_TYPES$range, _defaultSettings.ALL_FIELD_TYPES.real, 'lineChart'), _FILTER_TYPES$range)), _SupportedPlotType);
var FILTER_COMPONENTS = exports.FILTER_COMPONENTS = (_FILTER_COMPONENTS = {}, (0, _defineProperty2["default"])(_FILTER_COMPONENTS, FILTER_TYPES.select, 'SingleSelectFilter'), (0, _defineProperty2["default"])(_FILTER_COMPONENTS, FILTER_TYPES.multiSelect, 'MultiSelectFilter'), (0, _defineProperty2["default"])(_FILTER_COMPONENTS, FILTER_TYPES.timeRange, 'TimeRangeFilter'), (0, _defineProperty2["default"])(_FILTER_COMPONENTS, FILTER_TYPES.range, 'RangeFilter'), (0, _defineProperty2["default"])(_FILTER_COMPONENTS, FILTER_TYPES.polygon, 'PolygonFilter'), _FILTER_COMPONENTS);
var DEFAULT_FILTER_STRUCTURE = exports.DEFAULT_FILTER_STRUCTURE = {
dataId: [],
// [string]
freeze: false,
id: null,
// time range filter specific
fixedDomain: false,
enlarged: false,
isAnimating: false,
speed: 1,
// field specific
name: [],
// string
type: null,
fieldIdx: [],
// [integer]
domain: null,
value: null,
// plot
plotType: PLOT_TYPES.histogram,
yAxis: null,
interval: null,
// mode
gpu: false
};
var FILTER_ID_LENGTH = exports.FILTER_ID_LENGTH = 4;
var LAYER_FILTERS = exports.LAYER_FILTERS = [FILTER_TYPES.polygon];
/**
* Generates a filter with a dataset id as dataId
* @param {[string]} dataId
* @return {object} filter
*/
function getDefaultFilter(dataId) {
return _objectSpread(_objectSpread({}, DEFAULT_FILTER_STRUCTURE), {}, {
// store it as dataId and it could be one or many
dataId: (0, _utils.toArray)(dataId),
id: (0, _utils.generateHashId)(FILTER_ID_LENGTH)
});
}
/**
* Check if a filter is valid based on the given dataId
* @param {object} filter to validate
* @param {string} dataset id to validate filter against
* @return {boolean} true if a filter is valid, false otherwise
*/
function shouldApplyfilter(filter, datasetId) {
var dataIds = (0, _utils.toArray)(filter.dataId);
return dataIds.includes(datasetId) && filter.value !== null;
}
function validatePolygonFilter(dataset, filter, layers) {
var value = filter.value,
layerId = filter.layerId,
type = filter.type,
dataId = filter.dataId;
if (!(value && value.id && layerId)) {
return null;
}
var isValidDataset = dataId.includes(dataset.id);
if (!isValidDataset) {
return null;
}
var layer = layers.find(function (l) {
return layerId.includes(l.id);
});
if (!layer) {
return null;
}
if (!isValidFilterValue({
type: type,
value: value
})) {
return null;
}
return _objectSpread(_objectSpread({}, filter), {}, {
freeze: true,
fieldIdx: [0]
});
}
var filterValidators = (0, _defineProperty2["default"])({}, FILTER_TYPES.polygon, validatePolygonFilter);
function validateFilter(dataset, filter) {
var fields = dataset.fields,
allData = dataset.allData; // match filter.name to field.name
var filterDataId = (0, _utils.toArray)(filter.dataId);
var filterNames = (0, _utils.toArray)(filter.name);
var filterDatasetIndex = Array.isArray(filter.dataId) ? getDatasetIndexForFilter(dataset, filter) : 0;
var fieldIndex = fields.findIndex(function (_ref) {
var name = _ref.name;
return name === filterNames[filterDatasetIndex];
});
if (fieldIndex < 0) {
return null;
}
var field = fields[fieldIndex];
if (filterDatasetIndex === -1) {
// the current filter is not mapped against the current dataset
return null;
} // update fieldIdx with the current value
var newFieldIdx = (0, _utils.toArray)(filter.fieldIdx);
newFieldIdx[filterDatasetIndex] = fieldIndex; // return filter type, default value, fieldType and fieldDomain from field
var filterPropsFromField = getFilterProps(allData, field);
var matchedFilter = _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, getDefaultFilter(filter.dataId)), filter), filterPropsFromField), {}, {
dataId: filterDataId,
freeze: true,
fieldIdx: Object.assign((0, _toConsumableArray2["default"])(newFieldIdx), (0, _defineProperty2["default"])({}, filterDatasetIndex, fieldIndex)),
name: Object.assign((0, _toConsumableArray2["default"])(filterNames), (0, _defineProperty2["default"])({}, filterDatasetIndex, field.name))
});
var _matchedFilter = matchedFilter,
yAxis = _matchedFilter.yAxis; // TODO: validate yAxis against other datasets
if (yAxis) {
var matcheAxis = fields.find(function (_ref2) {
var name = _ref2.name,
type = _ref2.type;
return name === yAxis.name && type === yAxis.type;
});
matchedFilter = matcheAxis ? _objectSpread(_objectSpread({}, matchedFilter), {}, {
yAxis: matcheAxis
}, getFilterPlot(_objectSpread(_objectSpread({}, matchedFilter), {}, {
yAxis: matcheAxis
}), allData)) : matchedFilter;
}
matchedFilter.value = adjustValueToFilterDomain(filter.value, matchedFilter);
if (matchedFilter.value === null) {
// cannot adjust saved value to filter
return null;
}
return matchedFilter;
}
/**
* Validate saved filter config with new data,
* calculate domain and fieldIdx based new fields and data
*
* @param {Array<Object>} dataset.fields
* @param {Array<Object>} dataset.allData
* @param {Object} filter - filter to be validate
* @param {Array<Object>} layers - existing layers
* @return {Object | null} - validated filter
*/
function validateFilterWithData(dataset, filter, layers) {
return filterValidators.hasOwnProperty(filter.type) ? filterValidators[filter.type](dataset, filter, layers) : validateFilter(dataset, filter);
}
function updatePolygonFilter(filter, feature) {
var polygon = (0, _helpers.polygon)(feature.geometry.coordinates);
return _objectSpread(_objectSpread({}, filter), {}, {
// we merge both turf and feature properties into one
value: _objectSpread(_objectSpread({}, polygon), {}, {
id: feature.id,
properties: _objectSpread(_objectSpread({}, feature.properties), polygon.properties)
})
});
}
var featureToFilterValue = exports.featureToFilterValue = function featureToFilterValue(feature, filterId) {
var properties = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
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
* @param layers array of layers
* @param feature polygon to use
* @return {object} filter
*/
function generatePolygonFilter(layers, feature) {
var _layers$reduce = layers.reduce(function (acc, layer) {
return _objectSpread(_objectSpread({}, acc), {}, {
dataId: [].concat((0, _toConsumableArray2["default"])(acc.dataId), [layer.config.dataId]),
layerId: [].concat((0, _toConsumableArray2["default"])(acc.layerId), [layer.id]),
name: [].concat((0, _toConsumableArray2["default"])(acc.name), [layer.config.label])
});
}, {
dataId: [],
layerId: [],
name: []
}),
dataId = _layers$reduce.dataId,
layerId = _layers$reduce.layerId,
name = _layers$reduce.name;
var filter = getDefaultFilter(dataId);
return _objectSpread(_objectSpread({}, filter), {}, {
fixedDomain: true,
type: FILTER_TYPES.polygon,
name: name,
layerId: layerId,
value: featureToFilterValue(feature, filter.id, {
isVisible: true
})
});
}
/**
* Get default filter prop based on field type
*
* @param {Object[]} data
* @param {object} field
* @returns {object} default filter
*/
function getFilterProps(data, field) {
var filterProp = _objectSpread(_objectSpread({}, getFieldDomain(data, field)), {}, {
fieldType: field.type
});
switch (field.type) {
case _defaultSettings.ALL_FIELD_TYPES.real:
case _defaultSettings.ALL_FIELD_TYPES.integer:
return _objectSpread(_objectSpread({}, filterProp), {}, {
value: filterProp.domain,
type: FILTER_TYPES.range,
typeOptions: [FILTER_TYPES.range]
});
case _defaultSettings.ALL_FIELD_TYPES["boolean"]:
return _objectSpread(_objectSpread({}, filterProp), {}, {
type: FILTER_TYPES.select,
value: true
});
case _defaultSettings.ALL_FIELD_TYPES.string:
case _defaultSettings.ALL_FIELD_TYPES.date:
return _objectSpread(_objectSpread({}, filterProp), {}, {
type: FILTER_TYPES.multiSelect,
value: []
});
case _defaultSettings.ALL_FIELD_TYPES.timestamp:
return _objectSpread(_objectSpread({}, filterProp), {}, {
type: FILTER_TYPES.timeRange,
enlarged: true,
fixedDomain: true,
value: filterProp.domain
});
default:
return {};
}
}
/**
* Get default filter prop based on field type
*
* @param {Object[]} data
* @param {object} field
* @returns {object} default filter
*/
function getFilterApiProps(domain, histogram, field) {
var step = 0.1;
var filterProp = {
domain: domain,
histogram: histogram,
fieldType: field.type,
step: step
};
switch (field.type) {
case _defaultSettings.ALL_FIELD_TYPES.real:
case _defaultSettings.ALL_FIELD_TYPES.integer:
return _objectSpread(_objectSpread({}, filterProp), {}, {
value: filterProp.domain,
type: FILTER_TYPES.range,
typeOptions: [FILTER_TYPES.range]
});
case _defaultSettings.ALL_FIELD_TYPES["boolean"]:
return _objectSpread(_objectSpread({}, filterProp), {}, {
type: FILTER_TYPES.select,
value: true
});
case _defaultSettings.ALL_FIELD_TYPES.string:
case _defaultSettings.ALL_FIELD_TYPES.date:
return _objectSpread(_objectSpread({}, filterProp), {}, {
type: FILTER_TYPES.multiSelect,
value: []
});
case _defaultSettings.ALL_FIELD_TYPES.timestamp:
return _objectSpread(_objectSpread({}, filterProp), {}, {
type: FILTER_TYPES.timeRange,
enlarged: true,
fixedDomain: true,
value: filterProp.domain
});
default:
return {};
}
}
/**
* Calculate field domain based on field type and data
*
* @param {Object[]} data
* @param {object} field
* @returns {object} with domain as key
*/
function getFieldDomain(data, field) {
var fieldIdx = field.tableFieldIndex - 1;
var isTime = field.type === _defaultSettings.ALL_FIELD_TYPES.timestamp;
var valueAccessor = _dataUtils.maybeToDate.bind(null, isTime, fieldIdx, field.format);
var domain; // console.log('data and field in getFieldDomain', data, field);
switch (field.type) {
case _defaultSettings.ALL_FIELD_TYPES.real:
case _defaultSettings.ALL_FIELD_TYPES.integer:
// calculate domain and step
return getNumericFieldDomain(data, valueAccessor);
case _defaultSettings.ALL_FIELD_TYPES["boolean"]:
return {
domain: [true, false]
};
case _defaultSettings.ALL_FIELD_TYPES.string:
case _defaultSettings.ALL_FIELD_TYPES.date:
domain = ScaleUtils.getOrdinalDomain(data, valueAccessor);
return {
domain: domain
};
case _defaultSettings.ALL_FIELD_TYPES.timestamp:
return getTimestampFieldDomain(data, valueAccessor);
default:
return {
domain: ScaleUtils.getOrdinalDomain(data, valueAccessor)
};
}
}
/**
* Filter data based on an array of filters
* @param {Object} dataset to perform the filter on
* @param {Object[]} filters list of filters to use against dataset
* @param {Object[]} layers list of layers to perform filter on
*/
function filterData(dataset, filters, layers) {
var data = dataset.allData,
fields = dataset.fields;
if (!filters.length) {
var defaultValues = data.map(function (d, i) {
return i;
});
return {
data: data,
filteredIndex: defaultValues,
filteredIndexForDomain: defaultValues
};
}
var appliedFilters = filters.filter(function (d) {
return shouldApplyfilter(d, dataset.id);
}); // Map filter against current dataset field
var filtersToFields = filters.reduce(function (acc, filter) {
var fieldIndex = getDatasetFieldIndexForFilter(dataset, filter);
return _objectSpread(_objectSpread({}, acc), fieldIndex !== -1 ? (0, _defineProperty2["default"])({}, filter.id, fields[fieldIndex]) : {});
}, {// [filterId]: field
});
var _appliedFilters$reduc = appliedFilters.reduce(function (accu, f) {
(f.fixedDomain ? accu[1] : accu[0]).push(f);
return accu;
}, [[], []]),
_appliedFilters$reduc2 = (0, _slicedToArray2["default"])(_appliedFilters$reduc, 2),
dynamicDomainFilters = _appliedFilters$reduc2[0],
fixedDomainFilters = _appliedFilters$reduc2[1]; // we save a reference of allData index here to access dataToFeature
// in geojson and hexagonId layer
var _data$reduce = data.reduce(function (accu, d, i) {
// generate 2 sets of
// filter data used to calculate layer Domain
var matchForDomain = dynamicDomainFilters.every(function (filter) {
return isDataMatchFilter(d, filter, i, filtersToFields[filter.id], layers);
});
if (matchForDomain) {
accu.filteredIndexForDomain.push(i); // filter data for render
var matchForRender = fixedDomainFilters.every(function (filter) {
return isDataMatchFilter(d, filter, i, filtersToFields[filter.id], layers);
});
if (matchForRender) {
accu.filtered.push(d);
accu.filteredIndex.push(i);
}
}
return accu;
}, {
filtered: [],
filteredIndex: [],
filteredIndexForDomain: []
}),
filtered = _data$reduce.filtered,
filteredIndex = _data$reduce.filteredIndex,
filteredIndexForDomain = _data$reduce.filteredIndexForDomain;
return {
data: filtered,
filteredIndex: filteredIndex,
filteredIndexForDomain: filteredIndexForDomain
};
}
var filterDataMatchers = (_filterDataMatchers = {}, (0, _defineProperty2["default"])(_filterDataMatchers, FILTER_TYPES.range, function (data, filter, index, field) {
var val = field ? data[field.tableFieldIndex - 1] : null;
return isInRange(val, filter.value);
}), (0, _defineProperty2["default"])(_filterDataMatchers, FILTER_TYPES.timeRange, function (data, filter, index, field) {
var val = field ? data[field.tableFieldIndex - 1] : null;
var timeVal = field && field.filterProp && Array.isArray(field.filterProp.mappedValue) ? field.filterProp.mappedValue[index] : _moment["default"].utc(val).valueOf();
return isInRange(timeVal, filter.value);
}), (0, _defineProperty2["default"])(_filterDataMatchers, FILTER_TYPES.multiSelect, function (data, filter, index, field) {
var val = field ? data[field.tableFieldIndex - 1] : null;
return filter.value.includes(val);
}), (0, _defineProperty2["default"])(_filterDataMatchers, FILTER_TYPES.select, function (data, filter, index, field) {
var val = field ? data[field.tableFieldIndex - 1] : null;
return val === filter.value;
}), (0, _defineProperty2["default"])(_filterDataMatchers, FILTER_TYPES.polygon, function (data, filter, index, field, layers) {
if (!(layers || layers.length === 0)) {
return true;
} // determine which layers to apply the filter on
var currentLayers = filter.layerId.map(function (id) {
return layers.find(function (l) {
return l.id === id;
});
} // we may get null value because filter.layerId may contain layers from other datasets
).filter(function (l) {
return Boolean(l);
});
return currentLayers.every(function (layer) {
var _layer$config$columns = layer.config.columns,
lat = _layer$config$columns.lat,
lng = _layer$config$columns.lng;
var point = [data[lng.fieldIdx], data[lat.fieldIdx]];
return isInPolygon(point, filter.value);
});
}), _filterDataMatchers);
/**
* Check if value is in range of filter
*
* @param {Object[]} data
* @param {Object} filter
* @param {number} i
* @param {field} field containing values to test data against. This is used only when
* testing timestamp filters
* @param layers to perform filters upon
* @returns {Boolean} - whether value falls in the range of the filter
*/
function isDataMatchFilter(data, filter, i, field) {
var layers = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
return !filter.type || !filterDataMatchers.hasOwnProperty(filter.type) ? true : filterDataMatchers[filter.type](data, filter, i, field, layers);
}
/**
* Call by parsing filters from URL
* Check if value of filter within filter domain, if not adjust it to match
* filter domain
*
* @param {string[] | string | number | number[]} value
* @param {Array} filter.domain
* @param {String} filter.type
* @returns {*} - adjusted value to match filter or null to remove filter
*/
/* eslint-disable complexity */
function adjustValueToFilterDomain(value, _ref4) {
var domain = _ref4.domain,
type = _ref4.type;
if (!domain || !type) {
return false;
}
switch (type) {
case FILTER_TYPES.range:
case 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, _dataUtils.notNullorUndefined)(d) && isInRange(d, domain) ? d : domain[i];
});
case FILTER_TYPES.multiSelect:
if (!Array.isArray(value)) {
return [];
}
var filteredValue = value.filter(function (d) {
return domain.includes(d);
});
return filteredValue.length ? filteredValue : [];
case FILTER_TYPES.select:
return domain.includes(value) ? value : true;
default:
return null;
}
}
/* eslint-enable complexity */
/**
* Calculate numeric domain and suitable step
*
* @param {Object[]} data
* @param {function} valueAccessor
* @returns {object} domain and step
*/
function getNumericFieldDomain(data, valueAccessor) {
var domain = [0, 1];
var step = 0.1;
var mappedValue = Array.isArray(data) ? data.map(valueAccessor) : [];
if (Array.isArray(data) && data.length > 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');
}
var _getHistogram = getHistogram(domain, mappedValue),
histogram = _getHistogram.histogram,
enlargedHistogram = _getHistogram.enlargedHistogram;
return {
domain: domain,
step: step,
histogram: histogram,
enlargedHistogram: enlargedHistogram
};
}
function getNumericStepSize(diff) {
if (diff > 100) {
return 1;
} else if (diff < 20 && diff > 3) {
return 0.01;
} else if (diff <= 3) {
return 0.001;
}
}
/**
* Calculate timestamp domain and suitable step
*
* @param {Object[]} data
* @param {function} valueAccessor
* @returns {object} domain and step
*/
function getTimestampFieldDomain(data, 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 = Array.isArray(data) ? data.map(valueAccessor) : [];
var domain = ScaleUtils.getLinearDomain(mappedValue);
var step = 0.01;
var diff = domain[1] - domain[0];
var entry = TimestampStepMap.find(function (f) {
return f.max >= diff;
});
if (entry) {
step = entry.step;
}
var _getHistogram2 = getHistogram(domain, mappedValue),
histogram = _getHistogram2.histogram,
enlargedHistogram = _getHistogram2.enlargedHistogram;
return {
domain: domain,
step: step,
mappedValue: mappedValue,
histogram: histogram,
enlargedHistogram: enlargedHistogram
};
}
function histogramConstruct(domain, mappedValue, bins) {
return (0, _d3Array.histogram)().thresholds((0, _d3Array.ticks)(domain[0], domain[1], bins)).domain(domain)(mappedValue).map(function (bin) {
return {
count: bin.length,
x0: bin.x0,
x1: bin.x1
};
});
}
/**
* Calculate histogram from domain and array of values
*
* @param {number[]} domain
* @param {Object[]} mappedValue
* @returns {Array[]} histogram
*/
function getHistogram(domain, mappedValue) {
var histogram = histogramConstruct(domain, mappedValue, histogramBins);
var enlargedHistogram = histogramConstruct(domain, mappedValue, enlargedHistogramBins);
return {
histogram: histogram,
enlargedHistogram: enlargedHistogram
};
}
/**
* 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;
}
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) {
var convertedPoint = (0, _helpers.point)(point);
var present = (0, _booleanWithin["default"])(convertedPoint, polygon);
return present;
}
function getTimeWidgetTitleFormatter(domain) {
if (!Array.isArray(domain)) {
return null;
}
var diff = domain[1] - domain[0];
return diff > durationYear ? 'MM/DD/YY' : diff > durationDay ? 'MM/DD/YY hh:mma' : 'MM/DD/YY hh:mm:ssa';
}
function getTimeWidgetHintFormatter(domain) {
if (!Array.isArray(domain)) {
return null;
}
var diff = domain[1] - domain[0];
return diff > durationYear ? 'MM/DD/YY' : diff > durationWeek ? 'MM/DD' : diff > durationDay ? 'MM/DD hha' : diff > durationHour ? 'hh:mma' : 'hh:mm:ssa';
}
/**
* Sanity check on filters to prepare for save
* @param {String} type - filter type
* @param {*} value - filter value
* @returns {boolean} whether filter is value
*/
/* eslint-disable complexity */
function isValidFilterValue(_ref5) {
var type = _ref5.type,
value = _ref5.value;
if (!type) {
return false;
}
switch (type) {
case FILTER_TYPES.select:
return value === true || value === false;
case FILTER_TYPES.range:
case FILTER_TYPES.timeRange:
return Array.isArray(value) && value.every(function (v) {
return v !== null && !isNaN(v);
});
case FILTER_TYPES.multiSelect:
return Array.isArray(value) && Boolean(value.length);
case FILTER_TYPES.input:
return Boolean(value.length);
case FILTER_TYPES.polygon:
return Boolean(value && value.id && value.geometry && value.geometry.coordinates);
default:
return true;
}
}
/* eslint-enable complexity */
function getFilterPlot(filter, allData) {
if (filter.plotType === PLOT_TYPES.histogram || !filter.yAxis) {
// histogram should be calculated when create filter
return {};
}
var mappedValue = filter.mappedValue;
var yAxis = filter.yAxis; // return lineChart
var series = allData.map(function (d, i) {
return {
x: mappedValue[i],
y: d[yAxis.tableFieldIndex - 1]
};
}).filter(function (_ref6) {
var x = _ref6.x,
y = _ref6.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 getDefaultFilterPlotType(filter) {
var filterPlotTypes = SupportedPlotType[filter.type];
if (!filterPlotTypes) {
return null;
}
if (!filter.yAxis) {
return filterPlotTypes["default"];
}
return filterPlotTypes[filter.yAxis.type] || null;
}
/**
* Apply a list of filters to a given dataset
* @param dataset
* @param filters
* @return {Object} filtered dataset
*/
function applyFilterToDataset(dataset, filters, layers) {
return _objectSpread(_objectSpread({}, dataset), filterData(dataset, filters, layers));
}
/**
*
* @param datasetIds list of dataset ids to be filtered
* @param datasets all datasets
* @param filters all filters to be applied to datasets
* @return {{[datasetId: string]: Object}} datasets - new updated datasets
*/
function applyFiltersToDatasets(datasetIds, datasets, filters, layers) {
var dataIds = (0, _utils.toArray)(datasetIds);
return dataIds.reduce(function (acc, dataIdentifier) {
var layersToFilter = (layers || []).filter(function (l) {
return l.config.dataId === dataIdentifier;
});
return _objectSpread(_objectSpread({}, acc), {}, (0, _defineProperty2["default"])({}, dataIdentifier, applyFilterToDataset(datasets[dataIdentifier], filters, layersToFilter)));
}, datasets);
}
/**
* Applies a new field name value to fielter and update both filter and dataset
* @param filter to be applied the new field name on
* @param datasets
* @param fieldName
* @return {object} {filter, datasets}
*/
function applyFilterFieldName(filter, datasets, fieldName) {
var filterDatasetIndex = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
// using filterDatasetIndex we can filter only the specified dataset
var dataId = filter.dataId;
var dataIdentifier = dataId[filterDatasetIndex];
var _datasets$dataIdentif = datasets[dataIdentifier],
fields = _datasets$dataIdentif.fields,
allData = _datasets$dataIdentif.allData;
var fieldIndex = fields.findIndex(function (f) {
return f.name === fieldName;
}); // if no field with same name is found, move to the next datasets
if (fieldIndex === -1) {
throw new Error("fieldIndex not found. Dataset must contain a property with name: ".concat(fieldName));
}
var newFilter = _objectSpread(_objectSpread({}, filter), {}, {
// TODO, since we allow to add multiple fields to a filter we can no longer freeze the filter
freeze: true
}); // TODO: validate field type
var field = fields[fieldIndex];
var filterProps = field.hasOwnProperty('filterProps') ? field.filterProps : getFilterProps(allData, field); // Update Filter field idx
var filterName = (0, _utils.toArray)(filter.name);
var filterIdx = (0, _utils.toArray)(filter.fieldIdx);
var filterWithProps = _objectSpread(_objectSpread({}, mergeFilterProps(newFilter, filterProps)), {}, {
name: Object.assign((0, _toConsumableArray2["default"])(filterName), (0, _defineProperty2["default"])({}, filterDatasetIndex, field.name)),
fieldIdx: Object.assign((0, _toConsumableArray2["default"])(filterIdx), (0, _defineProperty2["default"])({}, filterDatasetIndex, field.tableFieldIndex - 1))
});
var fieldWithFilterProps = _objectSpread(_objectSpread({}, field), {}, {
filterProp: filterProps
});
var newFields = fields.map(function (d, i) {
return i === fieldIndex ? fieldWithFilterProps : d;
});
return {
filter: filterWithProps,
datasets: _objectSpread(_objectSpread({}, datasets), {}, (0, _defineProperty2["default"])({}, dataIdentifier, _objectSpread(_objectSpread({}, datasets[dataIdentifier]), {}, {
fields: newFields
})))
};
}
/**
* Applies a new field name value to fielter and update both filter and dataset
* @param filter to be applied the new field name on
* @param datasets
* @param fieldName
* @return {object} {filter, datasets}
*/
function applyFilterApiFieldName(filter, dataset, fieldName) {
var filterDatasetIndex = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
var _ref7 = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {},
_ref7$mergeDomain = _ref7.mergeDomain,
mergeDomain = _ref7$mergeDomain === void 0 ? false : _ref7$mergeDomain;
var histogram = arguments.length > 5 ? arguments[5] : undefined;
var domain = arguments.length > 6 ? arguments[6] : undefined;
// using filterDatasetIndex we can filter only the specified dataset
var fields = dataset.fields,
allData = dataset.allData;
var fieldIndex = fields.findIndex(function (f) {
return f.name === fieldName;
}); // if no field with same name is found, move to the next datasets
if (fieldIndex === -1) {
// throw new Error(`fieldIndex not found. Dataset must contain a property with name: ${fieldName}`);
return {
filter: null,
dataset: dataset
};
}
var newFilter = _objectSpread(_objectSpread({}, filter), {}, {
// TODO, since we allow to add multiple fields to a filter we can no longer freeze the filter
freeze: true
}); // TODO: validate field type
var field = fields[fieldIndex];
var filterProps = field.hasOwnProperty('filterProps') ? field.filterProps : getFilterApiProps(domain, histogram, field);
var filterWithProps = _objectSpread(_objectSpread({}, mergeDomain ? mergeFilterDomainStep(newFilter, filterProps) : _objectSpread(_objectSpread({}, newFilter), filterProps)), {}, {
name: Object.assign([].concat(filter.name), (0, _defineProperty2["default"])({}, filterDatasetIndex, field.name)),
fieldIdx: Object.assign([].concat(filter.fieldIdx), (0, _defineProperty2["default"])({}, filterDatasetIndex, field.tableFieldIndex - 1))
});
var fieldWithFilterProps = _objectSpread(_objectSpread({}, field), {}, {
filterProps: filterProps
});
var newFields = fields.map(function (d, i) {
return i === fieldIndex ? fieldWithFilterProps : d;
});
return {
filter: filterWithProps,
dataset: _objectSpread(_objectSpread({}, dataset), {}, {
fields: newFields
})
};
}
/**
* Merge one filter with other filter prop domain
* @param filter
* @param filterProps
* @param fieldIndex
* @param datasetIndex
* @return {*}
*/
/* eslint-disable complexity */
function mergeFilterProps(filter, filterProps) {
if (!filter) {
return filterProps;
}
if (!filterProps) {
return filter;
}
if (!filterProps || filter.fieldType && filter.fieldType !== filterProps.fieldType || !filterProps.domain) {
return filter;
}
var combinedDomain = !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), {}, {
domain: [combinedDomain[0], combinedDomain[combinedDomain.length - 1]]
});
switch (filterProps.fieldType) {
case _defaultSettings.ALL_FIELD_TYPES.string:
case _defaultSettings.ALL_FIELD_TYPES.date:
return _objectSpread(_objectSpread({}, newFilter), {}, {
domain: (0, _dataUtils.unique)(combinedDomain).sort()
});
case _defaultSettings.ALL_FIELD_TYPES.timestamp:
var step = filter.step < filterProps.step ? filter.step : filterProps.step;
return _objectSpread(_objectSpread({}, newFilter), {}, {
step: step // step: Math.min(filter.step, filterProps.step)
});
case _defaultSettings.ALL_FIELD_TYPES.real:
case _defaultSettings.ALL_FIELD_TYPES.integer:
default:
return newFilter;
}
}
/* eslint-enable complexity */
/**
* Return filter dataset index from filter.dataId
* @param dataset
* @param filter
* @return {*}
*/
function getDatasetIndexForFilter(dataset, filter) {
var dataId = filter.dataId;
var dataIds = (0, _utils.toArray)(dataId); // dataId is an array
return dataIds.findIndex(function (id) {
return id === dataset.id;
});
}
/**
* Return dataset field index from filter.fieldIdx
* The index matches the same dataset index for filter.dataId
* @param dataset
* @param filter
* @return {*}
*/
function getDatasetFieldIndexForFilter(dataset, filter) {
var datasetIndex = getDatasetIndexForFilter(dataset, filter);
if (datasetIndex === -1) {
return datasetIndex;
}
var fieldIndex = filter.fieldIdx[datasetIndex];
return (0, _dataUtils.notNullorUndefined)(fieldIndex) ? fieldIndex : -1;
}
/**
* Filter data based on an array of filters
*
* @param {Object[]} data
* @param {string} dataId
* @param {Object[]} filters
* @returns {Object[]} data
* @returns {Number[]} filteredIndex
*/
function filterTileLayerData(data, dataId, filters) {
if (!data || !dataId) {
// why would there not be any data? are we over doing this?
return {
data: [],
filteredIndex: []
};
}
if (!filters.length) {
return {
data: data,
filteredIndex: data.map(function (_, i) {
return i;
}),
filteredIndexForDomain: data.map(function (_, i) {
return i;
})
};
}
var appliedFilters = filters.filter(function (d) {
return d.dataId === dataId && d.fieldIdx > -1 && d.value !== null;
});
var _appliedFilters$reduc3 = appliedFilters.reduce(function (accu, f) {
if (f.dataId === dataId && f.fieldIdx > -1 && f.value !== null) {
(f.fixedDomain ? accu[1] : accu[0]).push(f);
}
return accu;
}, [[], []]),
_appliedFilters$reduc4 = (0, _slicedToArray2["default"])(_appliedFilters$reduc3, 2),
dynamicDomainFilters = _appliedFilters$reduc4[0],
fixedDomainFilters = _appliedFilters$reduc4[1]; // console.log(dynamicDomainFilters)
// console.log(fixedDomainFilters)
// we save a reference of allData index here to access dataToFeature
// in geojson and hexgonId layer
// console.time('filterData');
var _data$reduce2 = data.reduce(function (accu, d, i) {
// generate 2 sets of
// filter data used to calculate layer Domain
var matchForDomain = dynamicDomainFilters.every(function (filter) {
return isDataMatchFilter(d, filter, i);
});
if (matchForDomain) {
accu.filteredIndexForDomain.push(i); // filter data for render
var matchForRender = fixedDomainFilters.every(function (filter) {
return isDataMatchFilter(d, filter, i);
});
if (matchForRender) {
accu.filtered.push(d);
accu.filteredIndex.push(i);
}
}
return accu;
}, {
filtered: [],
filteredIndex: [],
filteredIndexForDomain: []
}),
filtered = _data$reduce2.filtered,
filteredIndex = _data$reduce2.filteredIndex,
filteredIndexForDomain = _data$reduce2.filteredIndexForDomain; // console.log('data==', data.length)
// console.log('filtered==', filtered.length)
// console.log('filteredIndex==', filteredIndex.length)
// console.log('filteredIndexForDomain==', filteredIndexForDomain.length)
//
// console.timeEnd('filterData');
return {
data: filtered,
filteredIndex: filteredIndex,
filteredIndexForDomain: filteredIndexForDomain
};
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9maWx0ZXItdXRpbHMuanMiXSwibmFtZXMiOlsiVGltZXN0YW1wU3RlcE1hcCIsIm1heCIsInN0ZXAiLCJOdW1iZXIiLCJQT1NJVElWRV9JTkZJTklUWSIsImhpc3RvZ3JhbUJpbnMiLCJlbmxhcmdlZEhpc3RvZ3JhbUJpbnMiLCJkdXJhdGlvblNlY29uZCIsImR1cmF0aW9uTWludXRlIiwiZHVyYXRpb25Ib3VyIiwiZHVyYXRpb25EYXkiLCJkdXJhdGlvbldlZWsiLCJkdXJhdGlvblllYXIiLCJGSUxURVJfVFlQRVMiLCJyYW5nZSIsInNlbGVjdCIsInRpbWVSYW5nZSIsIm11bHRpU2VsZWN0IiwicG9seWdvbiIsIlBMT1RfVFlQRVMiLCJoaXN0b2dyYW0iLCJsaW5lQ2hhcnQiLCJGSUxURVJfVVBEQVRFUl9QUk9QUyIsImRhdGFJZCIsIm5hbWUiLCJsYXllcklkIiwiTElNSVRFRF9GSUxURVJfRUZGRUNUX1BST1BTIiwiU3VwcG9ydGVkUGxvdFR5cGUiLCJBTExfRklFTERfVFlQRVMiLCJpbnRlZ2VyIiwicmVhbCIsIkZJTFRFUl9DT01QT05FTlRTIiwiREVGQVVMVF9GSUxURVJfU1RSVUNUVVJFIiwiZnJlZXplIiwiaWQiLCJmaXhlZERvbWFpbiIsImVubGFyZ2VkIiwiaXNBbmltYXRpbmciLCJzcGVlZCIsInR5cGUiLCJmaWVsZElkeCIsImRvbWFpbiIsInZhbHVlIiwicGxvdFR5cGUiLCJ5QXhpcyIsImludGVydmFsIiwiZ3B1IiwiRklMVEVSX0lEX0xFTkdUSCIsIkxBWUVSX0ZJTFRFUlMiLCJnZXREZWZhdWx0RmlsdGVyIiwic2hvdWxkQXBwbHlmaWx0ZXIiLCJmaWx0ZXIiLCJkYXRhc2V0SWQiLCJkYXRhSWRzIiwiaW5jbHVkZXMiLCJ2YWxpZGF0ZVBvbHlnb25GaWx0ZXIiLCJkYXRhc2V0IiwibGF5ZXJzIiwiaXNWYWxpZERhdGFzZXQiLCJsYXllciIsImZpbmQiLCJsIiwiaXNWYWxpZEZpbHRlclZhbHVlIiwiZmlsdGVyVmFsaWRhdG9ycyIsInZhbGlkYXRlRmlsdGVyIiwiZmllbGRzIiwiYWxsRGF0YSIsImZpbHRlckRhdGFJZCIsImZpbHRlck5hbWVzIiwiZmlsdGVyRGF0YXNldEluZGV4IiwiQXJyYXkiLCJpc0FycmF5IiwiZ2V0RGF0YXNldEluZGV4Rm9yRmlsdGVyIiwiZmllbGRJbmRleCIsImZpbmRJbmRleCIsImZpZWxkIiwibmV3RmllbGRJZHgiLCJmaWx0ZXJQcm9wc0Zyb21GaWVsZCIsImdldEZpbHRlclByb3BzIiwibWF0Y2hlZEZpbHRlciIsIk9iamVjdCIsImFzc2lnbiIsIm1hdGNoZUF4aXMiLCJnZXRGaWx0ZXJQbG90IiwiYWRqdXN0VmFsdWVUb0ZpbHRlckRvbWFpbiIsInZhbGlkYXRlRmlsdGVyV2l0aERhdGEiLCJoYXNPd25Qcm9wZXJ0eSIsInVwZGF0ZVBvbHlnb25GaWx0ZXIiLCJmZWF0dXJlIiwiZ2VvbWV0cnkiLCJjb29yZGluYXRlcyIsInByb3BlcnRpZXMiLCJmZWF0dXJlVG9GaWx0ZXJWYWx1ZSIsImZpbHRlcklkIiwiZ2V0RmlsdGVySWRJbkZlYXR1cmUiLCJmIiwiZ2VuZXJhdGVQb2x5Z29uRmlsdGVyIiwicmVkdWNlIiwiYWNjIiwiY29uZmlnIiwibGFiZWwiLCJpc1Zpc2libGUiLCJkYXRhIiwiZmlsdGVyUHJvcCIsImdldEZpZWxkRG9tYWluIiwiZmllbGRUeXBlIiwidHlwZU9wdGlvbnMiLCJzdHJpbmciLCJkYXRlIiwidGltZXN0YW1wIiwiZ2V0RmlsdGVyQXBpUHJvcHMiLCJ0YWJsZUZpZWxkSW5kZXgiLCJpc1RpbWUiLCJ2YWx1ZUFjY2Vzc29yIiwibWF5YmVUb0RhdGUiLCJiaW5kIiwiZm9ybWF0IiwiZ2V0TnVtZXJpY0ZpZWxkRG9tYWluIiwiU2NhbGVVdGlscyIsImdldE9yZGluYWxEb21haW4iLCJnZXRUaW1lc3RhbXBGaWVsZERvbWFpbiIsImZpbHRlckRhdGEiLCJmaWx0ZXJzIiwibGVuZ3RoIiwiZGVmYXVsdFZhbHVlcyIsIm1hcCIsImQiLCJpIiwiZmlsdGVyZWRJbmRleCIsImZpbHRlcmVkSW5kZXhGb3JEb21haW4iLCJhcHBsaWVkRmlsdGVycyIsImZpbHRlcnNUb0ZpZWxkcyIsImdldERhdGFzZXRGaWVsZEluZGV4Rm9yRmlsdGVyIiwiYWNjdSIsInB1c2giLCJkeW5hbWljRG9tYWluRmlsdGVycyIsImZpeGVkRG9tYWluRmlsdGVycyIsIm1hdGNoRm9yRG9tYWluIiwiZXZlcnkiLCJpc0RhdGFNYXRjaEZpbHRlciIsIm1hdGNoRm9yUmVuZGVyIiwiZmlsdGVyZWQiLCJmaWx0ZXJEYXRhTWF0Y2hlcnMiLCJpbmRleCIsInZhbCIsImlzSW5SYW5nZSIsInRpbWVWYWwiLCJtYXBwZWRWYWx1ZSIsIm1vbWVudCIsInV0YyIsInZhbHVlT2YiLCJjdXJyZW50TGF5ZXJzIiwiQm9vbGVhbiIsImNvbHVtbnMiLCJsYXQiLCJsbmciLCJwb2ludCIsImlzSW5Qb2x5Z29uIiwiZmlsdGVyZWRWYWx1ZSIsImdldExpbmVhckRvbWFpbiIsImRpZmYiLCJnZXROdW1lcmljU3RlcFNpemUiLCJmb3JtYXROdW1iZXJCeVN0ZXAiLCJnZXRIaXN0b2dyYW0iLCJlbmxhcmdlZEhpc3RvZ3JhbSIsImVudHJ5IiwiaGlzdG9ncmFtQ29uc3RydWN0IiwiYmlucyIsInRocmVzaG9sZHMiLCJiaW4iLCJjb3VudCIsIngwIiwieDEiLCJib3VuZCIsIk1hdGgiLCJmbG9vciIsImNlaWwiLCJjb252ZXJ0ZWRQb2ludCIsInByZXNlbnQiLCJnZXRUaW1lV2lkZ2V0VGl0bGVGb3JtYXR0ZXIiLCJnZXRUaW1lV2lkZ2V0SGludEZvcm1hdHRlciIsInYiLCJpc05hTiIsImlucHV0Iiwic2VyaWVzIiwieCIsInkiLCJpc0Zpbml0ZSIsInNvcnQiLCJhIiwiYiIsInlEb21haW4iLCJ4RG9tYWluIiwiZ2V0RGVmYXVsdEZpbHRlclBsb3RUeXBlIiwiZmlsdGVyUGxvdFR5cGVzIiwiYXBwbHlGaWx0ZXJUb0RhdGFzZXQiLCJhcHBseUZpbHRlcnNUb0RhdGFzZXRzIiwiZGF0YXNldElkcyIsImRhdGFzZXRzIiwiZGF0YUlkZW50aWZpZXIiLCJsYXllcnNUb0ZpbHRlciIsImFwcGx5RmlsdGVyRmllbGROYW1lIiwiZmllbGROYW1lIiwiRXJyb3IiLCJuZXdGaWx0ZXIiLCJmaWx0ZXJQcm9wcyIsImZpbHRlck5hbWUiLCJmaWx0ZXJJZHgiLCJmaWx0ZXJXaXRoUHJvcHMiLCJtZXJnZUZpbHRlclByb3BzIiwiZmllbGRXaXRoRmlsdGVyUHJvcHMiLCJuZXdGaWVsZHMiLCJhcHBseUZpbHRlckFwaUZpZWxkTmFtZSIsIm1lcmdlRG9tYWluIiwibWVyZ2VGaWx0ZXJEb21haW5TdGVwIiwiY29uY2F0IiwiY29tYmluZWREb21haW4iLCJkYXRhc2V0SW5kZXgiLCJmaWx0ZXJUaWxlTGF5ZXJEYXRhIiwiXyJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQW9CQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7Ozs7Ozs7Ozs7O0FBR08sSUFBTUEsZ0JBQWdCLDhCQUFHLENBQzlCO0FBQUNDLEVBQUFBLEdBQUcsRUFBRSxDQUFOO0FBQVNDLEVBQUFBLElBQUksRUFBRTtBQUFmLENBRDhCLEVBRTlCO0FBQUNELEVBQUFBLEdBQUcsRUFBRSxFQUFOO0FBQVVDLEVBQUFBLElBQUksRUFBRTtBQUFoQixDQUY4QixFQUc5QjtBQUFDRCxFQUFBQSxHQUFHLEVBQUUsR0FBTjtBQUFXQyxFQUFBQSxJQUFJLEVBQUU7QUFBakIsQ0FIOEIsRUFJOUI7QUFBQ0QsRUFBQUEsR0FBRyxFQUFFLEdBQU47QUFBV0MsRUFBQUEsSUFBSSxFQUFFO0FBQWpCLENBSjhCLEVBSzlCO0FBQUNELEVBQUFBLEdBQUcsRUFBRSxJQUFOO0FBQVlDLEVBQUFBLElBQUksRUFBRTtBQUFsQixDQUw4QixFQU05QjtBQUFDRCxFQUFBQSxHQUFHLEVBQUUsSUFBTjtBQUFZQyxFQUFBQSxJQUFJLEVBQUU7QUFBbEIsQ0FOOEIsRUFP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