kepler.gl.geoiq
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
303 lines (265 loc) • 33.5 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
var _deck = require("deck.gl");
var _geoViewport = _interopRequireDefault(require("@mapbox/geo-viewport"));
var _d3Array = require("d3-array");
var _dataScaleUtils = require("../../utils/data-scale-utils");
var _utils = require("../layer-utils/utils");
var _colorRanges = require("../../constants/color-ranges");
var _layerFactory = require("../../layers/layer-factory");
var _defaultSettings = require("../../constants/default-settings");
var _clusterUtils = require("../layer-utils/cluster-utils");
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
var defaultRadius = _layerFactory.LAYER_VIS_CONFIGS.clusterRadius.defaultValue;
var defaultRadiusRange = _layerFactory.LAYER_VIS_CONFIGS.clusterRadiusRange.defaultValue;
var defaultProps = {
clusterRadius: defaultRadius,
colorDomain: null,
colorRange: _colorRanges.DefaultColorRange,
colorScale: _defaultSettings.SCALE_TYPES.quantize,
radiusRange: defaultRadiusRange,
// maybe later...
lowerPercentile: 0,
upperPercentile: 100,
getPosition: function getPosition(x) {
return x.position;
},
// if want to have color based on customized aggregator, instead of count
getColorValue: function getColorValue(points) {
return points.length;
},
// if want to have radius based on customized aggregator, instead of count
getRadiusValue: function getRadiusValue(cell) {
return cell.properties.point_count;
},
fp64: false
};
var ClusterLayer =
/*#__PURE__*/
function (_CompositeLayer) {
(0, _inherits2["default"])(ClusterLayer, _CompositeLayer);
function ClusterLayer() {
(0, _classCallCheck2["default"])(this, ClusterLayer);
return (0, _possibleConstructorReturn2["default"])(this, (0, _getPrototypeOf2["default"])(ClusterLayer).apply(this, arguments));
}
(0, _createClass2["default"])(ClusterLayer, [{
key: "initializeState",
value: function initializeState() {
this.state = {
clusters: null,
geoJSON: null
};
}
}, {
key: "shouldUpdateState",
value: function shouldUpdateState(_ref) {
var changeFlags = _ref.changeFlags;
return changeFlags.somethingChanged;
}
}, {
key: "updateState",
value: function updateState(_ref2) {
var context = _ref2.context,
oldProps = _ref2.oldProps,
props = _ref2.props,
changeFlags = _ref2.changeFlags;
if (changeFlags.dataChanged || changeFlags.viewportChanged || this.needsReProjectPoints(oldProps, props)) {
// project data into clusters, and get clustered data
this.processGeoJSON();
this.getClusters(); // this needs clustered data to be set
this.getColorValueDomain();
} else if (this.needsReclusterPoints(oldProps, props)) {
this.getClusters();
this.getColorValueDomain();
} else if (this.needsRecalculateScaleFunction(oldProps, props)) {
this.getColorValueDomain();
}
}
}, {
key: "needsReProjectPoints",
value: function needsReProjectPoints(oldProps, props) {
return oldProps.clusterRadius !== props.clusterRadius || oldProps.getPosition !== props.getPosition;
}
}, {
key: "needsReclusterPoints",
value: function needsReclusterPoints(oldProps, props) {
return Math.round(oldProps.zoom) !== Math.round(props.zoom);
}
}, {
key: "needsRecalculateScaleFunction",
value: function needsRecalculateScaleFunction(oldProps, props) {
return (0, _utils.needsRecalculateColorDomain)(oldProps, props) || (0, _utils.needReCalculateScaleFunction)(oldProps, props) || (0, _utils.needsRecalculateRadiusRange)(oldProps, props) || oldProps.getColorValue !== props.getColorValue;
}
}, {
key: "processGeoJSON",
value: function processGeoJSON() {
var _this$props = this.props,
data = _this$props.data,
getPosition = _this$props.getPosition;
this.setState({
geoJSON: (0, _clusterUtils.getGeoJSON)(data, getPosition)
});
(0, _clusterUtils.clearClustererCache)();
}
}, {
key: "getClusters",
value: function getClusters() {
var geoJSON = this.state.geoJSON;
var clusterRadius = this.props.clusterRadius;
var _this$context = this.context,
viewport = _this$context.viewport,
_this$context$viewpor = _this$context.viewport,
longitude = _this$context$viewpor.longitude,
latitude = _this$context$viewpor.latitude,
height = _this$context$viewpor.height,
width = _this$context$viewpor.width; // zoom needs to be an integer for the different map utils. Also helps with cache key.
var zoom = Math.round(viewport.zoom);
var bbox = _geoViewport["default"].bounds([longitude, latitude], zoom, [width, height]);
var clusters = (0, _clusterUtils.clustersAtZoom)({
bbox: bbox,
clusterRadius: clusterRadius,
geoJSON: geoJSON,
zoom: zoom
});
this.setState({
clusters: clusters
});
}
}, {
key: "getColorValueDomain",
value: function getColorValueDomain() {
var _this$props2 = this.props,
colorScale = _this$props2.colorScale,
getColorValue = _this$props2.getColorValue,
getRadiusValue = _this$props2.getRadiusValue,
onSetColorDomain = _this$props2.onSetColorDomain;
var clusters = this.state.clusters;
var radiusDomain = [0, (0, _d3Array.max)(clusters, getRadiusValue)];
var colorValues = clusters.map(function (d) {
return getColorValue(d.properties.points);
});
var identity = function identity(d) {
return d;
};
var colorDomain = colorScale === _defaultSettings.SCALE_TYPES.ordinal ? (0, _dataScaleUtils.getOrdinalDomain)(colorValues, identity) : colorScale === _defaultSettings.SCALE_TYPES.quantile ? (0, _dataScaleUtils.getQuantileDomain)(colorValues, identity, _d3Array.ascending) : (0, _dataScaleUtils.getLinearDomain)(colorValues, identity);
this.setState({
colorDomain: colorDomain,
radiusDomain: radiusDomain
});
(0, _utils.getColorScaleFunction)(this);
(0, _utils.getRadiusScaleFunction)(this);
onSetColorDomain(colorDomain);
}
}, {
key: "getUpdateTriggers",
value: function getUpdateTriggers() {
return {
getColor: {
colorRange: this.props.colorRange,
colorDomain: this.props.colorDomain,
getColorValue: this.props.getColorValue,
colorScale: this.props.colorScale,
lowerPercentile: this.props.lowerPercentile,
upperPercentile: this.props.upperPercentile
},
getRadius: {
radiusRange: this.props.radiusRange,
radiusDomain: this.props.radiusDomain,
getRadiusValue: this.props.getRadiusValue
}
};
}
/*
* override default layer method to calculate cell color based on color scale function
*/
}, {
key: "_onGetSublayerColor",
value: function _onGetSublayerColor(cell) {
var getColorValue = this.props.getColorValue;
var _this$state = this.state,
colorScaleFunc = _this$state.colorScaleFunc,
colorDomain = _this$state.colorDomain;
var cv = getColorValue(cell.properties.points); // if cell value is outside domain, set alpha to 0
var color = cv >= colorDomain[0] && cv <= colorDomain[colorDomain.length - 1] ? colorScaleFunc(cv) : [0, 0, 0, 0]; // add final alpha to color
color[3] = Number.isFinite(color[3]) ? color[3] : 255;
return color;
}
}, {
key: "_onGetSublayerRadius",
value: function _onGetSublayerRadius(cell) {
var getRadiusValue = this.props.getRadiusValue;
var radiusScaleFunc = this.state.radiusScaleFunc;
return radiusScaleFunc(getRadiusValue(cell));
}
}, {
key: "getPickingInfo",
value: function getPickingInfo(_ref3) {
var info = _ref3.info;
var clusters = this.state.clusters;
var isPicked = info.picked && info.index > -1;
var object = null;
if (isPicked) {
// add cluster colorValue to object
var cluster = clusters[info.index];
var colorValue = this.props.getColorValue(cluster.properties.points);
object = _objectSpread({}, cluster.properties, {
colorValue: colorValue,
radius: this._onGetSublayerRadius(cluster),
position: cluster.geometry.coordinates
});
}
return _objectSpread({}, info, {
picked: Boolean(object),
// override object with picked cluster property
object: object
});
}
}, {
key: "renderLayers",
value: function renderLayers() {
// for subclassing, override this method to return
// customized sub layer props
var _this$props3 = this.props,
id = _this$props3.id,
radiusScale = _this$props3.radiusScale,
fp64 = _this$props3.fp64; // base layer props
var _this$props4 = this.props,
opacity = _this$props4.opacity,
pickable = _this$props4.pickable,
autoHighlight = _this$props4.autoHighlight,
highlightColor = _this$props4.highlightColor; // return props to the sublayer constructor
return new _deck.ScatterplotLayer({
id: "".concat(id, "-cluster"),
data: this.state.clusters,
radiusScale: radiusScale,
fp64: fp64,
opacity: opacity,
pickable: pickable,
autoHighlight: autoHighlight,
highlightColor: highlightColor,
getPosition: function getPosition(d) {
return d.geometry.coordinates;
},
getRadius: this._onGetSublayerRadius.bind(this),
getColor: this._onGetSublayerColor.bind(this),
updateTriggers: this.getUpdateTriggers()
});
}
}]);
return ClusterLayer;
}(_deck.CompositeLayer);
exports["default"] = ClusterLayer;
ClusterLayer.layerName = 'ClusterLayer';
ClusterLayer.defaultProps = defaultProps;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9kZWNrZ2wtbGF5ZXJzL2NsdXN0ZXItbGF5ZXIvY2x1c3Rlci1sYXllci5qcyJdLCJuYW1lcyI6WyJkZWZhdWx0UmFkaXVzIiwiTEFZRVJfVklTX0NPTkZJR1MiLCJjbHVzdGVyUmFkaXVzIiwiZGVmYXVsdFZhbHVlIiwiZGVmYXVsdFJhZGl1c1JhbmdlIiwiY2x1c3RlclJhZGl1c1JhbmdlIiwiZGVmYXVsdFByb3BzIiwiY29sb3JEb21haW4iLCJjb2xvclJhbmdlIiwiRGVmYXVsdENvbG9yUmFuZ2UiLCJjb2xvclNjYWxlIiwiU0NBTEVfVFlQRVMiLCJxdWFudGl6ZSIsInJhZGl1c1JhbmdlIiwibG93ZXJQZXJjZW50aWxlIiwidXBwZXJQZXJjZW50aWxlIiwiZ2V0UG9zaXRpb24iLCJ4IiwicG9zaXRpb24iLCJnZXRDb2xvclZhbHVlIiwicG9pbnRzIiwibGVuZ3RoIiwiZ2V0UmFkaXVzVmFsdWUiLCJjZWxsIiwicHJvcGVydGllcyIsInBvaW50X2NvdW50IiwiZnA2NCIsIkNsdXN0ZXJMYXllciIsInN0YXRlIiwiY2x1c3RlcnMiLCJnZW9KU09OIiwiY2hhbmdlRmxhZ3MiLCJzb21ldGhpbmdDaGFuZ2VkIiwiY29udGV4dCIsIm9sZFByb3BzIiwicHJvcHMiLCJkYXRhQ2hhbmdlZCIsInZpZXdwb3J0Q2hhbmdlZCIsIm5lZWRzUmVQcm9qZWN0UG9pbnRzIiwicHJvY2Vzc0dlb0pTT04iLCJnZXRDbHVzdGVycyIsImdldENvbG9yVmFsdWVEb21haW4iLCJuZWVkc1JlY2x1c3RlclBvaW50cyIsIm5lZWRzUmVjYWxjdWxhdGVTY2FsZUZ1bmN0aW9uIiwiTWF0aCIsInJvdW5kIiwiem9vbSIsImRhdGEiLCJzZXRTdGF0ZSIsInZpZXdwb3J0IiwibG9uZ2l0dWRlIiwibGF0aXR1ZGUiLCJoZWlnaHQiLCJ3aWR0aCIsImJib3giLCJnZW9WaWV3cG9ydCIsImJvdW5kcyIsIm9uU2V0Q29sb3JEb21haW4iLCJyYWRpdXNEb21haW4iLCJjb2xvclZhbHVlcyIsIm1hcCIsImQiLCJpZGVudGl0eSIsIm9yZGluYWwiLCJxdWFudGlsZSIsImFzY2VuZGluZyIsImdldENvbG9yIiwiZ2V0UmFkaXVzIiwiY29sb3JTY2FsZUZ1bmMiLCJjdiIsImNvbG9yIiwiTnVtYmVyIiwiaXNGaW5pdGUiLCJyYWRpdXNTY2FsZUZ1bmMiLCJpbmZvIiwiaXNQaWNrZWQiLCJwaWNrZWQiLCJpbmRleCIsIm9iamVjdCIsImNsdXN0ZXIiLCJjb2xvclZhbHVlIiwicmFkaXVzIiwiX29uR2V0U3VibGF5ZXJSYWRpdXMiLCJnZW9tZXRyeSIsImNvb3JkaW5hdGVzIiwiQm9vbGVhbiIsImlkIiwicmFkaXVzU2NhbGUiLCJvcGFjaXR5IiwicGlja2FibGUiLCJhdXRvSGlnaGxpZ2h0IiwiaGlnaGxpZ2h0Q29sb3IiLCJTY2F0dGVycGxvdExheWVyIiwiYmluZCIsIl9vbkdldFN1YmxheWVyQ29sb3IiLCJ1cGRhdGVUcmlnZ2VycyIsImdldFVwZGF0ZVRyaWdnZXJzIiwiQ29tcG9zaXRlTGF5ZXIiLCJsYXllck5hbWUiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQW9CQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFLQTs7QUFPQTs7QUFDQTs7QUFDQTs7QUFFQTs7Ozs7O0FBTUEsSUFBTUEsYUFBYSxHQUFHQyxnQ0FBa0JDLGFBQWxCLENBQWdDQyxZQUF0RDtBQUNBLElBQU1DLGtCQUFrQixHQUFHSCxnQ0FBa0JJLGtCQUFsQixDQUFxQ0YsWUFBaEU7QUFFQSxJQUFNRyxZQUFZLEdBQUc7QUFDbkJKLEVBQUFBLGFBQWEsRUFBRUYsYUFESTtBQUVuQk8sRUFBQUEsV0FBVyxFQUFFLElBRk07QUFHbkJDLEVBQUFBLFVBQVUsRUFBRUMsOEJBSE87QUFJbkJDLEVBQUFBLFVBQVUsRUFBRUMsNkJBQVlDLFFBSkw7QUFLbkJDLEVBQUFBLFdBQVcsRUFBRVQsa0JBTE07QUFPbkI7QUFDQVUsRUFBQUEsZUFBZSxFQUFFLENBUkU7QUFTbkJDLEVBQUFBLGVBQWUsRUFB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LFFBQUFBLEVBQUUsWUFBS0EsRUFBTCxhQUR3QjtBQUUxQnZDLFFBQUFBLElBQUksRUFBRSxLQUFLbkIsS0FBTCxDQUFXQyxRQUZTO0FBRzFCMEQsUUFBQUEsV0FBVyxFQUFYQSxXQUgwQjtBQUkxQjdELFFBQUFBLElBQUksRUFBSkEsSUFKMEI7QUFLMUI4RCxRQUFBQSxPQUFPLEVBQVBBLE9BTDBCO0FBTTFCQyxRQUFBQSxRQUFRLEVBQVJBLFFBTjBCO0FBTzFCQyxRQUFBQSxhQUFhLEVBQWJBLGFBUDBCO0FBUTFCQyxRQUFBQSxjQUFjLEVBQWRBLGNBUjBCO0FBUzFCM0UsUUFBQUEsV0FBVyxFQUFFLHFCQUFBNkMsQ0FBQztBQUFBLGlCQUFJQSxDQUFDLENBQUNzQixRQUFGLENBQVdDLFdBQWY7QUFBQSxTQVRZO0FBVTFCakIsUUFBQUEsU0FBUyxFQUFFLEtBQUtlLG9CQUFMLENBQTBCVyxJQUExQixDQUErQixJQUEvQixDQVZlO0FBVzFCM0IsUUFBQUEsUUFBUSxFQUFFLEtBQUs0QixtQkFBTCxDQUF5QkQsSUFBekIsQ0FBOEIsSUFBOUIsQ0FYZ0I7QUFZMUJFLFFBQUFBLGNBQWMsRUFBRSxLQUFLQyxpQkFBTDtBQVpVLE9BQXJCLENBQVA7QUFjRDs7O0VBN011Q0Msb0I7OztBQWdOMUN0RSxZQUFZLENBQUN1RSxTQUFiLEdBQXlCLGNBQXpCO0FBQ0F2RSxZQUFZLENBQUNyQixZQUFiLEdBQTRCQSxZQUE1QiIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAoYykgMjAxOSBVYmVyIFRlY2hub2xvZ2llcywgSW5jLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvIGRlYWxcbi8vIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHNcbi8vIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGxcbi8vIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcbi8vXG4vLyBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpblxuLy8gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEVcbi8vIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOXG4vLyBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCB7Q29tcG9zaXRlTGF5ZXIsIFNjYXR0ZXJwbG90TGF5ZXJ9IGZyb20gJ2RlY2suZ2wnO1xuaW1wb3J0IGdlb1ZpZXdwb3J0IGZyb20gJ0BtYXBib3gvZ2VvLXZpZXdwb3J0JztcbmltcG9ydCB7YXNjZW5kaW5nLCBtYXh9IGZyb20gJ2QzLWFycmF5JztcbmltcG9ydCB7XG4gIGdldFF1YW50aWxlRG9tYWluLFxuICBnZXRPcmRpbmFsRG9tYWluLFxuICBnZXRMaW5lYXJEb21haW5cbn0gZnJvbSAndXRpbHMvZGF0YS1zY2FsZS11dGlscyc7XG5pbXBvcnQge1xuICBnZXRDb2xvclNjYWxlRnVuY3Rpb24sXG4gIGdldFJhZGl1c1NjYWxlRnVuY3Rpb24sXG4gIG5lZWRzUmVjYWxjdWxhdGVSYWRpdXNSYW5nZSxcbiAgbmVlZHNSZWNhbGN1bGF0ZUNvbG9yRG9tYWluLFxuICBuZWVkUmVDYWxjdWxhdGVTY2FsZUZ1bmN0aW9uXG59IGZyb20gJy4uL2xheWVyLXV0aWxzL3V0aWxzJztcbmltcG9ydCB7RGVmYXVsdENvbG9yUmFuZ2V9IGZyb20gJ2NvbnN0YW50cy9jb2xvci1yYW5nZXMnO1xuaW1wb3J0IHtMQVlFUl9WSVNfQ09ORklHU30gZnJvbSAnbGF5ZXJzL2xheWVyLWZhY3RvcnknO1xuaW1wb3J0IHtTQ0FMRV9UWVBFU30gZnJvbSAnY29uc3RhbnRzL2RlZmF1bHQtc2V0dGluZ3MnO1xuXG5pbXBvcnQge1xuICBjbGVhckNsdXN0ZXJlckNhY2hlLFxuICBjbHVzdGVyc0F0Wm9vbSxcbiAgZ2V0R2VvSlNPTlxufSBmcm9tICcuLi9sYXllci11dGlscy9jbHVzdGVyLXV0aWxzJztcblxuY29uc3QgZGVmYXVsdFJhZGl1cyA9IExBWUVSX1ZJU19DT05GSUdTLmNsdXN0ZXJSYWRpdXMuZGVmYXVsdFZhbHVlO1xuY29uc3QgZGVmYXVsdFJhZGl1c1JhbmdlID0gTEFZRVJfVklTX0NPTkZJR1MuY2x1c3RlclJhZGl1c1JhbmdlLmRlZmF1bHRWYWx1ZTtcblxuY29uc3QgZGVmYXVsdFByb3BzID0ge1xuICBjbHVzdGVyUmFkaXVzOiBkZWZhdWx0UmFkaXVzLFxuICBjb2xvckRvbWFpbjogbnVsbCxcbiAgY29sb3JSYW5nZTogRGVmYXVsdENvbG9yUmFuZ2UsXG4gIGNvbG9yU2NhbGU6IFNDQUxFX1RZUEVTLnF1YW50aXplLFxuICByYWRpdXNSYW5nZTogZGVmYXVsdFJhZGl1c1JhbmdlLFxuXG4gIC8vIG1heWJlIGxhdGVyLi4uXG4gIGxvd2VyUGVyY2VudGlsZTogMCxcbiAgdXBwZXJQZXJjZW50aWxlOiAxMDAsXG5cbiAgZ2V0UG9zaXRpb246IHggPT4geC5wb3NpdGlvbixcblxuICAvLyBpZiB3YW50IHRvIGhhdmUgY29sb3IgYmFzZWQgb24gY3VzdG9taXplZCBhZ2dyZWdhdG9yLCBpbnN0ZWFkIG9mIGNvdW50XG4gIGdldENvbG9yVmFsdWU6IHBvaW50cyA9PiBwb2ludHMubGVuZ3RoLFxuXG4gIC8vICBpZiB3YW50IHRvIGhhdmUgcmFkaXVzIGJhc2VkIG9uIGN1c3RvbWl6ZWQgYWdncmVnYXRvciwgaW5zdGVhZCBvZiBjb3VudFxuICBnZXRSYWRpdXNWYWx1ZTogY2VsbCA9PiBjZWxsLnByb3BlcnRpZXMucG9pbnRfY291bnQsXG4gIGZwNjQ6IGZhbHNlXG59O1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBDbHVzdGVyTGF5ZXIgZXh0ZW5kcyBDb21wb3NpdGVMYXllciB7XG4gIGluaXRpYWxpemVTdGF0ZSgpIHtcbiAgICB0aGlzLnN0YXRlID0ge1xuICAgICAgY2x1c3RlcnM6IG51bGwsXG4gICAgICBnZW9KU09OOiBudWxsXG4gICAgfTtcbiAgfVxuXG4gIHNob3VsZFVwZGF0ZVN0YXRlKHtjaGFuZ2VGbGFnc30pIHtcbiAgICByZXR1cm4gY2hhbmdlRmxhZ3Muc29tZXRoaW5nQ2hhbmdlZDtcbiAgfVxuXG4gIHVwZGF0ZVN0YXRlKHtjb250ZXh0LCBvbGRQcm9wcywgcHJvcHMsIGNoYW5nZUZsYWdzfSkge1xuICAgIGlmIChcbiAgICAgIGNoYW5nZUZsYWdzLmRhdGFDaGFuZ2VkIHx8XG4gICAgICBjaGFuZ2VGbGFncy52aWV3cG9ydENoYW5nZWQgfHxcbiAgICAgIHRoaXMubmVlZHNSZVByb2plY3RQb2ludHMob2xkUHJvcHMsIHByb3BzKVxuICAgICkge1xuICAgICAgLy8gcHJvamVjdCBkYXRhIGludG8gY2x1c3RlcnMsIGFuZCBnZXQgY2x1c3RlcmVkIGRhdGFcbiAgICAgIHRoaXMucHJvY2Vzc0dlb0pTT04oKTtcbiAgICAgIHRoaXMuZ2V0Q2x1c3RlcnMoKTtcblxuICAgICAgLy8gdGhpcyBuZWVkcyBjbHVzdGVyZWQgZGF0YSB0byBiZSBzZXRcbiAgICAgIHRoaXMuZ2V0Q29sb3JWYWx1ZURvbWFpbigpO1xuICAgIH0gZWxzZSBpZiAodGhpcy5uZWVkc1JlY2x1c3RlclBvaW50cyhvbGRQcm9wcywgcHJvcHMpKSB7XG4gICAgICB0aGlzLmdldENsdXN0ZXJzKCk7XG4gICAgICB0aGlzLmdldENvbG9yVmFsdWVEb21haW4oKTtcbiAgICB9IGVsc2UgaWYgKHRoaXMubmVlZHNSZWNhbGN1bGF0ZVNjYWxlRnVuY3Rpb24ob2xkUHJvcHMsIHByb3BzKSkge1xuICAgICAgdGhpcy5nZXRDb2xvclZhbHVlRG9tYWluKCk7XG4gICAgfVxuICB9XG5cbiAgbmVlZHNSZVByb2plY3RQb2ludHMob2xkUHJvcHMsIHByb3BzKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIG9sZFByb3BzLmNsdXN0ZXJSYWRpdXMgIT09IHByb3BzLmNsdXN0ZXJSYWRpdXMgfHxcbiAgICAgIG9sZFByb3BzLmdldFBvc2l0aW9uICE9PSBwcm9wcy5nZXRQb3NpdGlvblxuICAgICk7XG4gIH1cblxuICBuZWVkc1JlY2x1c3RlclBvaW50cyhvbGRQcm9wcywgcHJvcHMpIHtcbiAgICByZXR1cm4gTWF0aC5yb3VuZChvbGRQcm9wcy56b29tKSAhPT0gTWF0aC5yb3VuZChwcm9wcy56b29tKTtcbiAgfVxuXG4gIG5lZWRzUmVjYWxjdWxhdGVTY2FsZUZ1bmN0aW9uKG9sZFByb3BzLCBwcm9wcykge1xuICAgIHJldHVybiAoXG4gICAgICBuZWVkc1JlY2FsY3VsYXRlQ29sb3JEb21haW4ob2xkUHJvcHMsIHByb3BzKSB8fFxuICAgICAgbmVlZFJlQ2FsY3VsYXRlU2NhbGVGdW5jdGlvbihvbGRQcm9wcywgcHJvcHMpIHx8XG4gICAgICBuZWVkc1JlY2FsY3VsYXRlUmFkaXVzUmFuZ2Uob2xkUHJvcHMsIHByb3BzKSB8fFxuICAgICAgb2xkUHJvcHMuZ2V0Q29sb3JWYWx1ZSAhPT0gcHJvcHMuZ2V0Q29sb3JWYWx1ZVxuICAgICk7XG4gIH1cblxuICBwcm9jZXNzR2VvSlNPTigpIHtcbiAgICBjb25zdCB7ZGF0YSwgZ2V0UG9zaXRpb259ID0gdGhpcy5wcm9wcztcbiAgICB0aGlzLnNldFN0YXRlKHtnZW9KU09OOiBnZXRHZW9KU09OKGRhdGEsIGdldFBvc2l0aW9uKX0pO1xuICAgIGNsZWFyQ2x1c3RlcmVyQ2FjaGUoKTtcbiAgfVxuXG4gIGdldENsdXN0ZXJzKCkge1xuICAgIGNvbnN0IHtnZW9KU09OfSA9IHRoaXMuc3RhdGU7XG4gICAgY29uc3Qge2NsdXN0ZXJSYWRpdXN9ID0gdGhpcy5wcm9wcztcbiAgICBjb25zdCB7XG4gICAgICB2aWV3cG9ydCxcbiAgICAgIHZpZXdwb3J0OiB7bG9uZ2l0dWRlLCBsYXRpdHVkZSwgaGVpZ2h0LCB3aWR0aH1cbiAgICB9ID0gdGhpcy5jb250ZXh0O1xuXG4gICAgLy8gem9vbSBuZWVkcyB0byBiZSBhbiBpbnRlZ2VyIGZvciB0aGUgZGlmZmVyZW50IG1hcCB1dGlscy4gQWxzbyBoZWxwcyB3aXRoIGNhY2hlIGtleS5cbiAgICBjb25zdCB6b29tID0gTWF0aC5yb3VuZCh2aWV3cG9ydC56b29tKTtcbiAgICBjb25zdCBiYm94ID0gZ2VvVmlld3BvcnQuYm91bmRzKFtsb25naXR1ZGUsIGxhdGl0dWRlXSwgem9vbSwgW1xuICAgICAgd2lkdGgsXG4gICAgICBoZWlnaHRcbiAgICBdKTtcblxuICAgIGNvbnN0IGNsdXN0ZXJzID0gY2x1c3RlcnNBdFpvb20oe2Jib3gsIGNsdXN0ZXJSYWRpdXMsIGdlb0pTT04sIHpvb219KTtcblxuICAgIHRoaXMuc2V0U3RhdGUoe2NsdXN0ZXJzfSk7XG4gIH1cblxuICBnZXRDb2xvclZhbHVlRG9tYWluKCkge1xuICAgIGNvbnN0IHtcbiAgICAgIGNvbG9yU2NhbGUsXG4gICAgICBnZXRDb2xvclZhbHVlLFxuICAgICAgZ2V0UmFkaXVzVmFsdWUsXG4gICAgICBvblNldENvbG9yRG9tYWluXG4gICAgfSA9IHRoaXMucHJvcHM7XG4gICAgY29uc3Qge2NsdXN0ZXJzfSA9IHRoaXMuc3RhdGU7XG5cbiAgICBjb25zdCByYWRpdXNEb21haW4gPSBbMCwgbWF4KGNsdXN0ZXJzLCBnZXRSYWRpdXNWYWx1ZSldO1xuXG4gICAgY29uc3QgY29sb3JWYWx1ZXMgPSBjbHVzdGVycy5tYXAoZCA9PiBnZXRDb2xvclZhbHVlKGQucHJvcGVydGllcy5wb2ludHMpKTtcblxuICAgIGNvbnN0IGlkZW50aXR5ID0gZCA9PiBkO1xuXG4gICAgY29uc3QgY29sb3JEb21haW4gPVxuICAgICAgY29sb3JTY2FsZSA9PT0gU0NBTEVfVFlQRVMub3JkaW5hbFxuICAgICAgICA/IGdldE9yZGluYWxEb21haW4oY29sb3JWYWx1ZXMsIGlkZW50aXR5KVxuICAgICAgICA6IGNvbG9yU2NhbGUgPT09IFNDQUxFX1RZUEVTLnF1YW50aWxlXG4gICAgICAgID8gZ2V0UXVhbnRpbGVEb21haW4oY29sb3JWYWx1ZXMsIGlkZW50aXR5LCBhc2NlbmRpbmcpXG4gICAgICAgIDogZ2V0TGluZWFyRG9tYWluKGNvbG9yVmFsdWVzLCBpZGVudGl0eSk7XG5cbiAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgIGNvbG9yRG9tYWluLFxuICAgICAgcmFkaXVzRG9tYWluXG4gICAgfSk7XG5cbiAgICBnZXRDb2xvclNjYWxlRnVuY3Rpb24odGhpcyk7XG4gICAgZ2V0UmFkaXVzU2NhbGVGdW5jdGlvbih0aGlzKTtcblxuICAgIG9uU2V0Q29sb3JEb21haW4oY29sb3JEb21haW4pO1xuICB9XG5cbiAgZ2V0VXBkYXRlVHJpZ2dlcnMoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGdldENvbG9yOiB7XG4gICAgICAgIGNvbG9yUmFuZ2U6IHRoaXMucHJvcHMuY29sb3JSYW5nZSxcbiAgICAgICAgY29sb3JEb21haW46IHRoaXMucHJvcHMuY29sb3JEb21haW4sXG4gICAgICAgIGdldENvbG9yVmFsdWU6IHRoaXMucHJvcHMuZ2V0Q29sb3JWYWx1ZSxcbiAgICAgICAgY29sb3JTY2FsZTogdGhpcy5wcm9wcy5jb2xvclNjYWxlLFxuICAgICAgICBsb3dlclBlcmNlbnRpbGU6IHRoaXMucHJvcHMubG93ZXJQZXJjZW50aWxlLFxuICAgICAgICB1cHBlclBlcmNlbnRpbGU6IHRoaXMucHJvcHMudXBwZXJQZXJjZW50aWxlXG4gICAgICB9LFxuICAgICAgZ2V0UmFkaXVzOiB7XG4gICAgICAgIHJhZGl1c1JhbmdlOiB0aGlzLnByb3BzLnJhZGl1c1JhbmdlLFxuICAgICAgICByYWRpdXNEb21haW46IHRoaXMucHJvcHMucmFkaXVzRG9tYWluLFxuICAgICAgICBnZXRSYWRpdXNWYWx1ZTogdGhpcy5wcm9wcy5nZXRSYWRpdXNWYWx1ZVxuICAgICAgfVxuICAgIH07XG4gIH1cblxuICAvKlxuICAgKiBvdmVycmlkZSBkZWZhdWx0IGxheWVyIG1ldGhvZCB0byBjYWxjdWxhdGUgY2VsbCBjb2xvciBiYXNlZCBvbiBjb2xvciBzY2FsZSBmdW5jdGlvblxuICAgKi9cbiAgX29uR2V0U3VibGF5ZXJDb2xvcihjZWxsKSB7XG4gICAgY29uc3Qge2dldENvbG9yVmFsdWV9ID0gdGhpcy5wcm9wcztcbiAgICBjb25zdCB7Y29sb3JTY2FsZUZ1bmMsIGNvbG9yRG9tYWlufSA9IHRoaXMuc3RhdGU7XG5cbiAgICBjb25zdCBjdiA9IGdldENvbG9yVmFsdWUoY2VsbC5wcm9wZXJ0aWVzLnBvaW50cyk7XG5cbiAgICAvLyBpZiBjZWxsIHZhbHVlIGlzIG91dHNpZGUgZG9tYWluLCBzZXQgYWxwaGEgdG8gMFxuICAgIGNvbnN0IGNvbG9yID1cbiAgICAgIGN2ID49IGNvbG9yRG9tYWluWzBdICYmIGN2IDw9IGNvbG9yRG9tYWluW2NvbG9yRG9tYWluLmxlbmd0aCAtIDFdXG4gICAgICAgID8gY29sb3JTY2FsZUZ1bmMoY3YpXG4gICAgICAgIDogWzAsIDAsIDAsIDBdO1xuXG4gICAgLy8gYWRkIGZpbmFsIGFscGhhIHRvIGNvbG9yXG4gICAgY29sb3JbM10gPSBOdW1iZXIuaXNGaW5pdGUoY29sb3JbM10pID8gY29sb3JbM10gOiAyNTU7XG5cbiAgICByZXR1cm4gY29sb3I7XG4gIH1cblxuICBfb25HZXRTdWJsYXllclJhZGl1cyhjZWxsKSB7XG4gICAgY29uc3Qge2dldFJhZGl1c1ZhbHVlfSA9IHRoaXMucHJvcHM7XG4gICAgY29uc3Qge3JhZGl1c1NjYWxlRnVuY30gPSB0aGlzLnN0YXRlO1xuICAgIHJldHVybiByYWRpdXNTY2FsZUZ1bmMoZ2V0UmFkaXVzVmFsdWUoY2VsbCkpO1xuICB9XG5cbiAgZ2V0UGlja2luZ0luZm8oe2luZm99KSB7XG4gICAgY29uc3Qge2NsdXN0ZXJzfSA9IHRoaXMuc3RhdGU7XG4gICAgY29uc3QgaXNQaWNrZWQgPSBpbmZvLnBpY2tlZCAmJiBpbmZvLmluZGV4ID4gLTE7XG5cbiAgICBsZXQgb2JqZWN0ID0gbnVsbDtcbiAgICBpZiAoaXNQaWNrZWQpIHtcbiAgICAgIC8vIGFkZCBjbHVzdGVyIGNvbG9yVmFsdWUgdG8gb2JqZWN0XG4gICAgICBjb25zdCBjbHVzdGVyID0gY2x1c3RlcnNbaW5mby5pbmRleF07XG4gICAgICBjb25zdCBjb2xvclZhbHVlID0gdGhpcy5wcm9wcy5nZXRDb2xvclZhbHVlKGNsdXN0ZXIucHJvcGVydGllcy5wb2ludHMpO1xuXG4gICAgICBvYmplY3QgPSB7XG4gICAgICAgIC4uLmNsdXN0ZXIucHJvcGVydGllcyxcbiAgICAgICAgY29sb3JWYWx1ZSxcbiAgICAgICAgcmFkaXVzOiB0aGlzLl9vbkdldFN1YmxheWVyUmFkaXVzKGNsdXN0ZXIpLFxuICAgICAgICBwb3NpdGlvbjogY2x1c3Rlci5nZW9tZXRyeS5jb29yZGluYXRlc1xuICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgLi4uaW5mbyxcbiAgICAgIHBpY2tlZDogQm9vbGVhbihvYmplY3QpLFxuICAgICAgLy8gb3ZlcnJpZGUgb2JqZWN0IHdpdGggcGlja2VkIGNsdXN0ZXIgcHJvcGVydHlcbiAgICAgIG9iamVjdFxuICAgIH07XG4gIH1cblxuICByZW5kZXJMYXllcnMoKSB7XG4gICAgLy8gZm9yIHN1YmNsYXNzaW5nLCBvdmVycmlkZSB0aGlzIG1ldGhvZCB0byByZXR1cm5cbiAgICAvLyBjdXN0b21pemVkIHN1YiBsYXllciBwcm9wc1xuICAgIGNvbnN0IHtpZCwgcmFkaXVzU2NhbGUsIGZwNjR9ID0gdGhpcy5wcm9wcztcblxuICAgIC8vIGJhc2UgbGF5ZXIgcHJvcHNcbiAgICBjb25zdCB7b3BhY2l0eSwgcGlja2FibGUsIGF1dG9IaWdobGlnaHQsIGhpZ2hsaWdodENvbG9yfSA9IHRoaXMucHJvcHM7XG5cbiAgICAvLyByZXR1cm4gcHJvcHMgdG8gdGhlIHN1YmxheWVyIGNvbnN0cnVjdG9yXG4gICAgcmV0dXJuIG5ldyBTY2F0dGVycGxvdExheWVyKHtcbiAgICAgIGlkOiBgJHtpZH0tY2x1c3RlcmAsXG4gICAgICBkYXRhOiB0aGlzLnN0YXRlLmNsdXN0ZXJzLFxuICAgICAgcmFkaXVzU2NhbGUsXG4gICAgICBmcDY0LFxuICAgICAgb3BhY2l0eSxcbiAgICAgIHBpY2thYmxlLFxuICAgICAgYXV0b0hpZ2hsaWdodCxcbiAgICAgIGhpZ2hsaWdodENvbG9yLFxuICAgICAgZ2V0UG9zaXRpb246IGQgPT4gZC5nZW9tZXRyeS5jb29yZGluYXRlcyxcbiAgICAgIGdldFJhZGl1czogdGhpcy5fb25HZXRTdWJsYXllclJhZGl1cy5iaW5kKHRoaXMpLFxuICAgICAgZ2V0Q29sb3I6IHRoaXMuX29uR2V0U3VibGF5ZXJDb2xvci5iaW5kKHRoaXMpLFxuICAgICAgdXBkYXRlVHJpZ2dlcnM6IHRoaXMuZ2V0VXBkYXRlVHJpZ2dlcnMoKVxuICAgIH0pO1xuICB9XG59XG5cbkNsdXN0ZXJMYXllci5sYXllck5hbWUgPSAnQ2x1c3RlckxheWVyJztcbkNsdXN0ZXJMYXllci5kZWZhdWx0UHJvcHMgPSBkZWZhdWx0UHJvcHM7XG4iXX0=