kepler.gl.geoiq
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
300 lines (256 loc) • 32.4 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.pointPosResolver = exports.pointPosAccessor = exports.getValueAggr = exports["default"] = exports.aggregateRequiredColumns = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _get2 = _interopRequireDefault(require("@babel/runtime/helpers/get"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
var _lodash = _interopRequireDefault(require("lodash.memoize"));
var _baseLayer = _interopRequireDefault(require("./base-layer"));
var _colorUtils = require("../utils/color-utils");
var _aggregateUtils = require("../utils/aggregate-utils");
var _defaultSettings = require("../constants/default-settings");
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; }
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
var pointPosAccessor = exports.pointPosAccessor = function pointPosAccessor(_ref) {
var lat = _ref.lat,
lng = _ref.lng;
return function (d) {
return [d[lng.fieldIdx], d[lat.fieldIdx]];
};
};
var pointPosResolver = exports.pointPosResolver = function pointPosResolver(_ref2) {
var lat = _ref2.lat,
lng = _ref2.lng;
return "".concat(lat.fieldIdx, "-").concat(lng.fieldIdx);
};
var getValueAggr = exports.getValueAggr = function getValueAggr(field, aggregation) {
return function (points) {
return (0, _aggregateUtils.aggregate)(points.map(function (p) {
return p[field.tableFieldIndex - 1];
}), aggregation);
};
};
var aggrResolver = function aggrResolver(field, aggregation) {
return "".concat(field.name, "-").concat(aggregation);
};
var getLayerColorRange = function getLayerColorRange(colorRange) {
return colorRange.colors.map(_colorUtils.hexToRgb);
};
var aggregateRequiredColumns = exports.aggregateRequiredColumns = ['lat', 'lng'];
var AggregationLayer = exports["default"] = /*#__PURE__*/function (_Layer) {
(0, _inherits2["default"])(AggregationLayer, _Layer);
var _super = _createSuper(AggregationLayer);
function AggregationLayer(props) {
var _this;
(0, _classCallCheck2["default"])(this, AggregationLayer);
_this = _super.call(this, props);
_this.getPosition = (0, _lodash["default"])(pointPosAccessor, pointPosResolver);
_this.getColorValue = (0, _lodash["default"])(getValueAggr, aggrResolver);
_this.getColorRange = (0, _lodash["default"])(getLayerColorRange);
_this.getElevationValue = (0, _lodash["default"])(getValueAggr, aggrResolver);
return _this;
}
(0, _createClass2["default"])(AggregationLayer, [{
key: "isAggregated",
get: function get() {
return true;
}
}, {
key: "requiredLayerColumns",
get: function get() {
return aggregateRequiredColumns;
}
}, {
key: "columnPairs",
get: function get() {
return this.defaultPointColumnPairs;
}
}, {
key: "noneLayerDataAffectingProps",
get: function get() {
return [].concat((0, _toConsumableArray2["default"])((0, _get2["default"])((0, _getPrototypeOf2["default"])(AggregationLayer.prototype), "noneLayerDataAffectingProps", this)), ['enable3d', 'colorRange', 'colorScale', 'colorDomain', 'sizeRange', 'sizeScale', 'sizeDomain', 'percentile', 'coverage', 'elevationPercentile', 'elevationScale']);
}
}, {
key: "visualChannels",
get: function get() {
return {
color: {
aggregation: 'colorAggregation',
channelScaleType: _defaultSettings.CHANNEL_SCALES.colorAggr,
defaultMeasure: 'Point Count',
domain: 'colorDomain',
field: 'colorField',
key: 'color',
property: 'color',
range: 'colorRange',
scale: 'colorScale'
},
size: {
aggregation: 'sizeAggregation',
channelScaleType: _defaultSettings.CHANNEL_SCALES.sizeAggr,
condition: function condition(config) {
return config.visConfig.enable3d;
},
defaultMeasure: 'Point Count',
domain: 'sizeDomain',
field: 'sizeField',
key: 'size',
property: 'height',
range: 'sizeRange',
scale: 'sizeScale'
}
};
}
/**
* Get the description of a visualChannel config
* @param key
* @returns {{label: string, measure: (string|string)}}
*/
}, {
key: "getVisualChannelDescription",
value: function getVisualChannelDescription(key) {
// e.g. label: Color, measure: Average of ETA
// console.log('inside getVisualChannelDescription', key);
var _this$visualChannels$ = this.visualChannels[key],
range = _this$visualChannels$.range,
field = _this$visualChannels$.field,
defaultMeasure = _this$visualChannels$.defaultMeasure,
aggregation = _this$visualChannels$.aggregation;
return {
label: this.visConfigSettings[range].label,
measure: this.config[field] ? "".concat(this.config.visConfig[aggregation], " of ").concat(this.config[field].name) : defaultMeasure
};
}
}, {
key: "getHoverData",
value: function getHoverData(object) {
// return aggregated object
return object;
}
/**
* Aggregation layer handles visual channel aggregation inside deck.gl layer
*/
}, {
key: "updateLayerVisualChannel",
value: function updateLayerVisualChannel(_ref3, channel) {
var data = _ref3.data,
allData = _ref3.allData;
this.validateVisualChannel(channel);
}
/**
* Validate aggregation type on top of basic layer visual channel validation
* @param channel
*/
}, {
key: "validateVisualChannel",
value: function validateVisualChannel(channel) {
// field type decides aggregation type decides scale type
this.validateFieldType(channel);
this.validateAggregationType(channel);
this.validateScale(channel);
}
/**
* Validate aggregation type based on selected field
*/
}, {
key: "validateAggregationType",
value: function validateAggregationType(channel) {
var visualChannel = this.visualChannels[channel];
var field = visualChannel.field,
aggregation = visualChannel.aggregation;
var aggregationOptions = this.getAggregationOptions(channel);
if (!aggregation) {
return;
}
if (!aggregationOptions.length) {
// if field cannot be aggregated, set field to null
this.updateLayerConfig((0, _defineProperty2["default"])({}, field, null));
} else if (!aggregationOptions.includes(this.config.visConfig[aggregation])) {
// current aggregation type is not supported by this field
// set aggregation to the first supported option
this.updateLayerVisConfig((0, _defineProperty2["default"])({}, aggregation, aggregationOptions[0]));
}
}
}, {
key: "getAggregationOptions",
value: function getAggregationOptions(channel) {
var visualChannel = this.visualChannels[channel];
var field = visualChannel.field,
channelScaleType = visualChannel.channelScaleType; // console.log("field and channelScaleType",field, channelScaleType )
return Object.keys(this.config[field] ? _defaultSettings.FIELD_OPTS[this.config[field].type].scale[channelScaleType] : _defaultSettings.DEFAULT_AGGREGATION[channelScaleType]);
}
/**
* Get scale options based on current field and aggregation type
* @param {string} channel
* @returns {string[]}
*/
}, {
key: "getScaleOptions",
value: function getScaleOptions(channel) {
var visualChannel = this.visualChannels[channel];
var field = visualChannel.field,
aggregation = visualChannel.aggregation,
channelScaleType = visualChannel.channelScaleType;
var aggregationType = this.config.visConfig[aggregation];
return this.config[field] ? // scale options based on aggregation
_defaultSettings.FIELD_OPTS[this.config[field].type].scale[channelScaleType][aggregationType] : // default scale options for point count
_defaultSettings.DEFAULT_AGGREGATION[channelScaleType][aggregationType];
}
/**
* Aggregation layer handles visual channel aggregation inside deck.gl layer
*/
}, {
key: "updateLayerDomain",
value: function updateLayerDomain(dataset, newFilter) {
return this;
}
}, {
key: "updateLayerMeta",
value: function updateLayerMeta(allData, getPosition) {
// get bounds from points
var bounds = this.getPointsBounds(allData, getPosition);
this.updateMeta({
bounds: bounds
});
}
}, {
key: "formatLayerData",
value: function formatLayerData(_, allData, filteredIndex, oldLayerData) {
var opt = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
var getPosition = this.getPosition(this.config.columns);
if (!oldLayerData || oldLayerData.getPosition !== getPosition) {
this.updateLayerMeta(allData, getPosition);
}
var getColorValue = this.config.colorField ? this.getColorValue(this.config.colorField, this.config.visConfig.colorAggregation) : undefined; // console.log('getColorValue inside aggregation Layer', getColorValue);
var getElevationValue = this.config.sizeField ? this.getElevationValue(this.config.sizeField, this.config.visConfig.sizeAggregation) : undefined;
var data;
if (oldLayerData && oldLayerData.data && opt.sameData && oldLayerData.getPosition === getPosition) {
data = oldLayerData.data;
} else {
data = filteredIndex.map(function (i) {
return allData[i];
});
}
return _objectSpread(_objectSpread({
data: data,
getPosition: getPosition
}, getColorValue ? {
getColorValue: getColorValue
} : {}), getElevationValue ? {
getElevationValue: getElevationValue
} : {});
}
}]);
return AggregationLayer;
}(_baseLayer["default"]);
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9sYXllcnMvYWdncmVnYXRpb24tbGF5ZXIuanMiXSwibmFtZXMiOlsicG9pbnRQb3NBY2Nlc3NvciIsImxhdCIsImxuZyIsImQiLCJmaWVsZElkeCIsInBvaW50UG9zUmVzb2x2ZXIiLCJnZXRWYWx1ZUFnZ3IiLCJmaWVsZCIsImFnZ3JlZ2F0aW9uIiwicG9pbnRzIiwibWFwIiwicCIsInRhYmxlRmllbGRJbmRleCIsImFnZ3JSZXNvbHZlciIsIm5hbWUiLCJnZXRMYXllckNvbG9yUmFuZ2UiLCJjb2xvclJhbmdlIiwiY29sb3JzIiwiaGV4VG9SZ2IiLCJhZ2dyZWdhdGVSZXF1aXJlZENvbHVtbnMiLCJBZ2dyZWdhdGlvbkxheWVyIiwicHJvcHMiLCJnZXRQb3NpdGlvbiIsImdldENvbG9yVmFsdWUiLCJnZXRDb2xvclJhbmdlIiwiZ2V0RWxldmF0aW9uVmFsdWUiLCJkZWZhdWx0UG9pbnRDb2x1bW5QYWlycyIsImNvbG9yIiwiY2hhbm5lbFNjYWxlVHlwZSIsIkNIQU5ORUxfU0NBTEVTIiwiY29sb3JBZ2dyIiwiZGVmYXVsdE1lYXN1cmUiLCJkb21haW4iLCJrZXkiLCJwcm9wZXJ0eSIsInJhbmdlIiwic2NhbGUiLCJzaXplIiwic2l6ZUFnZ3IiLCJjb25kaXRpb24iLCJjb25maWciLCJ2aXNDb25maWciLCJlbmFibGUzZCIsInZpc3VhbENoYW5uZWxzIiwibGFiZWwiLCJ2aXNDb25maWdTZXR0aW5ncyIsIm1lYXN1cmUiLCJvYmplY3QiLCJjaGFubmVsIiwiZGF0YSIsImFsbERhdGEiLCJ2YWxpZGF0ZVZpc3VhbENoYW5uZWwiLCJ2YWxpZGF0ZUZpZWxkVHlwZSIsInZhbGlkYXRlQWdncmVnYXRpb25UeXBlIiwidmFsaWRhdGVTY2FsZSIsInZpc3VhbENoYW5uZWwiLCJhZ2dyZWdhdGlvbk9wdGlvbnMiLCJnZXRBZ2dyZWdhdGlvbk9wdGlvbnMiLCJsZW5ndGgiLCJ1cGRhdGVMYXllckNvbmZpZyIsImluY2x1ZGVzIiwidXBkYXRlTGF5ZXJWaXNDb25maWciLCJPYmplY3QiLCJrZXlzIiwiRklFTERfT1BUUyIsInR5cGUiLCJERUZBVUxUX0FHR1JFR0FUSU9OIiwiYWdncmVnYXRpb25UeXBlIiwiZGF0YXNldCIsIm5ld0ZpbHRlciIsImJvdW5kcyIsImdldFBvaW50c0JvdW5kcyIsInVwZGF0ZU1ldGEiLCJfIiwiZmlsdGVyZWRJbmRleCIsIm9sZExheWVyRGF0YSIsIm9wdCIsImNvbHVtbnMiLCJ1cGRhdGVMYXllck1ldGEiLCJjb2xvckZpZWxkIiwiY29sb3JBZ2dyZWdhdGlvbiIsInVuZGVmaW5lZCIsInNpemVGaWVsZCIsInNpemVBZ2dyZWdhdGlvbiIsInNhbWVEYXRhIiwiaSIsIkxheWVyIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBb0JBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOzs7Ozs7Ozs7O0FBTU8sSUFBTUEsZ0JBQWdCLDhCQUFHLFNBQW5CQSxnQkFBbUI7QUFBQSxNQUFFQyxHQUFGLFFBQUVBLEdBQUY7QUFBQSxNQUFPQyxHQUFQLFFBQU9BLEdBQVA7QUFBQSxTQUFnQixVQUFBQyxDQUFDO0FBQUEsV0FBSSxDQUNuREEsQ0FBQyxDQUFDRCxHQUFHLENBQUNFLFFBQUwsQ0FEa0QsRUFFbkRELENBQUMsQ0FBQ0YsR0FBRyxDQUFDRyxRQUFMLENBRmtELENBQUo7QUFBQSxHQUFqQjtBQUFBLENBQXpCOztBQUtBLElBQU1DLGdCQUFnQiw4QkFBRyxTQUFuQkEsZ0JBQW1CO0FBQUEsTUFBRUosR0FBRixTQUFFQSxHQUFGO0FBQUEsTUFBT0MsR0FBUCxTQUFPQSxHQUFQO0FBQUEsbUJBQzNCRCxHQUFHLENBQUNHLFFBRHVCLGNBQ1hGLEdBQUcsQ0FBQ0UsUUFETztBQUFBLENBQXpCOztBQUdBLElBQU1FLFlBQVksMEJBQUcsU0FBZkEsWUFBZSxDQUFDQyxLQUFELEVBQVFDLFdBQVI7QUFBQSxTQUF3QixVQUFBQyxNQUFNO0FBQUEsV0FDeEQsK0JBQVVBLE1BQU0sQ0FBQ0MsR0FBUCxDQUFXLFVB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TCxDQUFZMEMsU0FBWixHQUN0QixLQUFLekQsaUJBQUwsQ0FDRSxLQUFLZSxNQUFMLENBQVkwQyxTQURkLEVBRUUsS0FBSzFDLE1BQUwsQ0FBWUMsU0FBWixDQUFzQjBDLGVBRnhCLENBRHNCLEdBS3RCRixTQUxKO0FBT0EsVUFBSWhDLElBQUo7O0FBQ0EsVUFDRTBCLFlBQVksSUFDWkEsWUFBWSxDQUFDMUIsSUFEYixJQUVBMkIsR0FBRyxDQUFDUSxRQUZKLElBR0FULFlBQVksQ0FBQ3JELFdBQWIsS0FBNkJBLFdBSi9CLEVBS0U7QUFDQTJCLFFBQUFBLElBQUksR0FBRzBCLFlBQVksQ0FBQzFCLElBQXBCO0FBQ0QsT0FQRCxNQU9PO0FBQ0xBLFFBQUFBLElBQUksR0FBR3lCLGFBQWEsQ0FBQ2hFLEdBQWQsQ0FBa0IsVUFBQTJFLENBQUM7QUFBQSxpQkFBSW5DLE9BQU8sQ0FBQ21DLENBQUQsQ0FBWDtBQUFBLFNBQW5CLENBQVA7QUFDRDs7QUFFRDtBQUNFcEMsUUFBQUEsSUFBSSxFQUFKQSxJQURGO0FBRUUzQixRQUFBQSxXQUFXLEVBQVhBO0FBRkYsU0FHTUMsYUFBYSxHQUFHO0FBQUNBLFFBQUFBLGFBQWEsRUFBYkE7QUFBRCxPQUFILEdBQXFCLEVBSHhDLEdBSU1FLGlCQUFpQixHQUFHO0FBQUNBLFFBQUFBLGlCQUFpQixFQUFqQkE7QUFBRCxPQUFILEdBQXlCLEVBSmhEO0FBTUQ7OztFQXhOMkM2RCxxQiIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAoYykgMjAyMyBVYmVyIFRlY2hub2xvZ2llcywgSW5jLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvIGRlYWxcbi8vIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHNcbi8vIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGxcbi8vIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcbi8vXG4vLyBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpblxuLy8gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEVcbi8vIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOXG4vLyBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCBtZW1vaXplIGZyb20gJ2xvZGFzaC5tZW1vaXplJztcbmltcG9ydCBMYXllciBmcm9tICcuL2Jhc2UtbGF5ZXInO1xuaW1wb3J0IHtoZXhUb1JnYn0gZnJvbSAndXRpbHMvY29sb3ItdXRpbHMnO1xuaW1wb3J0IHthZ2dyZWdhdGV9IGZyb20gJ3V0aWxzL2FnZ3JlZ2F0ZS11dGlscyc7XG5pbXBvcnQge1xuICBDSEFOTkVMX1NDQUxFUyxcbiAgRklFTERfT1BUUyxcbiAgREVGQVVMVF9BR0dSRUdBVElPTlxufSBmcm9tICdjb25zdGFudHMvZGVmYXVsdC1zZXR0aW5ncyc7XG5cbmV4cG9ydCBjb25zdCBwb2ludFBvc0FjY2Vzc29yID0gKHtsYXQsIGxuZ30pID0+IGQgPT4gW1xuICBkW2xuZy5maWVsZElkeF0sXG4gIGRbbGF0LmZpZWxkSWR4XVxuXTtcblxuZXhwb3J0IGNvbnN0IHBvaW50UG9zUmVzb2x2ZXIgPSAoe2xhdCwgbG5nfSkgPT5cbiAgYCR7bGF0LmZpZWxkSWR4fS0ke2xuZy5maWVsZElkeH1gO1xuXG5leHBvcnQgY29uc3QgZ2V0VmFsdWVBZ2dyID0gKGZpZWxkLCBhZ2dyZWdhdGlvbikgPT4gcG9pbnRzID0+XG4gIGFnZ3JlZ2F0ZShwb2ludHMubWFwKHAgPT4gcFtmaWVsZC50YWJsZUZpZWxkSW5kZXggLSAxXSksIGFnZ3JlZ2F0aW9uKTtcblxuY29uc3QgYWdnclJlc29sdmVyID0gKGZpZWxkLCBhZ2dyZWdhdGlvbikgPT4gYCR7ZmllbGQubmFtZX0tJHthZ2dyZWdhdGlvbn1gO1xuXG5jb25zdCBnZXRMYXllckNvbG9yUmFuZ2UgPSBjb2xvclJhbmdlID0+IGNvbG9yUmFuZ2UuY29sb3JzLm1hcChoZXhUb1JnYik7XG5cbmV4cG9ydCBjb25zdCBhZ2dyZWdhdGVSZXF1aXJlZENvbHVtbnMgPSBbJ2xhdCcsICdsbmcnXTtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQWdncmVnYXRpb25MYXllciBleHRlbmRzIExheWVyIHtcbiAgY29uc3RydWN0b3IocHJvcHMpIHtcbiAgICBzdXBlcihwcm9wcyk7XG5cbiAgICB0aGlzLmdldFBvc2l0aW9uID0gbWVtb2l6ZShwb2ludFBvc0FjY2Vzc29yLCBwb2ludFBvc1Jlc29sdmVyKTtcbiAgICB0aGlzLmdldENvbG9yVmFsdWUgPSBtZW1vaXplKGdldFZhbHVlQWdnciwgYWdnclJlc29sdmVyKTtcbiAgICB0aGlzLmdldENvbG9yUmFuZ2UgPSBtZW1vaXplKGdldExheWVyQ29sb3JSYW5nZSk7XG4gICAgdGhpcy5nZXRFbGV2YXRpb25WYWx1ZSA9IG1lbW9pemUoZ2V0VmFsdWVBZ2dyLCBhZ2dyUmVzb2x2ZXIpO1xuICB9XG5cbiAgZ2V0IGlzQWdncmVnYXRlZCgpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIGdldCByZXF1aXJlZExheWVyQ29sdW1ucygpIHtcbiAgICByZXR1cm4gYWdncmVnYXRlUmVxdWlyZWRDb2x1bW5zO1xuICB9XG5cbiAgZ2V0IGNvbHVtblBhaXJzKCkge1xuICAgIHJldHVybiB0aGlzLmRlZmF1bHRQb2ludENvbHVtblBhaXJzO1xuICB9XG5cbiAgZ2V0IG5vbmVMYXllckRhdGFBZmZlY3RpbmdQcm9wcygpIHtcbiAgICByZXR1cm4gW1xuICAgICAgLi4uc3VwZXIubm9uZUxheWVyRGF0YUFmZmVjdGluZ1Byb3BzLFxuICAgICAgJ2VuYWJsZTNkJyxcbiAgICAgICdjb2xvclJhbmdlJyxcbiAgICAgICdjb2xvclNjYWxlJyxcbiAgICAgICdjb2xvckRvbWFpbicsXG4gICAgICAnc2l6ZVJhbmdlJyxcbiAgICAgICdzaXplU2NhbGUnLFxuICAgICAgJ3NpemVEb21haW4nLFxuICAgICAgJ3BlcmNlbnRpbGUnLFxuICAgICAgJ2NvdmVyYWdlJyxcbiAgICAgICdlbGV2YXRpb25QZXJjZW50aWxlJyxcbiAgICAgICdlbGV2YXRpb25TY2FsZSdcbiAgICBdO1xuICB9XG5cbiAgZ2V0IHZpc3VhbENoYW5uZWxzKCkge1xuICAgIHJldHVybiB7XG4gICAgICBjb2xvcjoge1xuICAgICAgICBhZ2dyZWdhdGlvbjogJ2NvbG9yQWdncmVnYXRpb24nLFxuICAgICAgICBjaGFubmVsU2NhbGVUeXBlOiBDSEFOTkVMX1NDQUxFUy5jb2xvckFnZ3IsXG4gICAgICAgIGRlZmF1bHRNZWFzdXJlOiAnUG9pbnQgQ291bnQnLFxuICAgICAgICBkb21haW46ICdjb2xvckRvbWFpbicsXG4gICAgICAgIGZpZWxkOiAnY29sb3JGaWVsZCcsXG4gICAgICAgIGtleTogJ2NvbG9yJyxcbiAgICAgICAgcHJvcGVydHk6ICdjb2xvcicsXG4gICAgICAgIHJhbmdlOiAnY29sb3JSYW5nZScsXG4gICAgICAgIHNjYWxlOiAnY29sb3JTY2FsZSdcbiAgICAgIH0sXG4gICAgICBzaXplOiB7XG4gICAgICAgIGFnZ3JlZ2F0aW9uOiAnc2l6ZUFnZ3JlZ2F0aW9uJyxcbiAgICAgICAgY2hhbm5lbFNjYWxlVHlwZTogQ0hBTk5FTF9TQ0FMRVMuc2l6ZUFnZ3IsXG4gICAgICAgIGNvbmRpdGlvbjogY29uZmlnID0+IGNvbmZpZy52aXNDb25maWcuZW5hYmxlM2QsXG4gICAgICAgIGRlZmF1bHRNZWFzdXJlOiAnUG9pbnQgQ291bnQnLFxuICAgICAgICBkb21haW46ICdzaXplRG9tYWluJyxcbiAgICAgICAgZmllbGQ6ICdzaXplRmllbGQnLFxuICAgICAgICBrZXk6ICdzaXplJyxcbiAgICAgICAgcHJvcGVydHk6ICdoZWlnaHQnLFxuICAgICAgICByYW5nZTogJ3NpemVSYW5nZScsXG4gICAgICAgIHNjYWxlOiAnc2l6ZVNjYWxlJ1xuICAgICAgfVxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBkZXNjcmlwdGlvbiBvZiBhIHZpc3VhbENoYW5uZWwgY29uZmlnXG4gICAqIEBwYXJhbSBrZXlcbiAgICogQHJldHVybnMge3tsYWJlbDogc3RyaW5nLCBtZWFzdXJlOiAoc3RyaW5nfHN0cmluZyl9fVxuICAgKi9cbiAgZ2V0VmlzdWFsQ2hhbm5lbERlc2NyaXB0aW9uKGtleSkge1xuICAgIC8vIGUuZy4gbGFiZWw6IENvbG9yLCBtZWFzdXJlOiBBdmVyYWdlIG9mIEVUQVxuICAgIC8vIGNvbnNvbGUubG9nKCdpbnNpZGUgZ2V0VmlzdWFsQ2hhbm5lbERlc2NyaXB0aW9uJywga2V5KTtcbiAgICBjb25zdCB7cmFuZ2UsIGZpZWxkLCBkZWZhdWx0TWVhc3VyZSwgYWdncmVnYXRpb259ID0gdGhpcy52aXN1YWxDaGFubmVsc1tcbiAgICAgIGtleVxuICAgIF07XG4gICAgcmV0dXJuIHtcbiAgICAgIGxhYmVsOiB0aGlzLnZpc0NvbmZpZ1NldHRpbmdzW3JhbmdlXS5sYWJlbCxcbiAgICAgIG1lYXN1cmU6IHRoaXMuY29uZmlnW2ZpZWxkXVxuICAgICAgICA/IGAke3RoaXMuY29uZmlnLnZpc0NvbmZpZ1thZ2dyZWdhdGlvbl19IG9mICR7dGhpcy5jb25maWdbZmllbGRdLm5hbWV9YFxuICAgICAgICA6IGRlZmF1bHRNZWFzdXJlXG4gICAgfTtcbiAgfVxuXG4gIGdldEhvdmVyRGF0YShvYmplY3QpIHtcbiAgICAvLyByZXR1cm4gYWdncmVnYXRlZCBvYmplY3RcbiAgICByZXR1cm4gb2JqZWN0O1xuICB9XG5cbiAgLyoqXG4gICAqIEFnZ3JlZ2F0aW9uIGxheWVyIGhhbmRsZXMgdmlzdWFsIGNoYW5uZWwgYWdncmVnYXRpb24gaW5zaWRlIGRlY2suZ2wgbGF5ZXJcbiAgICovXG4gIHVwZGF0ZUxheWVyVmlzdWFsQ2hhbm5lbCh7ZGF0YSwgYWxsRGF0YX0sIGNoYW5uZWwpIHtcbiAgICB0aGlzLnZhbGlkYXRlVmlzdWFsQ2hhbm5lbChjaGFubmVsKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBhZ2dyZWdhdGlvbiB0eXBlIG9uIHRvcCBvZiBiYXNpYyBsYXllciB2aXN1YWwgY2hhbm5lbCB2YWxpZGF0aW9uXG4gICAqIEBwYXJhbSBjaGFubmVsXG4gICAqL1xuICB2YWxpZGF0ZVZpc3VhbENoYW5uZWwoY2hhbm5lbCkge1xuICAgIC8vIGZpZWxkIHR5cGUgZGVjaWRlcyBhZ2dyZWdhdGlvbiB0eXBlIGRlY2lkZXMgc2NhbGUgdHlwZVxuICAgIHRoaXMudmFsaWRhdGVGaWVsZFR5cGUoY2hhbm5lbCk7XG4gICAgdGhpcy52YWxpZGF0ZUFnZ3JlZ2F0aW9uVHlwZShjaGFubmVsKTtcbiAgICB0aGlzLnZhbGlkYXRlU2NhbGUoY2hhbm5lbCk7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgYWdncmVnYXRpb24gdHlwZSBiYXNlZCBvbiBzZWxlY3RlZCBmaWVsZFxuICAgKi9cbiAgdmFsaWRhdGVBZ2dyZWdhdGlvblR5cGUoY2hhbm5lbCkge1xuICAgIGNvbnN0IHZpc3VhbENoYW5uZWwgPSB0aGlzLnZpc3VhbENoYW5uZWxzW2NoYW5uZWxdO1xuICAgIGNvbnN0IHtmaWVsZCwgYWdncmVnYXRpb259ID0gdmlzdWFsQ2hhbm5lbDtcbiAgICBjb25zdCBhZ2dyZWdhdGlvbk9wdGlvbnMgPSB0aGlzLmdldEFnZ3JlZ2F0aW9uT3B0aW9ucyhjaGFubmVsKTtcblxuICAgIGlmICghYWdncmVnYXRpb24pIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoIWFnZ3JlZ2F0aW9uT3B0aW9ucy5sZW5ndGgpIHtcbiAgICAgIC8vIGlmIGZpZWxkIGNhbm5vdCBiZSBhZ2dyZWdhdGVkLCBzZXQgZmllbGQgdG8gbnVsbFxuICAgICAgdGhpcy51cGRhdGVMYXllckNvbmZpZyh7W2ZpZWxkXTogbnVsbH0pO1xuICAgIH0gZWxzZSBpZiAoXG4gICAgICAhYWdncmVnYXRpb25PcHRpb25zLmluY2x1ZGVzKHRoaXMuY29uZmlnLnZpc0NvbmZpZ1thZ2dyZWdhdGlvbl0pXG4gICAgKSB7XG4gICAgICAvLyBjdXJyZW50IGFnZ3JlZ2F0aW9uIHR5cGUgaXMgbm90IHN1cHBvcnRlZCBieSB0aGlzIGZpZWxkXG4gICAgICAvLyBzZXQgYWdncmVnYXRpb24gdG8gdGhlIGZpcnN0IHN1cHBvcnRlZCBvcHRpb25cbiAgICAgIHRoaXMudXBkYXRlTGF5ZXJWaXNDb25maWcoe1thZ2dyZWdhdGlvbl06IGFnZ3JlZ2F0aW9uT3B0aW9uc1swXX0pO1xuICAgIH1cbiAgfVxuXG4gIGdldEFnZ3JlZ2F0aW9uT3B0aW9ucyhjaGFubmVsKSB7XG4gICAgY29uc3QgdmlzdWFsQ2hhbm5lbCA9IHRoaXMudmlzdWFsQ2hhbm5lbHNbY2hhbm5lbF07XG4gICAgY29uc3Qge2ZpZWxkLCBjaGFubmVsU2NhbGVUeXBlfSA9IHZpc3VhbENoYW5uZWw7XG4gICAgLy8gY29uc29sZS5sb2coXCJmaWVsZCBhbmQgY2hhbm5lbFNjYWxlVHlwZVwiLGZpZWxkLCBjaGFubmVsU2NhbGVUeXBlIClcbiAgICByZXR1cm4gT2JqZWN0LmtleXMoXG4gICAgICB0aGlzLmNvbmZpZ1tmaWVsZF1cbiAgICAgICAgPyBGSUVMRF9PUFRTW3RoaXMuY29uZmlnW2ZpZWxkXS50eXBlXS5zY2FsZVtjaGFubmVsU2NhbGVUeXBlXVxuICAgICAgICA6IERFRkFVTFRfQUdHUkVHQVRJT05bY2hhbm5lbFNjYWxlVHlwZV1cbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBzY2FsZSBvcHRpb25zIGJhc2VkIG9uIGN1cnJlbnQgZmllbGQgYW5kIGFnZ3JlZ2F0aW9uIHR5cGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNoYW5uZWxcbiAgICogQHJldHVybnMge3N0cmluZ1tdfVxuICAgKi9cbiAgZ2V0U2NhbGVPcHRpb25zKGNoYW5uZWwpIHtcbiAgICBjb25zdCB2aXN1YWxDaGFubmVsID0gdGhpcy52aXN1YWxDaGFubmVsc1tjaGFubmVsXTtcbiAgICBjb25zdCB7ZmllbGQsIGFnZ3JlZ2F0aW9uLCBjaGFubmVsU2NhbGVUeXBlfSA9IHZpc3VhbENoYW5uZWw7XG4gICAgY29uc3QgYWdncmVnYXRpb25UeXBlID0gdGhpcy5jb25maWcudmlzQ29uZmlnW2FnZ3JlZ2F0aW9uXTtcbiAgICByZXR1cm4gdGhpcy5jb25maWdbZmllbGRdXG4gICAgICA/IC8vIHNjYWxlIG9wdGlvbnMgYmFzZWQgb24gYWdncmVnYXRpb25cbiAgICAgICAgRklFTERfT1BUU1t0aGlzLmNvbmZpZ1tmaWVsZF0udHlwZV0uc2NhbGVbY2hhbm5lbFNjYWxlVHlwZV1bXG4gICAgICAgICAgYWdncmVnYXRpb25UeXBlXG4gICAgICAgIF1cbiAgICAgIDogLy8gZGVmYXVsdCBzY2FsZSBvcHRpb25zIGZvciBwb2ludCBjb3VudFxuICAgICAgICBERUZBVUxUX0FHR1JFR0FUSU9OW2NoYW5uZWxTY2FsZVR5cGVdW2FnZ3JlZ2F0aW9uVHlwZV07XG4gIH1cblxuICAvKipcbiAgICogQWdncmVnYXRpb24gbGF5ZXIgaGFuZGxlcyB2aXN1YWwgY2hhbm5lbCBhZ2dyZWdhdGlvbiBpbnNpZGUgZGVjay5nbCBsYXllclxuICAgKi9cbiAgdXBkYXRlTGF5ZXJEb21haW4oZGF0YXNldCwgbmV3RmlsdGVyKSB7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICB1cGRhdGVMYXllck1ldGEoYWxsRGF0YSwgZ2V0UG9zaXRpb24pIHtcbiAgICAvLyBnZXQgYm91bmRzIGZyb20gcG9pbnRzXG4gICAgY29uc3QgYm91bmRzID0gdGhpcy5nZXRQb2ludHNCb3VuZHMoYWxsRGF0YSwgZ2V0UG9zaXRpb24pO1xuXG4gICAgdGhpcy51cGRhdGVNZXRhKHtib3VuZHN9KTtcbiAgfVxuXG4gIGZvcm1hdExheWVyRGF0YShfLCBhbGxEYXRhLCBmaWx0ZXJlZEluZGV4LCBvbGRMYXllckRhdGEsIG9wdCA9IHt9KSB7XG4gICAgY29uc3QgZ2V0UG9zaXRpb24gPSB0aGlzLmdldFBvc2l0aW9uKHRoaXMuY29uZmlnLmNvbHVtbnMpO1xuXG4gICAgaWYgKCFvbGRMYXllckRhdGEgfHwgb2xkTGF5ZXJEYXRhLmdldFBvc2l0aW9uICE9PSBnZXRQb3NpdGlvbikge1xuICAgICAgdGhpcy51cGRhdGVMYXllck1ldGEoYWxsRGF0YSwgZ2V0UG9zaXRpb24pO1xuICAgIH1cblxuICAgIGNvbnN0IGdldENvbG9yVmFsdWUgPSB0aGlzLmNvbmZpZy5jb2xvckZpZWxkXG4gICAgICA/IHRoaXMuZ2V0Q29sb3JWYWx1ZShcbiAgICAgICAgICB0aGlzLmNvbmZpZy5jb2xvckZpZWxkLFxuICAgICAgICAgIHRoaXMuY29uZmlnLnZpc0NvbmZpZy5jb2xvckFnZ3JlZ2F0aW9uXG4gICAgICAgIClcbiAgICAgIDogdW5kZWZpbmVkO1xuICAgIC8vIGNvbnNvbGUubG9nKCdnZXRDb2xvclZhbHVlIGluc2lkZSBhZ2dyZWdhdGlvbiBMYXllcicsIGdldENvbG9yVmFsdWUpO1xuXG4gICAgY29uc3QgZ2V0RWxldmF0aW9uVmFsdWUgPSB0aGlzLmNvbmZpZy5zaXplRmllbGRcbiAgICAgID8gdGhpcy5nZXRFbGV2YXRpb25WYWx1ZShcbiAgICAgICAgICB0aGlzLmNvbmZpZy5zaXplRmllbGQsXG4gICAgICAgICAgdGhpcy5jb25maWcudmlzQ29uZmlnLnNpemVBZ2dyZWdhdGlvblxuICAgICAgICApXG4gICAgICA6IHVuZGVmaW5lZDtcblxuICAgIGxldCBkYXRhO1xuICAgIGlmIChcbiAgICAgIG9sZExheWVyRGF0YSAmJlxuICAgICAgb2xkTGF5ZXJEYXRhLmRhdGEgJiZcbiAgICAgIG9wdC5zYW1lRGF0YSAmJlxuICAgICAgb2xkTGF5ZXJEYXRhLmdldFBvc2l0aW9uID09PSBnZXRQb3NpdGlvblxuICAgICkge1xuICAgICAgZGF0YSA9IG9sZExheWVyRGF0YS5kYXRhO1xuICAgIH0gZWxzZSB7XG4gICAgICBkYXRhID0gZmlsdGVyZWRJbmRleC5tYXAoaSA9PiBhbGxEYXRhW2ldKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgZGF0YSxcbiAgICAgIGdldFBvc2l0aW9uLFxuICAgICAgLi4uKGdldENvbG9yVmFsdWUgPyB7Z2V0Q29sb3JWYWx1ZX0gOiB7fSksXG4gICAgICAuLi4oZ2V0RWxldmF0aW9uVmFsdWUgPyB7Z2V0RWxldmF0aW9uVmFsdWV9IDoge30pXG4gICAgfTtcbiAgfVxufVxuIl19