UNPKG

kepler.gl

Version:

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

503 lines (497 loc) 67.9 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.tripVisConfigs = exports.featureResolver = exports.featureAccessor = exports.defaultThickness = exports.defaultLineWidth = exports["default"] = exports.COLUMN_MODE_TABLE = exports.COLUMN_MODE_GEOJSON = void 0; 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 _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _get2 = _interopRequireDefault(require("@babel/runtime/helpers/get")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _memoize = _interopRequireDefault(require("lodash/memoize")); var _uniq = _interopRequireDefault(require("lodash/uniq")); var _baseLayer = _interopRequireWildcard(require("../base-layer")); var _geoLayers = require("@deck.gl/geo-layers"); var _constants = require("@kepler.gl/constants"); var _tripLayerIcon = _interopRequireDefault(require("./trip-layer-icon")); var _geojsonUtils = require("../geojson-layer/geojson-utils"); var _tripUtils = require("./trip-utils"); var _tripInfoModal = _interopRequireDefault(require("./trip-info-modal")); var _d3Array = require("d3-array"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; } function 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 _callSuper(t, o, e) { return o = (0, _getPrototypeOf2["default"])(o), (0, _possibleConstructorReturn2["default"])(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2["default"])(t).constructor) : o.apply(t, e)); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } function _superPropGet(t, e, r, o) { var p = (0, _get2["default"])((0, _getPrototypeOf2["default"])(1 & o ? t.prototype : t), e, r); return 2 & o ? function (t) { return p.apply(r, t); } : p; } // SPDX-License-Identifier: MIT // Copyright contributors to the kepler.gl project var zoomFactorValue = 8; var defaultThickness = exports.defaultThickness = 0.5; var defaultLineWidth = exports.defaultLineWidth = 1; var tripVisConfigs = exports.tripVisConfigs = { opacity: 'opacity', thickness: { type: 'number', defaultValue: defaultThickness, label: 'Stroke Width', isRanged: false, range: [0, 100], step: 0.1, group: 'stroke', property: 'thickness' }, colorRange: 'colorRange', trailLength: 'trailLength', fadeTrail: 'fadeTrail', billboard: 'billboard', sizeRange: 'strokeWidthRange' }; var featureAccessor = exports.featureAccessor = function featureAccessor(_ref) { var geojson = _ref.geojson; return function (dc) { return function (d) { return dc.valueAt(d.index, geojson.fieldIdx); }; }; }; var featureResolver = exports.featureResolver = function featureResolver(_ref2) { var geojson = _ref2.geojson; return geojson.fieldIdx; }; var getTableModeValueAccessor = function getTableModeValueAccessor(f) { // Called from gpu-filter-utils.getFilterValueAccessor() return function (field) { return f.properties.values.map(function (v) { return field.valueAccessor(v); }); }; }; var getTableModeFieldValue = function getTableModeFieldValue(field, data) { var rv; if (typeof data === 'function') { rv = data(field); } else { rv = (0, _baseLayer.defaultGetFieldValue)(field, data); } return rv; }; var COLUMN_MODE_GEOJSON = exports.COLUMN_MODE_GEOJSON = 'geojson'; var COLUMN_MODE_TABLE = exports.COLUMN_MODE_TABLE = 'table'; var SUPPORTED_COLUMN_MODES = [{ key: COLUMN_MODE_GEOJSON, label: 'GeoJSON', requiredColumns: ['geojson'] }, { key: COLUMN_MODE_TABLE, label: 'Table columns', requiredColumns: ['id', 'lat', 'lng', 'timestamp'], optionalColumns: ['altitude'] }]; var DEFAULT_COLUMN_MODE = COLUMN_MODE_GEOJSON; var TripLayer = exports["default"] = /*#__PURE__*/function (_Layer) { function TripLayer(props) { var _this; (0, _classCallCheck2["default"])(this, TripLayer); _this = _callSuper(this, TripLayer, [props]); (0, _defineProperty2["default"])(_this, "dataToFeature", void 0); (0, _defineProperty2["default"])(_this, "dataToTimeStamp", void 0); (0, _defineProperty2["default"])(_this, "getFeature", void 0); (0, _defineProperty2["default"])(_this, "_layerInfoModal", void 0); _this.dataToFeature = []; _this.dataToTimeStamp = []; _this.dataContainer = null; _this.registerVisConfig(tripVisConfigs); _this.getFeature = (0, _memoize["default"])(featureAccessor, featureResolver); _this._layerInfoModal = (0, _defineProperty2["default"])((0, _defineProperty2["default"])({}, COLUMN_MODE_TABLE, (0, _tripInfoModal["default"])(COLUMN_MODE_TABLE)), COLUMN_MODE_GEOJSON, (0, _tripInfoModal["default"])(COLUMN_MODE_GEOJSON)); return _this; } (0, _inherits2["default"])(TripLayer, _Layer); return (0, _createClass2["default"])(TripLayer, [{ key: "supportedColumnModes", get: function get() { return SUPPORTED_COLUMN_MODES; } }, { key: "type", get: function get() { return TripLayer.type; } }, { key: "name", get: function get() { return 'Trip'; } }, { key: "layerIcon", get: function get() { return _tripLayerIcon["default"]; } }, { key: "columnPairs", get: function get() { return this.defaultPointColumnPairs; } }, { key: "accessVSFieldValue", value: function accessVSFieldValue() { if (this.config.columnMode === COLUMN_MODE_GEOJSON) { return _baseLayer.defaultGetFieldValue; } return getTableModeFieldValue; } }, { key: "visualChannels", get: function get() { var visualChannels = _superPropGet(TripLayer, "visualChannels", this, 1); return _objectSpread(_objectSpread({}, visualChannels), {}, { color: _objectSpread(_objectSpread({}, visualChannels.color), {}, { accessor: 'getColor', nullValue: visualChannels.color.nullValue, getAttributeValue: function getAttributeValue(config) { return function (d) { return d.properties.lineColor || config.color; }; }, // used this to get updateTriggers defaultValue: function defaultValue(config) { return config.color; } }), size: _objectSpread(_objectSpread({}, visualChannels.size), {}, { property: 'stroke', accessor: 'getWidth', condition: function condition(config) { return config.visConfig.stroked; }, nullValue: 0, getAttributeValue: function getAttributeValue() { return function (d) { return d.properties.lineWidth || defaultLineWidth; }; } }) }); } }, { key: "animationDomain", get: function get() { return this.config.animation.domain; } }, { key: "layerInfoModal", get: function get() { return (0, _defineProperty2["default"])((0, _defineProperty2["default"])({}, COLUMN_MODE_GEOJSON, { id: 'iconInfo', template: this._layerInfoModal[COLUMN_MODE_GEOJSON], modalProps: { title: 'modal.tripInfo.title' } }), COLUMN_MODE_TABLE, { id: 'iconInfo', template: this._layerInfoModal[COLUMN_MODE_TABLE], modalProps: { title: 'modal.tripInfo.titleTable' } }); } }, { key: "getPositionAccessor", value: function getPositionAccessor(dataContainer) { if (this.config.columnMode === COLUMN_MODE_GEOJSON) { return this.getFeature(this.config.columns)(dataContainer); } return null; } }, { key: "getDefaultLayerConfig", value: function getDefaultLayerConfig(props) { var _props$columnMode; return _objectSpread(_objectSpread({}, _superPropGet(TripLayer, "getDefaultLayerConfig", this, 3)([props])), {}, { columnMode: (_props$columnMode = props === null || props === void 0 ? void 0 : props.columnMode) !== null && _props$columnMode !== void 0 ? _props$columnMode : DEFAULT_COLUMN_MODE, animation: { enabled: true, domain: null } }); } }, { key: "getHoverData", value: function getHoverData(object, dataContainer, fields, animationConfig) { var _this$_findColumnMode; if (this.config.columnMode === COLUMN_MODE_GEOJSON) { // index for dataContainer is saved to feature.properties return dataContainer.row(object.properties.index); } return (_this$_findColumnMode = this._findColumnModeDatumForFeature(object.properties.index, animationConfig.currentTime)) === null || _this$_findColumnMode === void 0 ? void 0 : _this$_findColumnMode.datum; } }, { key: "calculateDataAttribute", value: function calculateDataAttribute(dataset) { var _this2 = this; switch (this.config.columnMode) { case COLUMN_MODE_GEOJSON: { return dataset.filteredIndex.map(function (i) { return _this2.dataToFeature[i]; }) // TODO d can be BinaryFeatureCollection, fix logic .filter(function (d) { var _geometry; return d && ((_geometry = d.geometry) === null || _geometry === void 0 ? void 0 : _geometry.type) === 'LineString'; }); } case COLUMN_MODE_TABLE: return (0, _geojsonUtils.applyFiltersToTableColumns)(dataset, this.dataToFeature); default: return []; } } }, { key: "formatLayerData", value: function formatLayerData(datasets, oldLayerData) { var _this3 = this; if (this.config.dataId === null) { return {}; } // to-do: parse segment from dataContainer var _datasets$this$config = datasets[this.config.dataId], dataContainer = _datasets$this$config.dataContainer, gpuFilter = _datasets$this$config.gpuFilter; var _this$updateData = this.updateData(datasets, oldLayerData), data = _this$updateData.data; var valueAccessor; if (this.config.columnMode === COLUMN_MODE_GEOJSON) { valueAccessor = function valueAccessor(dc, f, fieldIndex) { return dc.valueAt(f.properties.index, fieldIndex); }; } else { valueAccessor = getTableModeValueAccessor; } var indexAccessor = function indexAccessor(f) { return f.properties.index; }; var dataAccessor = function dataAccessor() { return function (d) { return { index: d.properties.index }; }; }; var accessors = this.getAttributeAccessors({ dataAccessor: dataAccessor, dataContainer: dataContainer }); var getFilterValue = gpuFilter.filterValueAccessor(dataContainer)(indexAccessor, valueAccessor); return _objectSpread({ data: data, getFilterValue: getFilterValue, getPath: function getPath(d) { return d.geometry.coordinates; }, getTimestamps: function getTimestamps(d) { return _this3.dataToTimeStamp[d.properties.index]; } }, accessors); } }, { key: "updateAnimationDomain", value: function updateAnimationDomain(domain) { this.updateLayerConfig({ animation: _objectSpread(_objectSpread({}, this.config.animation), {}, { domain: domain }) }); } }, { key: "updateLayerMeta", value: function updateLayerMeta(dataset) { var dataContainer = dataset.dataContainer; var getFeature; if (this.config.columnMode === COLUMN_MODE_GEOJSON) { getFeature = this.getPositionAccessor(dataContainer); if (getFeature === this.meta.getFeature) { // TODO: revisit this after gpu filtering return; } this.dataToFeature = (0, _geojsonUtils.getGeojsonDataMaps)(dataContainer, getFeature); } else { this.dataContainer = dataContainer; this.dataToFeature = (0, _geojsonUtils.groupColumnsAsGeoJson)(dataContainer, this.config.columns, 'timestamp'); } var _parseTripGeoJsonTime = (0, _tripUtils.parseTripGeoJsonTimestamp)(this.dataToFeature), dataToTimeStamp = _parseTripGeoJsonTime.dataToTimeStamp, animationDomain = _parseTripGeoJsonTime.animationDomain; this.dataToTimeStamp = dataToTimeStamp; this.updateAnimationDomain(animationDomain); // get bounds from features var bounds = (0, _geojsonUtils.getGeojsonBounds)(this.dataToFeature); // keep a record of what type of geometry the collection has var featureTypes = (0, _geojsonUtils.getGeojsonFeatureTypes)(this.dataToFeature); this.updateMeta({ bounds: bounds, featureTypes: featureTypes, getFeature: getFeature }); } }, { key: "setInitialLayerConfig", value: function setInitialLayerConfig(dataset) { var dataContainer = dataset.dataContainer; if (!dataContainer.numRows()) { return this; } // defefaultLayerProps will automatically find geojson column // if not found, we try to set it to id / lat /lng /ts if (!this.config.columns.geojson.value) { // find columns from lat, lng, id, and ts var columnConfig = (0, _geojsonUtils.detectTableColumns)(dataset, this.config.columns); if (columnConfig) { this.updateLayerConfig(_objectSpread(_objectSpread({}, columnConfig), {}, { columnMode: COLUMN_MODE_TABLE })); } else { return this; } } this.updateLayerMeta(dataset); return this; } }, { key: "renderLayer", value: function renderLayer(opts) { var _animationConfig$doma, _mapState$globe; var data = opts.data, gpuFilter = opts.gpuFilter, mapState = opts.mapState, animationConfig = opts.animationConfig; var visConfig = this.config.visConfig; var zoomFactor = this.getZoomFactor(mapState); var isValidTime = animationConfig && Array.isArray(animationConfig.domain) && animationConfig.domain.every(Number.isFinite) && Number.isFinite(animationConfig.currentTime); if (!isValidTime) { return []; } var domain0 = (_animationConfig$doma = animationConfig.domain) === null || _animationConfig$doma === void 0 ? void 0 : _animationConfig$doma[0]; var gpuFilterUpdateTriggers = { getFilterValue: gpuFilter.filterValueUpdateTriggers }; var updateTriggers = _objectSpread(_objectSpread({}, this.getVisualChannelUpdateTriggers()), {}, { getTimestamps: { columns: this.config.columns, domain0: domain0 } }, gpuFilterUpdateTriggers); var defaultLayerProps = this.getDefaultDeckLayerProps(opts); var billboardWidthFactor = visConfig.billboard ? _constants.PROJECTED_PIXEL_SIZE_MULTIPLIER : 1; var layerProps = _objectSpread(_objectSpread(_objectSpread({}, defaultLayerProps), data), {}, { getTimestamps: function getTimestamps(d) { return (data.getTimestamps(d) || []).map(function (ts) { return ts - domain0; }); }, widthScale: visConfig.thickness * zoomFactor * zoomFactorValue * billboardWidthFactor, capRounded: true, jointRounded: true, wrapLongitude: false, parameters: { depthTest: mapState.dragRotate, depthMask: false }, trailLength: visConfig.trailLength * 1000, fadeTrail: visConfig.fadeTrail, billboard: visConfig.billboard, // TODO: giuseppe this values becomes negative currentTime: animationConfig.currentTime - domain0, updateTriggers: updateTriggers, id: "".concat(defaultLayerProps.id).concat((_mapState$globe = mapState.globe) !== null && _mapState$globe !== void 0 && _mapState$globe.enabled ? '-globe' : '') }); return [new _geoLayers.TripsLayer(layerProps)]; } /** * Finds coordinates and datum at the current animation time by the specified feature index. * @param featureIndex * @param time * @returns {{datum: (null|string|*), idx: *, coords}|{datum: null, idx: number, coords: null}} */ }, { key: "_findColumnModeDatumForFeature", value: function _findColumnModeDatumForFeature(featureIndex, time) { if (this.config.columnMode === COLUMN_MODE_TABLE) { var object = this.dataToFeature[featureIndex]; var idx = (0, _d3Array.bisectRight)(this.dataToTimeStamp[featureIndex], time); // @ts-expect-error type geometry? var _ref4 = (object === null || object === void 0 ? void 0 : object.geometry) || { coordinates: [] }, coordinates = _ref4.coordinates; if (idx >= 0 && idx < coordinates.length) { var coords = coordinates[idx]; return { idx: idx, coords: coords, datum: coords === null || coords === void 0 ? void 0 : coords.datum }; } } return { idx: -1, coords: null, datum: null }; } }], [{ key: "type", get: function get() { return 'trip'; } }, { key: "findDefaultLayerProps", value: function findDefaultLayerProps(_ref5, foundLayers) { var _this4 = this; var label = _ref5.label, _ref5$fields = _ref5.fields, fields = _ref5$fields === void 0 ? [] : _ref5$fields, dataContainer = _ref5.dataContainer, id = _ref5.id; var geojsonColumns = fields.filter(function (f) { return f.type === 'geojson'; }).map(function (f) { return f.name; }); var defaultColumns = { geojson: (0, _uniq["default"])([].concat((0, _toConsumableArray2["default"])(_constants.GEOJSON_FIELDS.geojson), (0, _toConsumableArray2["default"])(geojsonColumns))) }; var geoJsonColumns = this.findDefaultColumnField(defaultColumns, fields); var tripGeojsonColumns = (geoJsonColumns || []).filter(function (col) { return (0, _tripUtils.isTripGeoJsonField)(dataContainer, fields[col.geojson.fieldIdx]); }); if (tripGeojsonColumns.length) { return { props: tripGeojsonColumns.map(function (columns) { return { label: typeof label === 'string' && label.replace(/\.[^/.]+$/, '') || _this4.type, columns: columns, isVisible: true, columnMode: COLUMN_MODE_GEOJSON }; }), // if a geojson layer is created from this column, delete it foundLayers: foundLayers === null || foundLayers === void 0 ? void 0 : foundLayers.filter(function (prop) { return prop.type !== 'geojson' || prop.dataId !== id || !tripGeojsonColumns.find(function (c) { return prop.columns.geojson.name === c.geojson.name; }); }) }; } return { props: [] }; } }]); }(_baseLayer["default"]); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbWVtb2l6ZSIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJyZXF1aXJlIiwiX3VuaXEiLCJfYmFzZUxheWVyIiwiX2ludGVyb3BSZXF1aXJlV2lsZGNhcmQiLCJfZ2VvTGF5ZXJzIiwiX2NvbnN0YW50cyIsIl90cmlwTGF5ZXJJY29uIiwiX2dlb2pzb25VdGlscyIsIl90cmlwVXRpbHMiLCJfdHJpcEluZm9Nb2RhbCIsIl9kM0FycmF5IiwiX2dldFJlcXVpcmVXaWxkY2FyZENhY2hlIiwiZSIsIldlYWtNYXAiLCJyIiwidCIsIl9fZXNNb2R1bGUiLCJfdHlwZW9mIiwiaGFzIiwiZ2V0IiwibiIsIl9fcHJvdG9fXyIsImEiLCJPYmplY3QiLCJkZWZpbmVQcm9wZXJ0eSIsImdldE93blByb3BlcnR5RGVzY3JpcHRvciIsInUiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJpIiwic2V0Iiwib3duS2V5cyIsImtleXMiLCJnZXRPd25Qcm9wZXJ0eVN5bWJvbHMiLCJvIiwiZmlsdGVyIiwiZW51bWVyYWJsZSIsInB1c2giLCJhcHBseSIsIl9vYmplY3RTcHJlYWQiLCJhcmd1bWVudHMiLCJsZW5ndGgiLCJmb3JFYWNoIiwiX2RlZmluZVByb3BlcnR5MiIsImdldE93blByb3BlcnR5RGVzY3JpcHRvcnMiLCJkZWZpbmVQcm9wZXJ0aWVzIiwiX2NhbGxTdXBlciIsIl9nZXRQcm90b3R5cGVPZjIiLCJfcG9zc2libGVDb25zdHJ1Y3RvclJldHVybjIiLCJfaXNOYXRpdmVSZWZsZWN0Q29uc3RydWN0IiwiUmVmbGVjdCIsImNvbnN0cnVjdCIsImNvbnN0cnVjdG9yIiwiQm9vbGVhbiIsInByb3RvdHlwZSIsInZhbHVlT2YiLCJfc3VwZXJQcm9wR2V0IiwicCIsIl9nZXQyIiwiem9vbUZhY3RvclZhbHVlIiwiZGVmYXVsdFRoaWNrbmVzcyIsImV4cG9ydHMiLCJkZWZhdWx0TGluZVdpZHRoIiwidHJpcFZpc0NvbmZpZ3MiLCJvcGFjaXR5IiwidGhpY2tuZXNzIiwidHlwZSIsImRlZmF1bHRWYWx1ZSIsImxhYmVsIiwiaXNSYW5nZWQiLCJyYW5nZSIsInN0ZXAiLCJncm91cCIsInByb3BlcnR5IiwiY29sb3JSYW5nZSIsInRyYWlsTGVuZ3RoIiwiZmFkZVRyYWlsIiwiYmlsbGJvYXJkIiwic2l6ZVJhbmdlIiwiZmVhdHVyZUFjY2Vzc29yIiwiX3JlZiIsImdlb2pzb24iLCJkYyIsImQiLCJ2YWx1ZUF0IiwiaW5kZXgiLCJmaWVsZElkeCIsImZlYXR1cmVSZXNvbHZlciIsIl9yZWYyIiwiZ2V0VGFibGVNb2RlVmFsdWVBY2Nlc3NvciIsImYiLCJmaWVsZCIsInByb3BlcnRpZXMiLCJ2YWx1ZXMiLCJtYXAiLCJ2IiwidmFsdWVBY2Nlc3NvciIsImdldFRhYmxlTW9kZUZpZWxkVmFsdWUiLCJkYXRhIiwicnYiLCJkZWZhdWx0R2V0RmllbGRWYWx1ZSIsIkNPTFVNTl9NT0RFX0dFT0pTT04iLCJDT0xVTU5fTU9ERV9UQUJMRSIsIlNVUFBPUlRFRF9DT0xVTU5fTU9ERVMiLCJrZXkiLCJyZXF1aXJlZENvbHVtbnMiLCJvcHRpb25hbENvbHVtbnMiLCJERUZBVUxUX0NPTFVNTl9NT0RFIiwiVHJpcExheWVyIiwiX0xheWVyIiwicHJvcHMiLCJfdGhpcyIsIl9jbGFzc0NhbGxDaGVjazIiLCJkYXRhVG9GZWF0dXJlIiwiZGF0YVRvVGltZVN0YW1wIiwiZGF0YUNvbnRhaW5lciIsInJlZ2lzdGVyVmlzQ29uZmlnIiwiZ2V0RmVhdHVyZSIsIm1lbW9pemUiLCJfbGF5ZXJJbmZvTW9kYWwiLCJUcmlwSW5mb01vZGFsRmFjdG9yeSIsIl9pbmhlcml0czIiLCJfY3JlYXRlQ2xhc3MyIiwiVHJpcExheWVySWNvbiIsImRlZmF1bHRQb2ludENvbHVtblBhaXJzIiwidmFsdWUiLCJhY2Nlc3NWU0ZpZWxkVmFsdWUiLCJjb25maWciLCJjb2x1bW5Nb2RlIiwidmlzdWFsQ2hhbm5lbHMiLCJjb2xvciIsImFjY2Vzc29yIiwibnVsbFZhbHVlIiwiZ2V0QXR0cmlidXRlVmFsdWUiLCJsaW5lQ29sb3IiLCJzaXplIiwiY29uZGl0aW9uIiwidmlzQ29uZmlnIiwic3Ryb2tlZCIsImxpbmVXaWR0aCIsImFuaW1hdGlvbiIsImRvbWFpbiIsImlkIiwidGVtcGxhdGUiLCJtb2RhbFByb3BzIiwidGl0bGUiLCJnZXRQb3NpdGlvbkFjY2Vzc29yIiwiY29sdW1ucyIsImdldERlZmF1bHRMYXllckNvbmZpZyIsIl9wcm9wcyRjb2x1bW5Nb2RlIiwiZW5hYmxlZCIsImdldEhvdmVyRGF0YSIsIm9iamVjdCIsImZpZWxkcyIsImFuaW1hdGlvbkNvbmZpZyIsIl90aGlzJF9maW5kQ29sdW1uTW9kZSIsInJvdyIsIl9maW5kQ29sdW1uTW9kZURhdHVtRm9yRmVhdHVyZSIsImN1cnJlbnRUaW1lIiwiZGF0dW0iLCJjYWxjdWxhdGVEYXRhQXR0cmlidXRlIiwiZGF0YXNldCIsIl90aGlzMiIsImZpbHRlcmVkSW5kZXgiLCJfZ2VvbWV0cnkiLCJnZW9tZXRyeSIsImFwcGx5RmlsdGVyc1RvVGFibGVDb2x1bW5zIiwiZm9ybWF0TGF5ZXJEYXRhIiwiZGF0YXNldHMiLCJvbGRMYXllckRhdGEiLCJfdGhpczMiLCJkYXRhSWQiLCJfZGF0YXNldHMkdGhpcyRjb25maWciLCJncHVGaWx0ZXIiLCJfdGhpcyR1cGRhdGVEYXRhIiwidXBkYXRlRGF0YSIsImZpZWxkSW5kZXgiLCJpbmRleEFjY2Vzc29yIiwiZGF0YUFjY2Vzc29yIiwiYWNjZXNzb3JzIiwiZ2V0QXR0cmlidXRlQWNjZXNzb3JzIiwiZ2V0RmlsdGVyVmFsdWUiLCJmaWx0ZXJWYWx1ZUFjY2Vzc29yIiwiZ2V0UGF0aCIsImNvb3JkaW5hdGVzIiwiZ2V0VGltZXN0YW1wcyIsInVwZGF0ZUFuaW1hdGlvbkRvbWFpbiIsInVwZGF0ZUxheWVyQ29uZmlnIiwidXBkYXRlTGF5ZXJNZXRhIiwibWV0YSIsImdldEdlb2pzb25EYXRhTWFwcyIsImdyb3VwQ29sdW1uc0FzR2VvSnNvbiIsIl9wYXJzZVRyaXBHZW9Kc29uVGltZSIsInBhcnNlVHJpcEdlb0pzb25UaW1lc3RhbXAiLCJhbmltYXRpb25Eb21haW4iLCJib3VuZHMiLCJnZXRHZW9qc29uQm91bmRzIiwiZmVhdHVyZVR5cGVzIiwiZ2V0R2VvanNvbkZlYXR1cmVUeXBlcyIsInVwZGF0ZU1ldGEiLCJzZXRJbml0aWFsTGF5ZXJDb25maWciLCJudW1Sb3dzIiwiY29sdW1uQ29uZmlnIiwiZGV0ZWN0VGFibGVDb2x1bW5zIiwicmVuZGVyTGF5ZXIiLCJvcHRzIiwiX2FuaW1hdGlvbkNvbmZpZyRkb21hIiwiX21hcFN0YXRlJGdsb2JlIiwibWFwU3RhdGUiLCJ6b29tRmFjdG9yIiwiZ2V0Wm9vbUZhY3RvciIsImlzVmFsaWRUaW1lIiwiQXJyYXkiLCJpc0FycmF5IiwiZXZlcnkiLCJOdW1iZXIiLCJpc0Zpbml0ZSIsImRvbWFpbjAiLCJncHVGaWx0ZXJVcGRhdGVUcmlnZ2VycyIsImZpbHRlclZhbHVlVXBkYXRlVHJpZ2dlcnMiLCJ1cGRhdGVUcmlnZ2VycyIsImdldFZpc3VhbENoYW5uZWxVcGRhdGVUcmlnZ2VycyIsImRlZmF1bHRMYXllclByb3BzIiwiZ2V0RGVmYXVsdERlY2tMYXllclByb3BzIiwiYmlsbGJvYXJkV2lkdGhGYWN0b3IiLCJQUk9KRUNURURfUElYRUxfU0laRV9NVUxUSVBMSUVSIiwibGF5ZXJQcm9wcyIsInRzIiwid2lkdGhTY2FsZSIsImNhcFJvdW5kZWQiLCJqb2ludFJvdW5kZWQiLCJ3cmFwTG9uZ2l0dWRlIiwicGFyYW1ldGVycyIsImRlcHRoVGVzdCIsImRyYWdSb3RhdGUiLCJkZXB0aE1hc2siLCJjb25jYXQiLCJnbG9iZSIsIkRlY2tHTFRyaXBzTGF5ZXIiLCJmZWF0dXJlSW5kZXgiLCJ0aW1lIiwiaWR4IiwiYmlzZWN0UmlnaHQiLCJfcmVmNCIsImNvb3JkcyIsImZpbmREZWZhdWx0TGF5ZXJQcm9wcyIsIl9yZWY1IiwiZm91bmRMYXllcnMiLCJfdGhpczQiLCJfcmVmNSRmaWVsZHMiLCJnZW9qc29uQ29sdW1ucyIsIm5hbWUiLCJkZWZhdWx0Q29sdW1ucyIsInVuaXEiLCJfdG9Db25zdW1hYmxlQXJyYXkyIiwiR0VPSlNPTl9GSUVMRFMiLCJnZW9Kc29uQ29sdW1ucyIsImZpbmREZWZhdWx0Q29sdW1uRmllbGQiLCJ0cmlwR2VvanNvbkNvbHVtbnMiLCJjb2wiLCJpc1RyaXBHZW9Kc29uRmllbGQiLCJyZXBsYWNlIiwiaXNWaXNpYmxlIiwicHJvcCIsImZpbmQiLCJjIiwiTGF5ZXIiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvdHJpcC1sYXllci90cmlwLWxheWVyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBNSVRcbi8vIENvcHlyaWdodCBjb250cmlidXRvcnMgdG8gdGhlIGtlcGxlci5nbCBwcm9qZWN0XG5cbmltcG9ydCBtZW1vaXplIGZyb20gJ2xvZGFzaC9tZW1vaXplJztcbmltcG9ydCB1bmlxIGZyb20gJ2xvZGFzaC91bmlxJztcbmltcG9ydCBMYXllciwge0xheWVyQmFzZUNvbmZpZywgZGVmYXVsdEdldEZpZWxkVmFsdWV9IGZyb20gJy4uL2Jhc2UtbGF5ZXInO1xuaW1wb3J0IHtUcmlwc0xheWVyIGFzIERlY2tHTFRyaXBzTGF5ZXJ9IGZyb20gJ0BkZWNrLmdsL2dlby1sYXllcnMnO1xuXG5pbXBvcnQge0dFT0pTT05fRklFTERTLCBQUk9KRUNURURfUElYRUxfU0laRV9NVUxUSVBMSUVSfSBmcm9tICdAa2VwbGVyLmdsL2NvbnN0YW50cyc7XG5pbXBvcnQgVHJpcExheWVySWNvbiBmcm9tICcuL3RyaXAtbGF5ZXItaWNvbic7XG5cbmltcG9ydCB7XG4gIGdldEdlb2pzb25EYXRhTWFwcyxcbiAgZ2V0R2VvanNvbkJvdW5kcyxcbiAgZ2V0R2VvanNvbkZlYXR1cmVUeXBlcyxcbiAgR2VvanNvbkRhdGFNYXBzLFxuICBkZXRlY3RUYWJsZUNvbHVtbnMsXG4gIGdyb3VwQ29sdW1uc0FzR2VvSnNvbixcbiAgYXBwbHlGaWx0ZXJzVG9UYWJsZUNvbHVtbnNcbn0gZnJvbSAnLi4vZ2VvanNvbi1sYXllci9nZW9qc29uLXV0aWxzJztcblxuaW1wb3J0IHtpc1RyaXBHZW9Kc29uRmllbGQsIHBhcnNlVHJpcEdlb0pzb25UaW1lc3RhbXB9IGZyb20gJy4vdHJpcC11dGlscyc7XG5pbXBvcnQgVHJpcEluZm9Nb2RhbEZhY3RvcnkgZnJvbSAnLi90cmlwLWluZm8tbW9kYWwnO1xuaW1wb3J0IHtiaXNlY3RSaWdodH0gZnJvbSAnZDMtYXJyYXknO1xuaW1wb3J0IHtcbiAgQ29sb3JSYW5nZSxcbiAgTWVyZ2UsXG4gIFZpc0NvbmZpZ0NvbG9yUmFuZ2UsXG4gIFZpc0NvbmZpZ051bWJlcixcbiAgVmlzQ29uZmlnUmFuZ2UsXG4gIExheWVyQ29sdW1uXG59IGZyb20gJ0BrZXBsZXIuZ2wvdHlwZXMnO1xuaW1wb3J0IHtkZWZhdWx0IGFzIEtlcGxlclRhYmxlLCBEYXRhc2V0c30gZnJvbSAnQGtlcGxlci5nbC90YWJsZSc7XG5pbXBvcnQge0RhdGFDb250YWluZXJJbnRlcmZhY2V9IGZyb20gJ0BrZXBsZXIuZ2wvdXRpbHMnO1xuXG5leHBvcnQgdHlwZSBUcmlwTGF5ZXJWaXNDb25maWdTZXR0aW5ncyA9IHtcbiAgb3BhY2l0eTogVmlzQ29uZmlnTnVtYmVyO1xuICB0aGlja25lc3M6IFZpc0NvbmZpZ051bWJlcjtcbiAgY29sb3JSYW5nZTogVmlzQ29uZmlnQ29sb3JSYW5nZTtcbiAgdHJhaWxMZW5ndGg6IFZpc0NvbmZpZ051bWJlcjtcbiAgc2l6ZVJhbmdlOiBWaXNDb25maWdSYW5nZTtcbn07XG5cbmV4cG9ydCB0eXBlIFRyaXBMYXllckNvbHVtbnNDb25maWcgPSB7XG4gIGdlb2pzb246IExheWVyQ29sdW1uO1xufTtcblxuZXhwb3J0IHR5cGUgVHJpcExheWVyVmlzQ29uZmlnID0ge1xuICBvcGFjaXR5OiBudW1iZXI7XG4gIHRoaWNrbmVzczogbnVtYmVyO1xuICBjb2xvclJhbmdlOiBDb2xvclJhbmdlO1xuICB0cmFpbExlbmd0aDogbnVtYmVyO1xuICBzaXplUmFuZ2U6IFtudW1iZXIsIG51bWJlcl07XG4gIGJpbGxib2FyZDogYm9vbGVhbjtcbiAgZmFkZVRyYWlsOiBib29sZWFuO1xufTtcblxuZXhwb3J0IHR5cGUgVHJpcExheWVyQ29uZmlnID0gTWVyZ2U8XG4gIExheWVyQmFzZUNvbmZpZyxcbiAge2NvbHVtbnM6IFRyaXBMYXllckNvbHVtbnNDb25maWc7IHZpc0NvbmZpZzogVHJpcExheWVyVmlzQ29uZmlnfVxuPjtcblxuZXhwb3J0IHR5cGUgVHJpcExheWVyTWV0YSA9IHtcbiAgZ2V0RmVhdHVyZTogYW55O1xufTtcblxuY29uc3Qgem9vbUZhY3RvclZhbHVlID0gODtcblxuZXhwb3J0IGNvbnN0IGRlZmF1bHRUaGlja25lc3MgPSAwLjU7XG5leHBvcnQgY29uc3QgZGVmYXVsdExpbmVXaWR0aCA9IDE7XG5cbmV4cG9ydCBjb25zdCB0cmlwVmlzQ29uZmlnczoge1xuICBvcGFjaXR5OiAnb3BhY2l0eSc7XG4gIHRoaWNrbmVzczogVmlzQ29uZmlnTnVtYmVyO1xuICBjb2xvclJhbmdlOiAnY29sb3JSYW5nZSc7XG4gIHRyYWlsTGVuZ3RoOiAndHJhaWxMZW5ndGgnO1xuICBmYWRlVHJhaWw6ICdmYWRlVHJhaWwnO1xuICBiaWxsYm9hcmQ6ICdiaWxsYm9hcmQnO1xuICBzaXplUmFuZ2U6ICdzdHJva2VXaWR0aFJhbmdlJztcbn0gPSB7XG4gIG9wYWNpdHk6ICdvcGFjaXR5JyxcbiAgdGhpY2tuZXNzOiB7XG4gICAgdHlwZTogJ251bWJlcicsXG4gICAgZGVmYXVsdFZhbHVlOiBkZWZhdWx0VGhpY2tuZXNzLFxuICAgIGxhYmVsOiAnU3Ryb2tlIFdpZHRoJyxcbiAgICBpc1JhbmdlZDogZmFsc2UsXG4gICAgcmFuZ2U6IFswLCAxMDBdLFxuICAgIHN0ZXA6IDAuMSxcbiAgICBncm91cDogJ3N0cm9rZScsXG4gICAgcHJvcGVydHk6ICd0aGlja25lc3MnXG4gIH0sXG4gIGNvbG9yUmFuZ2U6ICdjb2xvclJhbmdlJyxcbiAgdHJhaWxMZW5ndGg6ICd0cmFpbExlbmd0aCcsXG4gIGZhZGVUcmFpbDogJ2ZhZGVUcmFpbCcsXG4gIGJpbGxib2FyZDogJ2JpbGxib2FyZCcsXG4gIHNpemVSYW5nZTogJ3N0cm9rZVdpZHRoUmFuZ2UnXG59O1xuXG5leHBvcnQgY29uc3QgZmVhdHVyZUFjY2Vzc29yID1cbiAgKHtnZW9qc29ufTogVHJpcExheWVyQ29sdW1uc0NvbmZpZykgPT5cbiAgKGRjOiBEYXRhQ29udGFpbmVySW50ZXJmYWNlKSA9PlxuICBkID0+XG4gICAgZGMudmFsdWVBdChkLmluZGV4LCBnZW9qc29uLmZpZWxkSWR4KTtcbmV4cG9ydCBjb25zdCBmZWF0dXJlUmVzb2x2ZXIgPSAoe2dlb2pzb259OiBUcmlwTGF5ZXJDb2x1bW5zQ29uZmlnKSA9PiBnZW9qc29uLmZpZWxkSWR4O1xuY29uc3QgZ2V0VGFibGVNb2RlVmFsdWVBY2Nlc3NvciA9IGYgPT4ge1xuICAvLyBDYWxsZWQgZnJvbSBncHUtZmlsdGVyLXV0aWxzLmdldEZpbHRlclZhbHVlQWNjZXNzb3IoKVxuICByZXR1cm4gZmllbGQgPT4gZi5wcm9wZXJ0aWVzLnZhbHVlcy5tYXAodiA9PiBmaWVsZC52YWx1ZUFjY2Vzc29yKHYpKTtcbn07XG5jb25zdCBnZXRUYWJsZU1vZGVGaWVsZFZhbHVlID0gKGZpZWxkLCBkYXRhKSA9PiB7XG4gIGxldCBydjtcbiAgaWYgKHR5cGVvZiBkYXRhID09PSAnZnVuY3Rpb24nKSB7XG4gICAgcnYgPSBkYXRhKGZpZWxkKTtcbiAgfSBlbHNlIHtcbiAgICBydiA9IGRlZmF1bHRHZXRGaWVsZFZhbHVlKGZpZWxkLCBkYXRhKTtcbiAgfVxuICByZXR1cm4gcnY7XG59O1xuXG5leHBvcnQgY29uc3QgQ09MVU1OX01PREVfR0VPSlNPTiA9ICdnZW9qc29uJztcbmV4cG9ydCBjb25zdCBDT0xVTU5fTU9ERV9UQUJMRSA9ICd0YWJsZSc7XG5jb25zdCBTVVBQT1JURURfQ09MVU1OX01PREVTID0gW1xuICB7XG4gICAga2V5OiBDT0xVTU5fTU9ERV9HRU9KU09OLFxuICAgIGxhYmVsOiAnR2VvSlNPTicsXG4gICAgcmVxdWlyZWRDb2x1bW5zOiBbJ2dlb2pzb24nXVxuICB9LFxuICB7XG4gICAga2V5OiBDT0xVTU5fTU9ERV9UQUJMRSxcbiAgICBsYWJlbDogJ1RhYmxlIGNvbHVtbnMnLFxuICAgIHJlcXVpcmVkQ29sdW1uczogWydpZCcsICdsYXQnLCAnbG5nJywgJ3RpbWVzdGFtcCddLFxuICAgIG9wdGlvbmFsQ29sdW1uczogWydhbHRpdHVkZSddXG4gIH1cbl07XG5jb25zdCBERUZBVUxUX0NPTFVNTl9NT0RFID0gQ09MVU1OX01PREVfR0VPSlNPTjtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgVHJpcExheWVyIGV4dGVuZHMgTGF5ZXIge1xuICBkZWNsYXJlIHZpc0NvbmZpZ1NldHRpbmdzOiBUcmlwTGF5ZXJWaXNDb25maWdTZXR0aW5ncztcbiAgZGVjbGFyZSBjb25maWc6IFRyaXBMYXllckNvbmZpZztcbiAgZGVjbGFyZSBtZXRhOiBUcmlwTGF5ZXJNZXRhO1xuICBkZWNsYXJlIGRhdGFDb250YWluZXI6IERhdGFDb250YWluZXJJbnRlcmZhY2UgfCBudWxsO1xuXG4gIGRhdGFUb0ZlYXR1cmU6IEdlb2pzb25EYXRhTWFwcztcbiAgZGF0YVRvVGltZVN0YW1wOiBhbnlbXTtcbiAgZ2V0RmVhdHVyZTogKGNvbHVtbnM6IFRyaXBMYXllckNvbHVtbnNDb25maWcpID0+IChkYXRhQ29udGFpbmVyOiBEYXRhQ29udGFpbmVySW50ZXJmYWNlKSA9PiBhbnk7XG4gIF9sYXllckluZm9Nb2RhbDogUmVjb3JkPHN0cmluZywgKCkgPT4gSlNYLkVsZW1lbnQ+O1xuXG4gIGNvbnN0cnVjdG9yKHByb3BzKSB7XG4gICAgc3VwZXIocHJvcHMpO1xuXG4gICAgdGhpcy5kYXRhVG9GZWF0dXJlID0gW107XG4gICAgdGhpcy5kYXRhVG9UaW1lU3RhbXAgPSBbXTtcbiAgICB0aGlzLmRhdGFDb250YWluZXIgPSBudWxsO1xuICAgIHRoaXMucmVnaXN0ZXJWaXNDb25maWcodHJpcFZpc0NvbmZpZ3MpO1xuICAgIHRoaXMuZ2V0RmVhdHVyZSA9IG1lbW9pemUoZmVhdHVyZUFjY2Vzc29yLCBmZWF0dXJlUmVzb2x2ZXIpO1xuICAgIHRoaXMuX2xheWVySW5mb01vZGFsID0ge1xuICAgICAgW0NPTFVNTl9NT0RFX1RBQkxFXTogVHJpcEluZm9Nb2RhbEZhY3RvcnkoQ09MVU1OX01PREVfVEFCTEUpLFxuICAgICAgW0NPTFVNTl9NT0RFX0dFT0pTT05dOiBUcmlwSW5mb01vZGFsRmFjdG9yeShDT0xVTU5fTU9ERV9HRU9KU09OKVxuICAgIH07XG4gIH1cblxuICBnZXQgc3VwcG9ydGVkQ29sdW1uTW9kZXMoKSB7XG4gICAgcmV0dXJuIFNVUFBPUlRFRF9DT0xVTU5fTU9ERVM7XG4gIH1cblxuICBzdGF0aWMgZ2V0IHR5cGUoKTogJ3RyaXAnIHtcbiAgICByZXR1cm4gJ3RyaXAnO1xuICB9XG4gIGdldCB0eXBlKCkge1xuICAgIHJldHVybiBUcmlwTGF5ZXIudHlwZTtcbiAgfVxuXG4gIGdldCBuYW1lKCk6ICdUcmlwJyB7XG4gICAgcmV0dXJuICdUcmlwJztcbiAgfVxuXG4gIGdldCBsYXllckljb24oKSB7XG4gICAgcmV0dXJuIFRyaXBMYXllckljb247XG4gIH1cblxuICBnZXQgY29sdW1uUGFpcnMoKSB7XG4gICAgcmV0dXJuIHRoaXMuZGVmYXVsdFBvaW50Q29sdW1uUGFpcnM7XG4gIH1cblxuICBhY2Nlc3NWU0ZpZWxkVmFsdWUoKSB7XG4gICAgaWYgKHRoaXMuY29uZmlnLmNvbHVtbk1vZGUgPT09IENPTFVNTl9NT0RFX0dFT0pTT04pIHtcbiAgICAgIHJldHVybiBkZWZhdWx0R2V0RmllbGRWYWx1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGdldFRhYmxlTW9kZUZpZWxkVmFsdWU7XG4gIH1cblxuICBnZXQgdmlzdWFsQ2hhbm5lbHMoKSB7XG4gICAgY29uc3QgdmlzdWFsQ2hhbm5lbHMgPSBzdXBlci52aXN1YWxDaGFubmVscztcblxuICAgIHJldHVybiB7XG4gICAgICAuLi52aXN1YWxDaGFubmVscyxcbiAgICAgIGNvbG9yOiB7XG4gICAgICAgIC4uLnZpc3VhbENoYW5uZWxzLmNvbG9yLFxuICAgICAgICBhY2Nlc3NvcjogJ2dldENvbG9yJyxcbiAgICAgICAgbnVsbFZhbHVlOiB2aXN1YWxDaGFubmVscy5jb2xvci5udWxsVmFsdWUsXG4gICAgICAgIGdldEF0dHJpYnV0ZVZhbHVlOiBjb25maWcgPT4gZCA9PiBkLnByb3BlcnRpZXMubGluZUNvbG9yIHx8IGNvbmZpZy5jb2xvcixcbiAgICAgICAgLy8gdXNlZCB0aGlzIHRvIGdldCB1cGRhdGVUcmlnZ2Vyc1xuICAgICAgICBkZWZhdWx0VmFsdWU6IGNvbmZpZyA9PiBjb25maWcuY29sb3JcbiAgICAgIH0sXG4gICAgICBzaXplOiB7XG4gICAgICAgIC4uLnZpc3VhbENoYW5uZWxzLnNpemUsXG4gICAgICAgIHByb3BlcnR5OiAnc3Ryb2tlJyxcbiAgICAgICAgYWNjZXNzb3I6ICdnZXRXaWR0aCcsXG4gICAgICAgIGNvbmRpdGlvbjogY29uZmlnID0+IGNvbmZpZy52aXNDb25maWcuc3Ryb2tlZCxcbiAgICAgICAgbnVsbFZhbHVlOiAwLFxuICAgICAgICBnZXRBdHRyaWJ1dGVWYWx1ZTogKCkgPT4gZCA9PiBkLnByb3BlcnRpZXMubGluZVdpZHRoIHx8IGRlZmF1bHRMaW5lV2lkdGhcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgZ2V0IGFuaW1hdGlvbkRvbWFpbigpIHtcbiAgICByZXR1cm4gdGhpcy5jb25maWcuYW5pbWF0aW9uLmRvbWFpbjtcbiAgfVxuXG4gIGdldCBsYXllckluZm9Nb2RhbCgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgW0NPTFVNTl9NT0RFX0dFT0pTT05dOiB7XG4gICAgICAgIGlkOiAnaWNvbkluZm8nLFxuICAgICAgICB0ZW1wbGF0ZTogdGhpcy5fbGF5ZXJJbmZvTW9kYWxbQ09MVU1OX01PREVfR0VPSlNPTl0sXG4gICAgICAgIG1vZGFsUHJvcHM6IHtcbiAgICAgICAgICB0aXRsZTogJ21vZGFsLnRyaXBJbmZvLnRpdGxlJ1xuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgW0NPTFVNTl9NT0RFX1RBQkxFXToge1xuICAgICAgICBpZDogJ2ljb25JbmZvJyxcbiAgICAgICAgdGVtcGxhdGU6IHRoaXMuX2xheWVySW5mb01vZGFsW0NPTFVNTl9NT0RFX1RBQkxFXSxcbiAgICAgICAgbW9kYWxQcm9wczoge1xuICAgICAgICAgIHRpdGxlOiAnbW9kYWwudHJpcEluZm8udGl0bGVUYWJsZSdcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG4gIH1cblxuICBnZXRQb3NpdGlvbkFjY2Vzc29yKGRhdGFDb250YWluZXI6IERhdGFDb250YWluZXJJbnRlcmZhY2UpIHtcbiAgICBpZiAodGhpcy5jb25maWcuY29sdW1uTW9kZSA9PT0gQ09MVU1OX01PREVfR0VPSlNPTikge1xuICAgICAgcmV0dXJuIHRoaXMuZ2V0RmVhdHVyZSh0aGlzLmNvbmZpZy5jb2x1bW5zKShkYXRhQ29udGFpbmVyKTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBzdGF0aWMgZmluZERlZmF1bHRMYXllclByb3BzKFxuICAgIHtsYWJlbCwgZmllbGRzID0gW10sIGRhdGFDb250YWluZXIsIGlkfTogS2VwbGVyVGFibGUsXG4gICAgZm91bmRMYXllcnM/OiBhbnlbXVxuICApIHtcbiAgICBjb25zdCBnZW9qc29uQ29sdW1ucyA9IGZpZWxkcy5maWx0ZXIoZiA9PiBmLnR5cGUgPT09ICdnZW9qc29uJykubWFwKGYgPT4gZi5uYW1lKTtcblxuICAgIGNvbnN0IGRlZmF1bHRDb2x1bW5zID0ge1xuICAgICAgZ2VvanNvbjogdW5pcShbLi4uR0VPSlNPTl9GSUVMRFMuZ2VvanNvbiwgLi4uZ2VvanNvbkNvbHVtbnNdKVxuICAgIH07XG5cbiAgICBjb25zdCBnZW9Kc29uQ29sdW1ucyA9IHRoaXMuZmluZERlZmF1bHRDb2x1bW5GaWVsZChkZWZhdWx0Q29sdW1ucywgZmllbGRzKTtcblxuICAgIGNvbnN0IHRyaXBHZW9qc29uQ29sdW1ucyA9IChnZW9Kc29uQ29sdW1ucyB8fCBbXSkuZmlsdGVyKGNvbCA9PlxuICAgICAgaXNUcmlwR2VvSnNvbkZpZWxkKGRhdGFDb250YWluZXIsIGZpZWxkc1tjb2wuZ2VvanNvbi5maWVsZElkeF0pXG4gICAgKTtcblxuICAgIGlmICh0cmlwR2VvanNvbkNvbHVtbnMubGVuZ3RoKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBwcm9wczogdHJpcEdlb2pzb25Db2x1bW5zLm1hcChjb2x1bW5zID0+ICh7XG4gICAgICAgICAgbGFiZWw6ICh0eXBlb2YgbGFiZWwgPT09ICdzdHJpbmcnICYmIGxhYmVsLnJlcGxhY2UoL1xcLlteLy5dKyQvLCAnJykpIHx8IHRoaXMudHlwZSxcbiAgICAgICAgICBjb2x1bW5zLFxuICAgICAgICAgIGlzVmlzaWJsZTogdHJ1ZSxcbiAgICAgICAgICBjb2x1bW5Nb2RlOiBDT0xVTU5fTU9ERV9HRU9KU09OXG4gICAgICAgIH0pKSxcblxuICAgICAgICAvLyBpZiBhIGdlb2pzb24gbGF5ZXIgaXMgY3JlYXRlZCBmcm9tIHRoaXMgY29sdW1uLCBkZWxldGUgaXRcbiAgICAgICAgZm91bmRMYXllcnM6IGZvdW5kTGF5ZXJzPy5maWx0ZXIoXG4gICAgICAgICAgcHJvcCA9PlxuICAgICAgICAgICAgcHJvcC50eXBlICE9PSAnZ2VvanNvbicgfHxcbiAgICAgICAgICAgIHByb3AuZGF0YUlkICE9PSBpZCB8fFxuICAgICAgICAgICAgIXRyaXBHZW9qc29uQ29sdW1ucy5maW5kKGMgPT4gcHJvcC5jb2x1bW5zLmdlb2pzb24ubmFtZSA9PT0gYy5nZW9qc29uLm5hbWUpXG4gICAgICAgIClcbiAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIHtwcm9wczogW119O1xuICB9XG5cbiAgZ2V0RGVmYXVsdExheWVyQ29uZmlnKHByb3BzKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLnN1cGVyLmdldERlZmF1bHRMYXllckNvbmZpZyhwcm9wcyksXG4gICAgICBjb2x1bW5Nb2RlOiBwcm9wcz8uY29sdW1uTW9kZSA/PyBERUZBVUxUX0NPTFVNTl9NT0RFLFxuICAgICAgYW5pbWF0aW9uOiB7XG4gICAgICAgIGVuYWJsZWQ6IHRydWUsXG4gICAgICAgIGRvbWFpbjogbnVsbFxuICAgICAgfVxuICAgIH07XG4gIH1cblxuICBnZXRIb3ZlckRhdGEob2JqZWN0LCBkYXRhQ29udGFpbmVyOiBEYXRhQ29udGFpbmVySW50ZXJmYWNlLCBmaWVsZHMsIGFuaW1hdGlvbkNvbmZpZykge1xuICAgIGlmICh0aGlzLmNvbmZpZy5jb2x1bW5Nb2RlID09PSBDT0xVTU5fTU9ERV9HRU9KU09OKSB7XG4gICAgICAvLyBpbmRleCBmb3IgZGF0YUNvbnRhaW5lciBpcyBzYXZlZCB0byBmZWF0dXJlLnByb3BlcnRpZXNcbiAgICAgIHJldHVybiBkYXRhQ29udGFpbmVyLnJvdyhvYmplY3QucHJvcGVydGllcy5pbmRleCk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLl9maW5kQ29sdW1uTW9kZURhdHVtRm9yRmVhdHVyZShvYmplY3QucHJvcGVydGllcy5pbmRleCwgYW5pbWF0aW9uQ29uZmlnLmN1cnJlbnRUaW1lKVxuICAgICAgPy5kYXR1bTtcbiAgfVxuXG4gIGNhbGN1bGF0ZURhdGFBdHRyaWJ1dGUoZGF0YXNldDogS2VwbGVyVGFibGUpIHtcbiAgICBzd2l0Y2ggKHRoaXMuY29uZmlnLmNvbHVtbk1vZGUpIHtcbiAgICAgIGNhc2UgQ09MVU1OX01PREVfR0VPSlNPTjoge1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgIGRhdGFzZXQuZmlsdGVyZWRJbmRleFxuICAgICAgICAgICAgLm1hcChpID0+IHRoaXMuZGF0YVRvRmVhdHVyZVtpXSlcbiAgICAgICAgICAgIC8vIFRPRE8gZCBjYW4gYmUgQmluYXJ5RmVhdHVyZUNvbGxlY3Rpb24sIGZpeCBsb2dpY1xuICAgICAgICAgICAgLmZpbHRlcihkID0+IGQgJiYgKGQgYXMgYW55KS5nZW9tZXRyeT8udHlwZSA9PT0gJ0xpbmVTdHJpbmcnKVxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICBjYXNlIENPTFVNTl9NT0RFX1RBQkxFOlxuICAgICAgICByZXR1cm4gYXBwbHlGaWx0ZXJzVG9UYWJsZUNvbHVtbnMoZGF0YXNldCwgdGhpcy5kYXRhVG9GZWF0dXJlKTtcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgfVxuXG4gIGZvcm1hdExheWVyRGF0YShkYXRhc2V0czogRGF0YXNldHMsIG9sZExheWVyRGF0YSkge1xuICAgIGlmICh0aGlzLmNvbmZpZy5kYXRhSWQgPT09IG51bGwpIHtcbiAgICAgIHJldHVybiB7fTtcbiAgICB9XG4gICAgLy8gdG8tZG86IHBhcnNlIHNlZ21lbnQgZnJvbSBkYXRhQ29udGFpbmVyXG5cbiAgICBjb25zdCB7ZGF0YUNvbnRhaW5lciwgZ3B1RmlsdGVyfSA9IGRhdGFzZXRzW3RoaXMuY29uZmlnLmRhdGFJZF07XG4gICAgY29uc3Qge2RhdGF9ID0gdGhpcy51cGRhdGVEYXRhKGRhdGFzZXRzLCBvbGRMYXllckRhdGEpO1xuXG4gICAgbGV0IHZhbHVlQWNjZXNzb3I7XG4gICAgaWYgKHRoaXMuY29uZmlnLmNvbHVtbk1vZGUgPT09IENPTFVNTl9NT0RFX0dFT0pTT04pIHtcbiAgICAgIHZhbHVlQWNjZXNzb3IgPSAoZGM6IERhdGFDb250YWluZXJJbnRlcmZhY2UsIGYsIGZpZWxkSW5kZXg6IG51bWJlcikgPT4ge1xuICAgICAgICByZXR1cm4gZGMudmFsdWVBdChmLnByb3BlcnRpZXMuaW5kZXgsIGZpZWxkSW5kZXgpO1xuICAgICAgfTtcbiAgICB9IGVsc2Uge1xuICAgICAgdmFsdWVBY2Nlc3NvciA9IGdldFRhYmxlTW9kZVZhbHVlQWNjZXNzb3I7XG4gICAgfVxuICAgIGNvbnN0IGluZGV4QWNjZXNzb3IgPSBmID0+IGYucHJvcGVydGllcy5pbmRleDtcbiAgICBjb25zdCBkYXRhQWNjZXNzb3IgPSAoKSA9PiBkID0+ICh7aW5kZXg6IGQucHJvcGVydGllcy5pbmRleH0pO1xuICAgIGNvbnN0IGFjY2Vzc29ycyA9IHRoaXMuZ2V0QXR0cmlidXRlQWNjZXNzb3JzKHtkYXRhQWNjZXNzb3IsIGRhdGFDb250YWluZXJ9KTtcbiAgICBjb25zdCBnZXRGaWx0ZXJWYWx1ZSA9IGdwdUZpbHRlci5maWx0ZXJWYWx1ZUFjY2Vzc29yKGRhdGFDb250YWluZXIpKFxuICAgICAgaW5kZXhBY2Nlc3NvcixcbiAgICAgIHZhbHVlQWNjZXNzb3JcbiAgICApO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGRhdGEsXG4gICAgICBnZXRGaWx0ZXJWYWx1ZSxcbiAgICAgIGdldFBhdGg6IGQgPT4gZC5nZW9tZXRyeS5jb29yZGluYXRlcyxcbiAgICAgIGdldFRpbWVzdGFtcHM6IGQgPT4gdGhpcy5kYXRhVG9UaW1lU3RhbXBbZC5wcm9wZXJ0aWVzLmluZGV4XSxcbiAgICAgIC4uLmFjY2Vzc29yc1xuICAgIH07XG4gIH1cblxuICB1cGRhdGVBbmltYXRpb25Eb21haW4oZG9tYWluKSB7XG4gICAgdGhpcy51cGRhdGVMYXllckNvbmZpZyh7XG4gICAgICBhbmltYXRpb246IHtcbiAgICAgICAgLi4udGhpcy5jb25maWcuYW5pbWF0aW9uLFxuICAgICAgICBkb21haW5cbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIHVwZGF0ZUxheWVyTWV0YShkYXRhc2V0OiBLZXBsZXJUYWJsZSkge1xuICAgIGNvbnN0IHtkYXRhQ29udGFpbmVyfSA9IGRhdGFzZXQ7XG4gICAgbGV0IGdldEZlYXR1cmU7XG4gICAgaWYgKHRoaXMuY29uZmlnLmNvbHVtbk1vZGUgPT09IENPTFVNTl9NT0RFX0dFT0pTT04pIHtcbiAgICAgIGdldEZlYXR1cmUgPSB0aGlzLmdldFBvc2l0aW9uQWNjZXNzb3IoZGF0YUNvbnRhaW5lcik7XG4gICAgICBpZiAoZ2V0RmVhdHVyZSA9PT0gdGhpcy5tZXRhLmdldEZlYXR1cmUpIHtcbiAgICAgICAgLy8gVE9ETzogcmV2aXNpdCB0aGlzIGFmdGVyIGdwdSBmaWx0ZXJpbmdcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgdGhpcy5kYXRhVG9GZWF0dXJlID0gZ2V0R2VvanNvbkRhdGFNYXBzKGRhdGFDb250YWluZXIsIGdldEZlYXR1cmUpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmRhdGFDb250YWluZXIgPSBkYXRhQ29udGFpbmVyO1xuICAgICAgdGhpcy5kYXRhVG9GZWF0dXJlID0gZ3JvdXBDb2x1bW5zQXNHZW9Kc29uKGRhdGFDb250YWluZXIsIHRoaXMuY29uZmlnLmNvbHVtbnMsICd0aW1lc3RhbXAnKTtcbiAgICB9XG5cbiAgICBjb25zdCB7ZGF0YVRvVGltZVN0YW1wLCBhbmltYXRpb25Eb21haW59ID0gcGFyc2VUcmlwR2VvSnNvblRpbWVzdGFtcCh0aGlzLmRhdGFUb0ZlYXR1cmUpO1xuXG4gICAgdGhpcy5kYXRhVG9UaW1lU3RhbXAgPSBkYXRhVG9UaW1lU3RhbXA7XG4gICAgdGhpcy51cGRhdGVBbmltYXRpb25Eb21haW4oYW5pbWF0aW9uRG9tYWluKTtcblxuICAgIC8vIGdldCBib3VuZHMgZnJvbSBmZWF0dXJlc1xuICAgIGNvbnN0IGJvdW5kcyA9IGdldEdlb2pzb25Cb3VuZHModGhpcy5kYXRhVG9GZWF0dXJlKTtcblxuICAgIC8vIGtlZXAgYSByZWNvcmQgb2Ygd2hhdCB0eXBlIG9mIGdlb21ldHJ5IHRoZSBjb2xsZWN0aW9uIGhhc1xuICAgIGNvbnN0IGZlYXR1cmVUeXBlcyA9IGdldEdlb2pzb25GZWF0dXJlVHlwZXModGhpcy5kYXRhVG9GZWF0dXJlKTtcblxuICAgIHRoaXMudXBkYXRlTWV0YSh7Ym91bmRzLCBmZWF0dXJlVHlwZXMsIGdldEZlYXR1cmV9KTtcbiAgfVxuXG4gIHNldEluaXRpYWxMYXllckNvbmZpZyhkYXRhc2V0KSB7XG4gICAgY29uc3Qge2RhdGFDb250YWluZXJ9ID0gZGF0YXNldDtcbiAgICBpZiAoIWRhdGFDb250YWluZXIubnVtUm93cygpKSB7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICAvLyBkZWZlZmF1bHRMYXllclByb3BzIHdpbGwgYXV0b21hdGljYWxseSBmaW5kIGdlb2pzb24gY29sdW1uXG4gICAgLy8gaWYgbm90IGZvdW5kLCB3ZSB0cnkgdG8gc2V0IGl0IHRvIGlkIC8gbGF0IC9sbmcgL3RzXG4gICAgaWYgKCF0aGlzLmNvbmZpZy5jb2x1bW5zLmdlb2pzb24udmFsdWUpIHtcbiAgICAgIC8vIGZpbmQgY29sdW1ucyBmcm9tIGxhdCwgbG5nLCBpZCwgYW5kIHRzXG4gICAgICBjb25zdCBjb2x1bW5Db25maWcgPSBkZXRlY3RUYWJsZUNvbHVtbnMoZGF0YXNldCwgdGhpcy5jb25maWcuY29sdW1ucyk7XG4gICAgICBpZiAoY29sdW1uQ29uZmlnKSB7XG4gICAgICAgIHRoaXMudXBkYXRlTGF5ZXJDb25maWcoe1xuICAgICAgICAgIC4uLmNvbHVtbkNvbmZpZyxcbiAgICAgICAgICBjb2x1bW5Nb2RlOiBDT0xVTU5fTU9ERV9UQUJMRVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMudXBkYXRlTGF5ZXJNZXRhKGRhdGFzZXQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgcmVuZGVyTGF5ZXIob3B0cykge1xuICAgIGNvbnN0IHtkYXRhLCBncHVGaWx0ZXIsIG1hcFN0YXRlLCBhbmltYXRpb25Db25maWd9ID0gb3B0cztcbiAgICBjb25zdCB7dmlzQ29uZmlnfSA9IHRoaXMuY29uZmlnO1xuICAgIGNvbnN0IHpvb21GYWN0b3IgPSB0aGlzLmdldFpvb21GYWN0b3IobWFwU3RhdGUpO1xuICAgIGNvbnN0IGlzVmFsaWRUaW1lID1cbiAgICAgIGFuaW1hdGlvbkNvbmZpZyAmJlxuICAgICAgQXJyYXkuaXNBcnJheShhbmltYXRpb25Db25maWcuZG9tYWluKSAmJlxuICAgICAgYW5pbWF0aW9uQ29uZmlnLmRvbWFpbi5ldmVyeShOdW1iZXIuaXNGaW5pdGUpICYmXG4gICAgICBOdW1iZXIuaXNGaW5pdGUoYW5pbWF0aW9uQ29uZmlnLmN1cnJlbnRUaW1lKTtcblxuICAgIGlmICghaXNWYWxpZFRpbWUpIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG5cbiAgICBjb25zdCBkb21haW4wID0gYW5pbWF0aW9uQ29uZmlnLmRvbWFpbj8uWzBdO1xuXG4gICAgY29uc3QgZ3B1RmlsdGVyVXBkYXRlVHJpZ2dlcnMgPSB7Z2V0RmlsdGVyVmFsdWU6IGdwdUZpbHRlci5maWx0ZXJWYWx1ZVVwZGF0ZVRyaWdnZXJzfTtcbiAgICBjb25zdCB1cGRhdGVUcmlnZ2VycyA9IHtcbiAgICAgIC4uLnRoaXMuZ2V0VmlzdWFsQ2hhbm5lbFVwZGF0ZVRyaWdnZXJzKCksXG4gICAgICBnZXRUaW1lc3RhbXBzOiB7XG4gICAgICAgIGNvbHVtbnM6IHRoaXMuY29uZmlnLmNvbHVtbnMsXG4gICAgICAgIGRvbWFpbjBcbiAgICAgIH0sXG4gICAgICAuLi5ncHVGaWx0ZXJVcGRhdGVUcmlnZ2Vyc1xuICAgIH07XG4gICAgY29uc3QgZGVmYXVsdExheWVyUHJvcHMgPSB0aGlzLmdldERlZmF1bHREZWNrTGF5ZXJQcm9wcyhvcHRzKTtcblxuICAgIGNvbnN0IGJpbGxib2FyZFdpZHRoRmFjdG9yID0gdmlzQ29uZmlnLmJpbGxib2FyZCA/IFBST0pFQ1RFRF9QSVhFTF9TSVpFX01VTFRJUExJRVIgOiAxO1xuXG4gICAgY29uc3QgbGF5ZXJQcm9wcyA9IHtcbiAgICAgIC4uLmRlZmF1bHRMYXllclByb3BzLFxuICAgICAgLi4uZGF0YSxcbiAgICAgIGdldFRpbWVzdGFtcHM6IGQgPT4gKGRhdGEuZ2V0VGltZXN0YW1wcyhkKSB8fCBbXSkubWFwKHRzID0+IHRzIC0gZG9tYWluMCksXG4gICAgICB3aWR0aFNjYWxlOiB2aXNDb25maWcudGhpY2tuZXNzICogem9vbUZhY3RvciAqIHpvb21GYWN0b3JWYWx1ZSAqIGJpbGxib2FyZFdpZHRoRmFjdG9yLFxuICAgICAgY2FwUm91bmRlZDogdHJ1ZSxcbiAgICAgIGpvaW50Um91bmRlZDogdHJ1ZSxcbiAgICAgIHdyYXBMb25naXR1ZGU6IGZhbHNlLFxuICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICBkZXB0aFRlc3Q6IG1hcFN0YXRlLmRyYWdSb3RhdGUsXG4gICAgICAgIGRlcHRoTWFzazogZmFsc2VcbiAgICAgIH0sXG4gICAgICB0cmFpbExlbmd0aDogdmlzQ29uZmlnLnRyYWlsTGVuZ3RoICogMTAwMCxcbiAgICAgIGZhZGVUcmFpbDogdmlzQ29uZmlnLmZhZGVUcmFpbCxcbiAgICAgIGJpbGxib2FyZDogdmlzQ29uZmlnLmJpbGxib2FyZCxcbiAgICAgIC8vIFRPRE86IGdpdXNlcHBlIHRoaXMgdmFsdWVzIGJlY29tZXMgbmVnYXRpdmVcbiAgICAgIGN1cnJlbnRUaW1lOiBhbmltYXRpb25Db25maWcuY3VycmVudFRpbWUgLSBkb21haW4wLFxuICAgICAgdXBkYXRlVHJpZ2dlcnMsXG4gICAgICBpZDogYCR7ZGVmYXVsdExheWVyUHJvcHMuaWR9JHttYXBTdGF0ZS5nbG9iZT8uZW5hYmxlZCA/ICctZ2xvYmUnIDogJyd9YFxuICAgIH07XG4gICAgcmV0dXJuIFtuZXcgRGVja0dMVHJpcHNMYXllcihsYXllclByb3BzKV07XG4gIH1cblxuICAvKipcbiAgICogRmluZHMgY29vcmRpbmF0ZXMgYW5kIGRhdHVtIGF0IHRoZSBjdXJyZW50IGFuaW1hdGlvbiB0aW1lIGJ5IHRoZSBzcGVjaWZpZWQgZmVhdHVyZSBpbmRleC5cbiAgICogQHBhcmFtIGZlYXR1cmVJbmRleFxuICAgKiBAcGFyYW0gdGltZVxuICAgKiBAcmV0dXJucyB7e2RhdHVtOiAobnVsbHxzdHJpbmd8KiksIGlkeDogKiwgY29vcmRzfXx7ZGF0dW06IG51bGwsIGlkeDogbnVtYmVyLCBjb29yZHM6IG51bGx9fVxuICAgKi9cbiAgcHJpdmF0ZSBfZmluZENvbHVtbk1vZGVEYXR1bUZvckZlYXR1cmUoXG4gICAgZmVhdHVyZUluZGV4OiBudW1iZXIsXG4gICAgdGltZTogbnVtYmVyXG4gICk6IHtcbiAgICBpZHg6IG51bWJlcjtcbiAgICBjb29yZHM6IG51bWJlcltdIHwgbnVsbDtcbiAgICBkYXR1bTogYW55O1xuICB9IHtcbiAgICBpZiAodGhpcy5jb25maWcuY29sdW1uTW9kZSA9PT0gQ09MVU1OX01PREVfVEFCTEUpIHtcbiAgICAgIGNvbnN0IG9iamVjdCA9IHRoaXMuZGF0YVRvRmVhdHVyZVtmZWF0dXJlSW5kZXhdO1xuICAgICAgY29uc3QgaWR4ID0gYmlzZWN0UmlnaHQodGhpcy5kYXRhVG9UaW1lU3RhbXBbZmVhdHVyZUluZGV4XSwgdGltZSk7XG4gICAgICAvLyBAdHMtZXhwZWN0LWVycm9yIHR5cGUgZ2VvbWV0cnk/XG4gICAgICBjb25zdCB7Y29vcmRpbmF0ZXN9ID0gb2JqZWN0Py5nZW9tZXRyeSB8fCB7Y29vcmRpbmF0ZXM6IFtdfTtcbiAgICAgIGlmIChpZHggPj0gMCAmJiBpZHggPCBjb29yZGluYXRlcy5sZW5ndGgpIHtcbiAgICAgICAgY29uc3QgY29vcmRzID0gY29vcmRpbmF0ZXNbaWR4XTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBpZHgsXG4gICAgICAgICAgY29vcmRzLFxuICAgICAgICAgIGRhdHVtOiBjb29yZHM/LmRhdHVtXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICBpZHg6IC0xLFxuICAgICAgY29vcmRzOiBudWxsLFxuICAgICAgZGF0dW06IG51bGxcbiAgICB9O1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7QUFHQSxJQUFBQSxRQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBQyxLQUFBLEdBQUFGLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBRSxVQUFBLEdBQUFDLHVCQUFBLENBQUFILE9BQUE7QUFDQSxJQUFBSSxVQUFBLEdBQUFKLE9BQUE7QUFFQSxJQUFBSyxVQUFBLEdBQUFMLE9BQUE7QUFDQSxJQUFBTSxjQUFBLEdBQUFQLHNCQUFBLENBQUFDLE9BQUE7QUFFQSxJQUFBTyxhQUFBLEdBQUFQ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