UNPKG

kepler.gl

Version:

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

446 lines (433 loc) 62.5 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.FeatureTypes = exports.COLUMN_MODE_GEOJSON = void 0; exports.applyFiltersToTableColumns = applyFiltersToTableColumns; exports.detectTableColumns = detectTableColumns; exports.featureToDeckGlGeoType = void 0; exports.fieldIsGeoArrow = fieldIsGeoArrow; exports.getGeojsonBounds = getGeojsonBounds; exports.getGeojsonDataMaps = getGeojsonDataMaps; exports.getGeojsonFeatureTypes = getGeojsonFeatureTypes; exports.getGeojsonLayerMeta = getGeojsonLayerMeta; exports.getGeojsonPointDataMaps = getGeojsonPointDataMaps; exports.groupColumnsAsGeoJson = groupColumnsAsGeoJson; exports.parseGeoJsonRawFeature = parseGeoJsonRawFeature; var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _buffer = require("buffer"); var _geojsonNormalize = _interopRequireDefault(require("@mapbox/geojson-normalize")); var _bbox = _interopRequireDefault(require("@turf/bbox")); var _d3Array = require("d3-array"); var _center = _interopRequireDefault(require("@turf/center")); var _core = require("@loaders.gl/core"); var _wkt = require("@loaders.gl/wkt"); var _gis = require("@loaders.gl/gis"); var _utils = require("@kepler.gl/utils"); var _constants = require("@kepler.gl/constants"); var _layerUtils = require("../layer-utils"); function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return 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; } // SPDX-License-Identifier: MIT // Copyright contributors to the kepler.gl project var COLUMN_MODE_GEOJSON = exports.COLUMN_MODE_GEOJSON = 'geojson'; /* eslint-disable */ // TODO: Re-enable eslint when we upgrade to handle enums and type maps var FeatureTypes = exports.FeatureTypes = /*#__PURE__*/function (FeatureTypes) { FeatureTypes["Point"] = "Point"; FeatureTypes["MultiPoint"] = "MultiPoint"; FeatureTypes["LineString"] = "LineString"; FeatureTypes["MultiLineString"] = "MultiLineString"; FeatureTypes["Polygon"] = "Polygon"; FeatureTypes["MultiPolygon"] = "MultiPolygon"; return FeatureTypes; }({}); // @ts-expect-error return type of getGeojsonFeatureTypes ? /* eslint-enable */ /** * Returns true if the field has geoarrow extension. * @param geoField A field to test. * @returns */ function fieldIsGeoArrow(geoField) { var _geoField$metadata; return Boolean(geoField === null || geoField === void 0 || (_geoField$metadata = geoField.metadata) === null || _geoField$metadata === void 0 ? void 0 : _geoField$metadata.get('ARROW:extension:name')); } function parseGeoJsonRawFeature(rawFeature) { var properties = null; // help ensure that properties is present on the returned geojson feature // Support WKB geometry provided as binary (e.g., from Parquet/GeoParquet) if (rawFeature instanceof Uint8Array || rawFeature instanceof ArrayBuffer) { try { var binaryInput = rawFeature instanceof ArrayBuffer ? rawFeature : rawFeature.buffer.slice(rawFeature.byteOffset, rawFeature.byteOffset + rawFeature.byteLength); var binaryGeo = (0, _core.parseSync)(binaryInput, _wkt.WKBLoader); // @ts-expect-error loaders.gl binary type to GeoJSON geometry var parsedGeo = (0, _gis.binaryToGeometry)(binaryGeo); var normalized = (0, _geojsonNormalize["default"])(parsedGeo); if (!normalized || !Array.isArray(normalized.features) || !normalized.features.length) { return null; } return _objectSpread({ properties: properties }, normalized.features[0]); } catch (e) { return null; } } if ((0, _typeof2["default"])(rawFeature) === 'object') { // Support GeoJson feature as object // probably need to normalize it as well var _normalized = (0, _geojsonNormalize["default"])(rawFeature); if (!_normalized || !Array.isArray(_normalized.features)) { // fail to normalize GeoJson return null; } return _objectSpread({ properties: properties }, _normalized.features[0]); } else if (typeof rawFeature === 'string') { var parsedGeometry = parseGeometryFromString(rawFeature); if (!parsedGeometry) return null; // @ts-expect-error verify whether parsedGeometry always contains properties return _objectSpread({ properties: properties }, parsedGeometry); } else if (Array.isArray(rawFeature)) { // Support GeoJson LineString as an array of points return { type: 'Feature', geometry: { // why do we need to flip it... coordinates: rawFeature.map(function (pts) { return [pts[1], pts[0]]; }), type: 'LineString' }, properties: properties }; } return null; } function getGeojsonLayerMeta(_ref) { var dataContainer = _ref.dataContainer, getFeature = _ref.getFeature, config = _ref.config; var dataToFeature = config.columnMode === COLUMN_MODE_GEOJSON ? getGeojsonDataMaps(dataContainer, getFeature) : // COLUMN_MODE_TABLE groupColumnsAsGeoJson(dataContainer, config.columns, 'sortBy'); // get bounds from features var bounds = getGeojsonBounds(dataToFeature); // if any of the feature has properties.radius set to be true var fixedRadius = Boolean(dataToFeature.find(function (d) { var _d$properties; return d && 'properties' in d && ((_d$properties = d.properties) === null || _d$properties === void 0 ? void 0 : _d$properties.radius); })); // keep a record of what type of geometry the collection has var featureTypes = getGeojsonFeatureTypes(dataToFeature); var meanCenters = []; for (var i = 0; i < dataToFeature.length; i++) { var feature = dataToFeature[i]; if (feature) { try { // TODO: use line interpolate to get center of line for LineString var cent = (0, _center["default"])(feature); meanCenters.push(cent.geometry.coordinates); } catch (e) { meanCenters.push(null); } } } return { dataToFeature: dataToFeature, bounds: bounds, fixedRadius: fixedRadius, featureTypes: featureTypes, centroids: meanCenters }; } /** * Parse raw data to GeoJson feature */ function getGeojsonDataMaps(dataContainer, getFeature) { var acceptableTypes = ['Point', 'MultiPoint', 'LineString', 'MultiLineString', 'Polygon', 'MultiPolygon', 'GeometryCollection']; var dataToFeature = []; for (var index = 0; index < dataContainer.numRows(); index++) { var feature = parseGeoJsonRawFeature(getFeature({ index: index })); if (feature && feature.geometry && acceptableTypes.includes(feature.geometry.type)) { var cleaned = _objectSpread(_objectSpread({}, feature), {}, { // store index of the data in feature properties properties: _objectSpread(_objectSpread({}, feature.properties), {}, { index: index }) }); dataToFeature[index] = cleaned; } else { dataToFeature[index] = null; } } return dataToFeature; } /** * Parse raw data to GeoJson point feature coordinates */ function getGeojsonPointDataMaps(dataContainer, getFeature) { var acceptableTypes = ['Point', 'MultiPoint', 'GeometryCollection']; var dataToFeature = []; for (var index = 0; index < dataContainer.numRows(); index++) { var feature = parseGeoJsonRawFeature(getFeature(dataContainer.rowAsArray(index))); if (feature && feature.geometry && acceptableTypes.includes(feature.geometry.type)) { dataToFeature[index] = feature.geometry.type === 'Point' || feature.geometry.type === 'MultiPoint' ? feature.geometry.coordinates : // @ts-expect-error Property 'geometries' does not exist on type 'LineString' (feature.geometry.geometries || []).reduce(function (accu, f) { if (f.type === 'Point') { accu.push(f.coordinates); } else if (f.type === 'MultiPoint') { accu.push.apply(accu, (0, _toConsumableArray2["default"])(f.coordinates)); } return accu; }, []); } else { dataToFeature[index] = null; } } return dataToFeature; } /** * Parse geojson from string * @param {String} geoString * @returns {null | Object} geojson object or null if failed */ function parseGeometryFromString(geoString) { var parsedGeo; // try parse as geojson string // {"type":"Polygon","coordinates":[[[-74.158491,40.83594]]]} try { parsedGeo = JSON.parse(geoString); } catch (e) { // keep trying to parse } // try parse as wkt using loaders.gl WKTLoader if (!parsedGeo) { try { parsedGeo = (0, _core.parseSync)(geoString, _wkt.WKTLoader); } catch (e) { return null; } } // try parse as wkb using loaders.gl WKBLoader if (!parsedGeo) { try { var buffer = _buffer.Buffer.from(geoString, 'hex'); var binaryGeo = (0, _core.parseSync)(buffer, _wkt.WKBLoader); // @ts-expect-error parsedGeo = (0, _gis.binaryToGeometry)(binaryGeo); } catch (e) { return null; } } if (!parsedGeo) { return null; } var normalized = (0, _geojsonNormalize["default"])(parsedGeo); if (!normalized || !Array.isArray(normalized.features)) { // fail to normalize geojson return null; } return normalized.features[0]; } /** * Get geojson bounds */ function getGeojsonBounds() { var features = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; // 70 ms for 10,000 polygons // here we only pick couple var maxCount = 10000; var samples = features.length > maxCount ? (0, _utils.getSampleData)(features, maxCount) : features; var validSingleGeometry = function validSingleGeometry(geom) { return geom.coordinates && geom.coordinates.length; }; var validGeometryCollection = function validGeometryCollection(geom) { return geom.geometries && geom.geometries.length && geom.geometries.every(validSingleGeometry); }; var nonEmpty = samples.filter(function (d) { return d && d.geometry && (validSingleGeometry(d.geometry) || validGeometryCollection(d.geometry)); }); try { return (0, _bbox["default"])({ type: 'FeatureCollection', features: nonEmpty }); } catch (e) { return null; } } var featureToDeckGlGeoType = exports.featureToDeckGlGeoType = { Point: 'point', MultiPoint: 'point', LineString: 'line', MultiLineString: 'line', Polygon: 'polygon', MultiPolygon: 'polygon' }; /** * Parse geojson from string */ function getGeojsonFeatureTypes(allFeatures) { // @ts-expect-error some test cases only have 1 geotype var featureTypes = {}; for (var f = 0; f < allFeatures.length; f++) { var feature = allFeatures[f]; if (feature && 'geometry' in feature) { var geoType = featureToDeckGlGeoType[feature.geometry && feature.geometry.type]; if (geoType) { featureTypes[geoType] = true; } } } return featureTypes; } function groupColumnsAsGeoJson(dataContainer, columns) { var sortByColumn = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'timestamp'; var groupedById = {}; var sortByFieldIdx = columns[sortByColumn].fieldIdx; var sortByRequired = !columns[sortByColumn].optional; for (var index = 0; index < dataContainer.numRows(); index++) { // note: can materialize the row var datum = dataContainer.rowAsArray(index); var id = datum[columns.id.fieldIdx]; var lat = datum[columns.lat.fieldIdx]; var lon = datum[columns.lng.fieldIdx]; var altitude = columns.altitude ? datum[columns.altitude.fieldIdx] : 0; var sortBy = sortByFieldIdx > -1 ? datum[sortByFieldIdx] : null; // @ts-expect-error var coords = [lon, lat, altitude, sortBy]; // Adding references to the original data to the coordinates array coords.datumIndex = index; coords.datum = datum; if (!groupedById[id]) groupedById[id] = []; if (Number.isFinite(lon) && Number.isFinite(lat) && (!sortByRequired || sortByRequired && sortBy)) { // only push points if lat,lng,and sortby exist groupedById[id].push(coords); } } var result = Object.entries(groupedById).map( // eslint-disable-next-line @typescript-eslint/no-unused-vars function (_ref2, index) { var _ref3 = (0, _slicedToArray2["default"])(_ref2, 2), _ = _ref3[0], items = _ref3[1]; return { type: 'Feature', geometry: { type: 'LineString', // Sort by columns if has sortByField // TODO: items are expected in Position[] format? coordinates: sortByFieldIdx > -1 ? items.sort(function (a, b) { return (0, _d3Array.ascending)(a[3], b[3]); }) : items }, properties: { index: index, // values are used for valueAccessor in TripLayer.formatLayerData() // Note: this can cause row materialization in case of non-row based containers values: items.map(function (item) { return dataContainer.rowAsArray(item.datumIndex); }) } }; }); return result; } /** * Find id / ts / lat / lng columns from a table and assign it to layer columns */ function detectTableColumns(dataset, layerColumns) { var sortBy = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'timestamp'; var fields = dataset.fields, fieldPairs = dataset.fieldPairs; if (!fieldPairs.length || !fields.length) { return null; } // find sort by field var sortByFieldIdx = fields.findIndex(function (f) { return f.type === _constants.ALL_FIELD_TYPES.timestamp; }); // find id column var idFieldIdx = fields.findIndex(function (f) { var _f$name; return (_f$name = f.name) === null || _f$name === void 0 ? void 0 : _f$name.toLowerCase().match(/^(id|uuid)$/g); }); if (sortByFieldIdx > -1 && idFieldIdx > -1) { var pointColumns = (0, _layerUtils.assignPointPairToLayerColumn)(fieldPairs[0], true); return { columns: _objectSpread(_objectSpread({}, Object.keys(layerColumns).reduce(function (accu, col) { var _pointColumns$col; return _objectSpread(_objectSpread({}, accu), {}, (0, _defineProperty2["default"])({}, col, (_pointColumns$col = pointColumns[col]) !== null && _pointColumns$col !== void 0 ? _pointColumns$col : layerColumns[col])); }, {})), {}, (0, _defineProperty2["default"])({ geojson: { value: null, fieldIdx: -1 // optional: true }, id: { value: fields[idFieldIdx].name, fieldIdx: idFieldIdx // optional: false } }, sortBy, { value: fields[sortByFieldIdx].name, fieldIdx: sortByFieldIdx // optional: false })), label: fieldPairs[0].defaultName }; } return null; } function applyFiltersToTableColumns(dataset, dataToFeature) { var dataContainer = dataset.dataContainer, filteredIndex = dataset.filteredIndex; if (filteredIndex.length === dataContainer.numRows()) { // Only apply the filtering when something is to be filtered out return dataToFeature; } var filteredIndexSet = new Set(filteredIndex); var filteredFeatures = []; var _iterator = _createForOfIteratorHelper(dataToFeature), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var feature = _step.value; // @ts-expect-error geometry.coordinates not available for GeometryCollection var filteredCoords = feature.geometry.coordinates.filter(function (c) { return filteredIndexSet.has(c.datumIndex); }); if (filteredCoords.length > 0 && feature) { filteredFeatures.push(_objectSpread(_objectSpread({}, feature), {}, { geometry: _objectSpread(_objectSpread({}, feature.geometry), {}, { coordinates: filteredCoords }), properties: _objectSpread(_objectSpread({}, feature.properties), {}, { // @ts-expect-error BinaryFeatureCollection values: feature.geometry.coordinates.map(function (c) { return dataContainer.rowAsArray(c.datumIndex); }) }) })); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } return filteredFeatures; } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYnVmZmVyIiwicmVxdWlyZSIsIl9nZW9qc29uTm9ybWFsaXplIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsIl9iYm94IiwiX2QzQXJyYXkiLCJfY2VudGVyIiwiX2NvcmUiLCJfd2t0IiwiX2dpcyIsIl91dGlscyIsIl9jb25zdGFudHMiLCJfbGF5ZXJVdGlscyIsIl9jcmVhdGVGb3JPZkl0ZXJhdG9ySGVscGVyIiwiciIsImUiLCJ0IiwiU3ltYm9sIiwiaXRlcmF0b3IiLCJBcnJheSIsImlzQXJyYXkiLCJfdW5zdXBwb3J0ZWRJdGVyYWJsZVRvQXJyYXkiLCJsZW5ndGgiLCJfbiIsIkYiLCJzIiwibiIsImRvbmUiLCJ2YWx1ZSIsImYiLCJUeXBlRXJyb3IiLCJvIiwiYSIsInUiLCJjYWxsIiwibmV4dCIsIl9hcnJheUxpa2VUb0FycmF5IiwidG9TdHJpbmciLCJzbGljZSIsImNvbnN0cnVjdG9yIiwibmFtZSIsImZyb20iLCJ0ZXN0Iiwib3duS2V5cyIsIk9iamVjdCIsImtleXMiLCJnZXRPd25Qcm9wZXJ0eVN5bWJvbHMiLCJmaWx0ZXIiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJlbnVtZXJhYmxlIiwicHVzaCIsImFwcGx5IiwiX29iamVjdFNwcmVhZCIsImFyZ3VtZW50cyIsImZvckVhY2giLCJfZGVmaW5lUHJvcGVydHkyIiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9ycyIsImRlZmluZVByb3BlcnRpZXMiLCJkZWZpbmVQcm9wZXJ0eSIsIkNPTFVNTl9NT0RFX0dFT0pTT04iLCJleHBvcnRzIiwiRmVhdHVyZVR5cGVzIiwiZmllbGRJc0dlb0Fycm93IiwiZ2VvRmllbGQiLCJfZ2VvRmllbGQkbWV0YWRhdGEiLCJCb29sZWFuIiwibWV0YWRhdGEiLCJnZXQiLCJwYXJzZUdlb0pzb25SYXdGZWF0dXJlIiwicmF3RmVhdHVyZSIsInByb3BlcnRpZXMiLCJVaW50OEFycmF5IiwiQXJyYXlCdWZmZXIiLCJiaW5hcnlJbnB1dCIsImJ1ZmZlciIsImJ5dGVPZmZzZXQiLCJieXRlTGVuZ3RoIiwiYmluYXJ5R2VvIiwicGFyc2VTeW5jIiwiV0tCTG9hZGVyIiwicGFyc2VkR2VvIiwiYmluYXJ5VG9HZW9tZXRyeSIsIm5vcm1hbGl6ZWQiLCJub3JtYWxpemUiLCJmZWF0dXJlcyIsIl90eXBlb2YyIiwicGFyc2VkR2VvbWV0cnkiLCJwYXJzZUdlb21ldHJ5RnJvbVN0cmluZyIsInR5cGUiLCJnZW9tZXRyeSIsImNvb3JkaW5hdGVzIiwibWFwIiwicHRzIiwiZ2V0R2VvanNvbkxheWVyTWV0YSIsIl9yZWYiLCJkYXRhQ29udGFpbmVyIiwiZ2V0RmVhdHVyZSIsImNvbmZpZyIsImRhdGFUb0ZlYXR1cmUiLCJjb2x1bW5Nb2RlIiwiZ2V0R2VvanNvbkRhdGFNYXBzIiwiZ3JvdXBDb2x1bW5zQXNHZW9Kc29uIiwiY29sdW1ucyIsImJvdW5kcyIsImdldEdlb2pzb25Cb3VuZHMiLCJmaXhlZFJhZGl1cyIsImZpbmQiLCJkIiwiX2QkcHJvcGVydGllcyIsInJhZGl1cyIsImZlYXR1cmVUeXBlcyIsImdldEdlb2pzb25GZWF0dXJlVHlwZXMiLCJtZWFuQ2VudGVycyIsImkiLCJmZWF0dXJlIiwiY2VudCIsImNlbnRlciIsImNlbnRyb2lkcyIsImFjY2VwdGFibGVUeXBlcyIsImluZGV4IiwibnVtUm93cyIsImluY2x1ZGVzIiwiY2xlYW5lZCIsImdldEdlb2pzb25Qb2ludERhdGFNYXBzIiwicm93QXNBcnJheSIsImdlb21ldHJpZXMiLCJyZWR1Y2UiLCJhY2N1IiwiX3RvQ29uc3VtYWJsZUFycmF5MiIsImdlb1N0cmluZyIsIkpTT04iLCJwYXJzZSIsIldLVExvYWRlciIsIkJ1ZmZlciIsInVuZGVmaW5lZCIsIm1heENvdW50Iiwic2FtcGxlcyIsImdldFNhbXBsZURhdGEiLCJ2YWxpZFNpbmdsZUdlb21ldHJ5IiwiZ2VvbSIsInZhbGlkR2VvbWV0cnlDb2xsZWN0aW9uIiwiZXZlcnkiLCJub25FbXB0eSIsImJib3giLCJmZWF0dXJlVG9EZWNrR2xHZW9UeXBlIiwiUG9pbnQiLCJNdWx0aVBvaW50IiwiTGluZVN0cmluZyIsIk11bHRpTGluZVN0cmluZyIsIlBvbHlnb24iLCJNdWx0aVBvbHlnb24iLCJhbGxGZWF0dXJlcyIsImdlb1R5cGUiLCJzb3J0QnlDb2x1bW4iLCJncm91cGVkQnlJZCIsInNvcnRCeUZpZWxkSWR4IiwiZmllbGRJZHgiLCJzb3J0QnlSZXF1aXJlZCIsIm9wdGlvbmFsIiwiZGF0dW0iLCJpZCIsImxhdCIsImxvbiIsImxuZyIsImFsdGl0dWRlIiwic29ydEJ5IiwiY29vcmRzIiwiZGF0dW1JbmRleCIsIk51bWJlciIsImlzRmluaXRlIiwicmVzdWx0IiwiZW50cmllcyIsIl9yZWYyIiwiX3JlZjMiLCJfc2xpY2VkVG9BcnJheTIiLCJfIiwiaXRlbXMiLCJzb3J0IiwiYiIsImFzY2VuZGluZyIsInZhbHVlcyIsIml0ZW0iLCJkZXRlY3RUYWJsZUNvbHVtbnMiLCJkYXRhc2V0IiwibGF5ZXJDb2x1bW5zIiwiZmllbGRzIiwiZmllbGRQYWlycyIsImZpbmRJbmRleCIsIkFMTF9GSUVMRF9UWVBFUyIsInRpbWVzdGFtcCIsImlkRmllbGRJZHgiLCJfZiRuYW1lIiwidG9Mb3dlckNhc2UiLCJtYXRjaCIsInBvaW50Q29sdW1ucyIsImFzc2lnblBvaW50UGFpclRvTGF5ZXJDb2x1bW4iLCJjb2wiLCJfcG9pbnRDb2x1bW5zJGNvbCIsImdlb2pzb24iLCJsYWJlbCIsImRlZmF1bHROYW1lIiwiYXBwbHlGaWx0ZXJzVG9UYWJsZUNvbHVtbnMiLCJmaWx0ZXJlZEluZGV4IiwiZmlsdGVyZWRJbmRleFNldCIsIlNldCIsImZpbHRlcmVkRmVhdHVyZXMiLCJfaXRlcmF0b3IiLCJfc3RlcCIsImZpbHRlcmVkQ29vcmRzIiwiYyIsImhhcyIsImVyciJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9nZW9qc29uLWxheWVyL2dlb2pzb24tdXRpbHMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVFxuLy8gQ29weXJpZ2h0IGNvbnRyaWJ1dG9ycyB0byB0aGUga2VwbGVyLmdsIHByb2plY3RcblxuaW1wb3J0IHtCdWZmZXJ9IGZyb20gJ2J1ZmZlcic7XG5pbXBvcnQge0ZlYXR1cmUsIFBvc2l0aW9uLCBCQm94fSBmcm9tICdnZW9qc29uJztcbmltcG9ydCBub3JtYWxpemUgZnJvbSAnQG1hcGJveC9nZW9qc29uLW5vcm1hbGl6ZSc7XG5pbXBvcnQgYmJveCBmcm9tICdAdHVyZi9iYm94JztcbmltcG9ydCB7YXNjZW5kaW5nfSBmcm9tICdkMy1hcnJheSc7XG5pbXBvcnQgY2VudGVyIGZyb20gJ0B0dXJmL2NlbnRlcic7XG5pbXBvcnQge0FsbEdlb0pTT059IGZyb20gJ0B0dXJmL2hlbHBlcnMnO1xuaW1wb3J0IHtwYXJzZVN5bmN9IGZyb20gJ0Bsb2FkZXJzLmdsL2NvcmUnO1xuaW1wb3J0IHtXS0JMb2FkZXIsIFdLVExvYWRlcn0gZnJvbSAnQGxvYWRlcnMuZ2wvd2t0JztcbmltcG9ydCB7YmluYXJ5VG9HZW9tZXRyeX0gZnJvbSAnQGxvYWRlcnMuZ2wvZ2lzJztcbmltcG9ydCB7QmluYXJ5RmVhdHVyZUNvbGxlY3Rpb259IGZyb20gJ0Bsb2FkZXJzLmdsL3NjaGVtYSc7XG5pbXBvcnQge0RhdGFDb250YWluZXJJbnRlcmZhY2UsIGdldFNhbXBsZURhdGF9IGZyb20gJ0BrZXBsZXIuZ2wvdXRpbHMnO1xuaW1wb3J0IHtBTExfRklFTERfVFlQRVN9IGZyb20gJ0BrZXBsZXIuZ2wvY29uc3RhbnRzJztcbmltcG9ydCB7TGF5ZXJDb2x1bW5zLCBQcm90b0RhdGFzZXRGaWVsZH0gZnJvbSAnQGtlcGxlci5nbC90eXBlcyc7XG5pbXBvcnQge0tlcGxlclRhYmxlfSBmcm9tICdAa2VwbGVyLmdsL3RhYmxlJztcblxuaW1wb3J0IHtHZW9qc29uTGF5ZXJNZXRhUHJvcHMsIGFzc2lnblBvaW50UGFpclRvTGF5ZXJDb2x1bW59IGZyb20gJy4uL2xheWVyLXV0aWxzJztcbmltcG9ydCB7TGF5ZXJCYXNlQ29uZmlnfSBmcm9tICcuLi9iYXNlLWxheWVyJztcblxuZXhwb3J0IHR5cGUgR2V0RmVhdHVyZSA9IChkOiBhbnkpID0+IEZlYXR1cmU7XG5leHBvcnQgdHlwZSBHZW9qc29uRGF0YU1hcHMgPSAoRmVhdHVyZSB8IEJpbmFyeUZlYXR1cmVDb2xsZWN0aW9uIHwgbnVsbClbXTtcbmV4cG9ydCB0eXBlIEdlb2pzb25Qb2ludERhdGFNYXBzID0gKG51bWJlcltdIHwgbnVtYmVyW11bXSB8IG51bGwpW107XG5cbmV4cG9ydCBjb25zdCBDT0xVTU5fTU9ERV9HRU9KU09OID0gJ2dlb2pzb24nO1xuXG4vKiBlc2xpbnQtZGlzYWJsZSAqL1xuLy8gVE9ETzogUmUtZW5hYmxlIGVzbGludCB3aGVuIHdlIHVwZ3JhZGUgdG8gaGFuZGxlIGVudW1zIGFuZCB0eXBlIG1hcHNcbmV4cG9ydCBlbnVtIEZlYXR1cmVUeXBlcyB7XG4gIFBvaW50ID0gJ1BvaW50JyxcbiAgTXVsdGlQb2ludCA9ICdNdWx0aVBvaW50JyxcbiAgTGluZVN0cmluZyA9ICdMaW5lU3RyaW5nJyxcbiAgTXVsdGlMaW5lU3RyaW5nID0gJ011bHRpTGluZVN0cmluZycsXG4gIFBvbHlnb24gPSAnUG9seWdvbicsXG4gIE11bHRpUG9seWdvbiA9ICdNdWx0aVBvbHlnb24nXG59XG5cbi8vIEB0cy1leHBlY3QtZXJyb3IgcmV0dXJuIHR5cGUgb2YgZ2V0R2VvanNvbkZlYXR1cmVUeXBlcyA/XG50eXBlIEZlYXR1cmVUeXBlTWFwID0ge1xuICBba2V5IGluIEZlYXR1cmVUeXBlc106IGJvb2xlYW47XG59O1xuXG4vKiBlc2xpbnQtZW5hYmxlICovXG5cbi8qKlxuICogUmV0dXJucyB0cnVlIGlmIHRoZSBmaWVsZCBoYXMgZ2VvYXJyb3cgZXh0ZW5zaW9uLlxuICogQHBhcmFtIGdlb0ZpZWxkIEEgZmllbGQgdG8gdGVzdC5cbiAqIEByZXR1cm5zXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmaWVsZElzR2VvQXJyb3coZ2VvRmllbGQ/OiBQcm90b0RhdGFzZXRGaWVsZCB8IG51bGwpOiBib29sZWFuIHtcbiAgcmV0dXJuIEJvb2xlYW4oZ2VvRmllbGQ/Lm1ldGFkYXRhPy5nZXQoJ0FSUk9XOmV4dGVuc2lvbjpuYW1lJykpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VHZW9Kc29uUmF3RmVhdHVyZShyYXdGZWF0dXJlOiB1bmtub3duKTogRmVhdHVyZSB8IG51bGwge1xuICBjb25zdCBwcm9wZXJ0aWVzID0gbnVsbDsgLy8gaGVscCBlbnN1cmUgdGhhdCBwcm9wZXJ0aWVzIGlzIHByZXNlbnQgb24gdGhlIHJldHVybmVkIGdlb2pzb24gZmVhdHVyZVxuICAvLyBTdXBwb3J0IFdLQiBnZW9tZXRyeSBwcm92aWRlZCBhcyBiaW5hcnkgKGUuZy4sIGZyb20gUGFycXVldC9HZW9QYXJxdWV0KVxuICBpZiAocmF3RmVhdHVyZSBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkgfHwgcmF3RmVhdHVyZSBpbnN0YW5jZW9mIEFycmF5QnVmZmVyKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGJpbmFyeUlucHV0ID1cbiAgICAgICAgcmF3RmVhdHVyZSBpbnN0YW5jZW9mIEFycmF5QnVmZmVyXG4gICAgICAgICAgPyByYXdGZWF0dXJlXG4gICAgICAgICAgOiAocmF3RmVhdHVyZSBhcyBVaW50OEFycmF5KS5idWZmZXIuc2xpY2UoXG4gICAgICAgICAgICAgIChyYXdGZWF0dXJlIGFzIFVpbnQ4QXJyYXkpLmJ5dGVPZmZzZXQsXG4gICAgICAgICAgICAgIChyYXdGZWF0dXJlIGFzIFVpbnQ4QXJyYXkpLmJ5dGVPZmZzZXQgKyAocmF3RmVhdHVyZSBhcyBVaW50OEFycmF5KS5ieXRlTGVuZ3RoXG4gICAgICAgICAgICApO1xuICAgICAgY29uc3QgYmluYXJ5R2VvID0gcGFyc2VTeW5jKGJpbmFyeUlucHV0IGFzIEFycmF5QnVmZmVyLCBXS0JMb2FkZXIpO1xuICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvciBsb2FkZXJzLmdsIGJpbmFyeSB0eXBlIHRvIEdlb0pTT04gZ2VvbWV0cnlcbiAgICAgIGNvbnN0IHBhcnNlZEdlbyA9IGJpbmFyeVRvR2VvbWV0cnkoYmluYXJ5R2VvKTtcbiAgICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSBub3JtYWxpemUocGFyc2VkR2VvKTtcbiAgICAgIGlmICghbm9ybWFsaXplZCB8fCAhQXJyYXkuaXNBcnJheShub3JtYWxpemVkLmZlYXR1cmVzKSB8fCAhbm9ybWFsaXplZC5mZWF0dXJlcy5sZW5ndGgpIHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG4gICAgICByZXR1cm4ge3Byb3BlcnRpZXMsIC4uLm5vcm1hbGl6ZWQuZmVhdHVyZXNbMF19O1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuICBpZiAodHlwZW9mIHJhd0ZlYXR1cmUgPT09ICdvYmplY3QnKSB7XG4gICAgLy8gU3VwcG9ydCBHZW9Kc29uIGZlYXR1cmUgYXMgb2JqZWN0XG4gICAgLy8gcHJvYmFibHkgbmVlZCB0byBub3JtYWxpemUgaXQgYXMgd2VsbFxuICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSBub3JtYWxpemUocmF3RmVhdHVyZSk7XG4gICAgaWYgKCFub3JtYWxpemVkIHx8ICFBcnJheS5pc0FycmF5KG5vcm1hbGl6ZWQuZmVhdHVyZXMpKSB7XG4gICAgICAvLyBmYWlsIHRvIG5vcm1hbGl6ZSBHZW9Kc29uXG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICByZXR1cm4ge3Byb3BlcnRpZXMsIC4uLm5vcm1hbGl6ZWQuZmVhdHVyZXNbMF19O1xuICB9IGVsc2UgaWYgKHR5cGVvZiByYXdGZWF0dXJlID09PSAnc3RyaW5nJykge1xuICAgIGNvbnN0IHBhcnNlZEdlb21ldHJ5ID0gcGFyc2VHZW9tZXRyeUZyb21TdHJpbmcocmF3RmVhdHVyZSk7XG4gICAgaWYgKCFwYXJzZWRHZW9tZXRyeSkgcmV0dXJuIG51bGw7XG4gICAgLy8gQHRzLWV4cGVjdC1lcnJvciB2ZXJpZnkgd2hldGhlciBwYXJzZWRHZW9tZXRyeSBhbHdheXMgY29udGFpbnMgcHJvcGVydGllc1xuICAgIHJldHVybiB7cHJvcGVydGllcywgLi4ucGFyc2VkR2VvbWV0cnl9O1xuICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkocmF3RmVhdHVyZSkpIHtcbiAgICAvLyBTdXBwb3J0IEdlb0pzb24gIExpbmVTdHJpbmcgYXMgYW4gYXJyYXkgb2YgcG9pbnRzXG4gICAgcmV0dXJuIHtcbiAgICAgIHR5cGU6ICdGZWF0dXJlJyxcbiAgICAgIGdlb21ldHJ5OiB7XG4gICAgICAgIC8vIHdoeSBkbyB3ZSBuZWVkIHRvIGZsaXAgaXQuLi5cbiAgICAgICAgY29vcmRpbmF0ZXM6IHJhd0ZlYXR1cmUubWFwKHB0cyA9PiBbcHRzWzFdLCBwdHNbMF1dKSxcbiAgICAgICAgdHlwZTogJ0xpbmVTdHJpbmcnXG4gICAgICB9LFxuICAgICAgcHJvcGVydGllc1xuICAgIH07XG4gIH1cblxuICByZXR1cm4gbnVsbDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldEdlb2pzb25MYXllck1ldGEoe1xuICBkYXRhQ29udGFpbmVyLFxuICBnZXRGZWF0dXJlLFxuICBjb25maWdcbn06IHtcbiAgZGF0YUNvbnRhaW5lcjogRGF0YUNvbnRhaW5lckludGVyZmFjZTtcbiAgZ2V0RmVhdHVyZTogR2V0RmVhdHVyZTtcbiAgY29uZmlnOiBMYXllckJhc2VDb25maWc7XG59KTogR2VvanNvbkxheWVyTWV0YVByb3BzIHtcbiAgY29uc3QgZGF0YVRvRmVhdHVyZSA9XG4gICAgY29uZmlnLmNvbHVtbk1vZGUgPT09IENPTFVNTl9NT0RFX0dFT0pTT05cbiAgICAgID8gZ2V0R2VvanNvbkRhdGFNYXBzKGRhdGFDb250YWluZXIsIGdldEZlYXR1cmUpXG4gICAgICA6IC8vIENPTFVNTl9NT0RFX1RBQkxFXG4gICAgICAgIGdyb3VwQ29sdW1uc0FzR2VvSnNvbihkYXRhQ29udGFpbmVyLCBjb25maWcuY29sdW1ucywgJ3NvcnRCeScpO1xuXG4gIC8vIGdldCBib3VuZHMgZnJvbSBmZWF0dXJlc1xuICBjb25zdCBib3VuZHMgPSBnZXRHZW9qc29uQm91bmRzKGRhdGFUb0ZlYXR1cmUpO1xuICAvLyBpZiBhbnkgb2YgdGhlIGZlYXR1cmUgaGFzIHByb3BlcnRpZXMucmFkaXVzIHNldCB0byBiZSB0cnVlXG4gIGNvbnN0IGZpeGVkUmFkaXVzID0gQm9vbGVhbihcbiAgICBkYXRhVG9GZWF0dXJlLmZpbmQoZCA9PiBkICYmICdwcm9wZXJ0aWVzJyBpbiBkICYmIGQucHJvcGVydGllcz8ucmFkaXVzKVxuICApO1xuXG4gIC8vIGtlZXAgYSByZWNvcmQgb2Ygd2hhdCB0eXBlIG9mIGdlb21ldHJ5IHRoZSBjb2xsZWN0aW9uIGhhc1xuICBjb25zdCBmZWF0dXJlVHlwZXMgPSBnZXRHZW9qc29uRmVhdHVyZVR5cGVzKGRhdGFUb0ZlYXR1cmUpO1xuXG4gIGNvbnN0IG1lYW5DZW50ZXJzOiBBcnJheTxudW1iZXJbXSB8IG51bGw+ID0gW107XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgZGF0YVRvRmVhdHVyZS5sZW5ndGg7IGkrKykge1xuICAgIGNvbnN0IGZlYXR1cmUgPSBkYXRhVG9GZWF0dXJlW2ldO1xuICAgIGlmIChmZWF0dXJlKSB7XG4gICAgICB0cnkge1xuICAgICAgICAvLyBUT0RPOiB1c2UgbGluZSBpbnRlcnBvbGF0ZSB0byBnZXQgY2VudGVyIG9mIGxpbmUgZm9yIExpbmVTdHJpbmdcbiAgICAgICAgY29uc3QgY2VudCA9IGNlbnRlcihmZWF0dXJlIGFzIEFsbEdlb0pTT04pO1xuICAgICAgICBtZWFuQ2VudGVycy5wdXNoKGNlbnQuZ2VvbWV0cnkuY29vcmRpbmF0ZXMpO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBtZWFuQ2VudGVycy5wdXNoKG51bGwpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7XG4gICAgZGF0YVRvRmVhdHVyZSxcbiAgICBib3VuZHMsXG4gICAgZml4ZWRSYWRpdXMsXG4gICAgZmVhdHVyZVR5cGVzLFxuICAgIGNlbnRyb2lkczogbWVhbkNlbnRlcnNcbiAgfTtcbn1cblxuLyoqXG4gKiBQYXJzZSByYXcgZGF0YSB0byBHZW9Kc29uIGZlYXR1cmVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEdlb2pzb25EYXRhTWFwcyhcbiAgZGF0YUNvbnRhaW5lcjogRGF0YUNvbnRhaW5lckludGVyZmFjZSxcbiAgZ2V0RmVhdHVyZTogR2V0RmVhdHVyZVxuKTogR2VvanNvbkRhdGFNYXBzIHtcbiAgY29uc3QgYWNjZXB0YWJsZVR5cGVzID0gW1xuICAgICdQb2ludCcsXG4gICAgJ011bHRpUG9pbnQnLFxuICAgICdMaW5lU3RyaW5nJyxcbiAgICAnTXVsdGlMaW5lU3RyaW5nJyxcbiAgICAnUG9seWdvbicsXG4gICAgJ011bHRpUG9seWdvbicsXG4gICAgJ0dlb21ldHJ5Q29sbGVjdGlvbidcbiAgXTtcblxuICBjb25zdCBkYXRhVG9GZWF0dXJlOiBHZW9qc29uRGF0YU1hcHMgPSBbXTtcblxuICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgZGF0YUNvbnRhaW5lci5udW1Sb3dzKCk7IGluZGV4KyspIHtcbiAgICBjb25zdCBmZWF0dXJlID0gcGFyc2VHZW9Kc29uUmF3RmVhdHVyZShnZXRGZWF0dXJlKHtpbmRleH0pKTtcblxuICAgIGlmIChmZWF0dXJlICYmIGZlYXR1cmUuZ2VvbWV0cnkgJiYgYWNjZXB0YWJsZVR5cGVzLmluY2x1ZGVzKGZlYXR1cmUuZ2VvbWV0cnkudHlwZSkpIHtcbiAgICAgIGNvbnN0IGNsZWFuZWQgPSB7XG4gICAgICAgIC4uLmZlYXR1cmUsXG4gICAgICAgIC8vIHN0b3JlIGluZGV4IG9mIHRoZSBkYXRhIGluIGZlYXR1cmUgcHJvcGVydGllc1xuICAgICAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgLi4uZmVhdHVyZS5wcm9wZXJ0aWVzLFxuICAgICAgICAgIGluZGV4XG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgIGRhdGFUb0ZlYXR1cmVbaW5kZXhdID0gY2xlYW5lZDtcbiAgICB9IGVsc2Uge1xuICAgICAgZGF0YVRvRmVhdHVyZVtpbmRleF0gPSBudWxsO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBkYXRhVG9GZWF0dXJlO1xufVxuXG4vKipcbiAqIFBhcnNlIHJhdyBkYXRhIHRvIEdlb0pzb24gcG9pbnQgZmVhdHVyZSBjb29yZGluYXRlc1xuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0R2VvanNvblBvaW50RGF0YU1hcHMoXG4gIGRhdGFDb250YWluZXI6IERhdGFDb250YWluZXJJbnRlcmZhY2UsXG4gIGdldEZlYXR1cmU6IEdldEZlYXR1cmVcbik6IEdlb2pzb25Qb2ludERhdGFNYXBzIHtcbiAgY29uc3QgYWNjZXB0YWJsZVR5cGVzID0gWydQb2ludCcsICdNdWx0aVBvaW50JywgJ0dlb21ldHJ5Q29sbGVjdGlvbiddO1xuXG4gIGNvbnN0IGRhdGFUb0ZlYXR1cmU6IEdlb2pzb25Qb2ludERhdGFNYXBzID0gW107XG5cbiAgZm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IGRhdGFDb250YWluZXIubnVtUm93cygpOyBpbmRleCsrKSB7XG4gICAgY29uc3QgZmVhdHVyZSA9IHBhcnNlR2VvSnNvblJhd0ZlYXR1cmUoZ2V0RmVhdHVyZShkYXRhQ29udGFpbmVyLnJvd0FzQXJyYXkoaW5kZXgpKSk7XG5cbiAgICBpZiAoZmVhdHVyZSAmJiBmZWF0dXJlLmdlb21ldHJ5ICYmIGFjY2VwdGFibGVUeXBlcy5pbmNsdWRlcyhmZWF0dXJlLmdlb21ldHJ5LnR5cGUpKSB7XG4gICAgICBkYXRhVG9GZWF0dXJlW2luZGV4XSA9XG4gICAgICAgIGZlYXR1cmUuZ2VvbWV0cnkudHlwZSA9PT0gJ1BvaW50JyB8fCBmZWF0dXJlLmdlb21ldHJ5LnR5cGUgPT09ICdNdWx0aVBvaW50J1xuICAgICAgICAgID8gZmVhdHVyZS5nZW9tZXRyeS5jb29yZGluYXRlc1xuICAgICAgICAgIDogLy8gQHRzLWV4cGVjdC1lcnJvciBQcm9wZXJ0eSAnZ2VvbWV0cmllcycgZG9lcyBub3QgZXhpc3Qgb24gdHlwZSAnTGluZVN0cmluZydcbiAgICAgICAgICAgIChmZWF0dXJlLmdlb21ldHJ5Lmdlb21ldHJpZXMgfHwgW10pLnJlZHVjZSgoYWNjdSwgZikgPT4ge1xuICAgICAgICAgICAgICBpZiAoZi50eXBlID09PSAnUG9pbnQnKSB7XG4gICAgICAgICAgICAgICAgYWNjdS5wdXNoKGYuY29vcmRpbmF0ZXMpO1xuICAgICAgICAgICAgICB9IGVsc2UgaWYgKGYudHlwZSA9PT0gJ011bHRpUG9pbnQnKSB7XG4gICAgICAgICAgICAgICAgYWNjdS5wdXNoKC4uLmYuY29vcmRpbmF0ZXMpO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgcmV0dXJuIGFjY3U7XG4gICAgICAgICAgICB9LCBbXSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGRhdGFUb0ZlYXR1cmVbaW5kZXhdID0gbnVsbDtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gZGF0YVRvRmVhdHVyZTtcbn1cblxuLyoqXG4gKiBQYXJzZSBnZW9qc29uIGZyb20gc3RyaW5nXG4gKiBAcGFyYW0ge1N0cmluZ30gZ2VvU3RyaW5nXG4gKiBAcmV0dXJucyB7bnVsbCB8IE9iamVjdH0gZ2VvanNvbiBvYmplY3Qgb3IgbnVsbCBpZiBmYWlsZWRcbiAqL1xuZnVuY3Rpb24gcGFyc2VHZW9tZXRyeUZyb21TdHJpbmcoZ2VvU3RyaW5nOiBzdHJpbmcpOiBGZWF0dXJlIHwgbnVsbCB7XG4gIGxldCBwYXJzZWRHZW87XG5cbiAgLy8gdHJ5IHBhcnNlIGFzIGdlb2pzb24gc3RyaW5nXG4gIC8vIHtcInR5cGVcIjpcIlBvbHlnb25cIixcImNvb3JkaW5hdGVzXCI6W1tbLTc0LjE1ODQ5MSw0MC44MzU5NF1dXX1cbiAgdHJ5IHtcbiAgICBwYXJzZWRHZW8gPSBKU09OLnBhcnNlKGdlb1N0cmluZyk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICAvLyBrZWVwIHRyeWluZyB0byBwYXJzZVxuICB9XG5cbiAgLy8gdHJ5IHBhcnNlIGFzIHdrdCB1c2luZyBsb2FkZXJzLmdsIFdLVExvYWRlclxuICBpZiAoIXBhcnNlZEdlbykge1xuICAgIHRyeSB7XG4gICAgICBwYXJzZWRHZW8gPSBwYXJzZVN5bmMoZ2VvU3RyaW5nLCBXS1RMb2FkZXIpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIC8vIHRyeSBwYXJzZSBhcyB3a2IgdXNpbmcgbG9hZGVycy5nbCBXS0JMb2FkZXJcbiAgaWYgKCFwYXJzZWRHZW8pIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgYnVmZmVyID0gQnVmZmVyLmZyb20oZ2VvU3RyaW5nLCAnaGV4Jyk7XG4gICAgICBjb25zdCBiaW5hcnlHZW8gPSBwYXJzZVN5bmMoYnVmZmVyLCBXS0JMb2FkZXIpO1xuICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvclxuICAgICAgcGFyc2VkR2VvID0gYmluYXJ5VG9HZW9tZXRyeShiaW5hcnlHZW8pO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIGlmICghcGFyc2VkR2VvKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBjb25zdCBub3JtYWxpemVkID0gbm9ybWFsaXplKHBhcnNlZEdlbyk7XG5cbiAgaWYgKCFub3JtYWxpemVkIHx8ICFBcnJheS5pc0FycmF5KG5vcm1hbGl6ZWQuZmVhdHVyZXMpKSB7XG4gICAgLy8gZmFpbCB0byBub3JtYWxpemUgZ2VvanNvblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgcmV0dXJuIG5vcm1hbGl6ZWQuZmVhdHVyZXNbMF07XG59XG5cbi8qKlxuICogR2V0IGdlb2pzb24gYm91bmRzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRHZW9qc29uQm91bmRzKGZlYXR1cmVzOiBHZW9qc29uRGF0YU1hcHMgPSBbXSk6IEJCb3ggfCBudWxsIHtcbiAgLy8gNzAgbXMgZm9yIDEwLDAwMCBwb2x5Z29uc1xuICAvLyBoZXJlIHdlIG9ubHkgcGljayBjb3VwbGVcbiAgY29uc3QgbWF4Q291bnQgPSAxMDAwMDtcbiAgY29uc3Qgc2FtcGxlcyA9IGZlYXR1cmVzLmxlbmd0aCA+IG1heENvdW50ID8gZ2V0U2FtcGxlRGF0YShmZWF0dXJlcywgbWF4Q291bnQpIDogZmVhdHVyZXM7XG5cbiAgY29uc3QgdmFsaWRTaW5nbGVHZW9tZXRyeSA9IGdlb20gPT4gZ2VvbS5jb29yZGluYXRlcyAmJiBnZW9tLmNvb3JkaW5hdGVzLmxlbmd0aDtcbiAgY29uc3QgdmFsaWRHZW9tZXRyeUNvbGxlY3Rpb24gPSBnZW9tID0+XG4gICAgZ2VvbS5nZW9tZXRyaWVzICYmIGdlb20uZ2VvbWV0cmllcy5sZW5ndGggJiYgZ2VvbS5nZW9tZXRyaWVzLmV2ZXJ5KHZhbGlkU2luZ2xlR2VvbWV0cnkpO1xuICBjb25zdCBub25FbXB0eSA9IHNhbXBsZXMuZmlsdGVyKFxuICAgIGQgPT4gZCAmJiBkLmdlb21ldHJ5ICYmICh2YWxpZFNpbmdsZUdlb21ldHJ5KGQuZ2VvbWV0cnkpIHx8IHZhbGlkR2VvbWV0cnlDb2xsZWN0aW9uKGQuZ2VvbWV0cnkpKVxuICApO1xuXG4gIHRyeSB7XG4gICAgcmV0dXJuIGJib3goe1xuICAgICAgdHlwZTogJ0ZlYXR1cmVDb2xsZWN0aW9uJyxcbiAgICAgIGZlYXR1cmVzOiBub25FbXB0eVxuICAgIH0pO1xuICB9IGNhdGNoIChlKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbn1cblxuZXhwb3J0IGNvbnN0IGZlYXR1cmVUb0RlY2tHbEdlb1R5cGUgPSB7XG4gIFBvaW50OiAncG9pbnQnLFxuICBNdWx0aVBvaW50OiAncG9pbnQnLFxuICBMaW5lU3RyaW5nOiAnbGluZScsXG4gIE11bHRpTGluZVN0cmluZzogJ2xpbmUnLFxuICBQb2x5Z29uOiAncG9seWdvbicsXG4gIE11bHRpUG9seWdvbjogJ3BvbHlnb24nXG59O1xuXG5leHBvcnQgdHlwZSBEZWNrR2xHZW9UeXBlcyA9IHtcbiAgcG9pbnQ6IGJvb2xlYW47XG4gIGxpbmU6IGJvb2xlYW47XG4gIHBvbHlnb246IGJvb2xlYW47XG59O1xuXG4vKipcbiAqIFBhcnNlIGdlb2pzb24gZnJvbSBzdHJpbmdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEdlb2pzb25GZWF0dXJlVHlwZXMoYWxsRmVhdHVyZXM6IEdlb2pzb25EYXRhTWFwcyk6IERlY2tHbEdlb1R5cGVzIHtcbiAgLy8gQHRzLWV4cGVjdC1lcnJvciBzb21lIHRlc3QgY2FzZXMgb25seSBoYXZlIDEgZ2VvdHlwZVxuICBjb25zdCBmZWF0dXJlVHlwZXM6IERlY2tHbEdlb1R5cGVzID0ge307XG4gIGZvciAobGV0IGYgPSAwOyBmIDwgYWxsRmVhdHVyZXMubGVuZ3RoOyBmKyspIHtcbiAgICBjb25zdCBmZWF0dXJlID0gYWxsRmVhdHVyZXNbZl07XG4gICAgaWYgKGZlYXR1cmUgJiYgJ2dlb21ldHJ5JyBpbiBmZWF0dXJlKSB7XG4gICAgICBjb25zdCBnZW9UeXBlID0gZmVhdHVyZVRvRGVja0dsR2VvVHlwZVtmZWF0dXJlLmdlb21ldHJ5ICYmIGZlYXR1cmUuZ2VvbWV0cnkudHlwZV07XG4gICAgICBpZiAoZ2VvVHlwZSkge1xuICAgICAgICBmZWF0dXJlVHlwZXNbZ2VvVHlwZV0gPSB0cnVlO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBmZWF0dXJlVHlwZXM7XG59XG5cbnR5cGUgQ29vcmRzVHlwZSA9IFtudW1iZXIsIG51bWJlciwgbnVtYmVyLCBudW1iZXIgfCBudWxsXSAmIHtcbiAgZGF0dW1JbmRleDogbnVtYmVyO1xuICBkYXR1bTogbnVtYmVyW107XG59O1xuXG5leHBvcnQgZnVuY3Rpb24gZ3JvdXBDb2x1bW5zQXNHZW9Kc29uKFxuICBkYXRhQ29udGFpbmVyOiBEYXRhQ29udGFpbmVySW50ZXJmYWNlLFxuICBjb2x1bW5zOiBMYXllckNvbHVtbnMsXG4gIHNvcnRCeUNvbHVtbiA9ICd0aW1lc3RhbXAnXG4pOiBGZWF0dXJlW10ge1xuICBjb25zdCBncm91cGVkQnlJZDoge1trZXk6IHN0cmluZ106IENvb3Jkc1R5cGVbXX0gPSB7fTtcbiAgY29uc3Qgc29ydEJ5RmllbGRJZHggPSBjb2x1bW5zW3NvcnRCeUNvbHVtbl0uZmllbGRJZHg7XG4gIGNvbnN0IHNvcnRCeVJlcXVpcmVkID0gIWNvbHVtbnNbc29ydEJ5Q29sdW1uXS5vcHRpb25hbDtcbiAgZm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IGRhdGFDb250YWluZXIubnVtUm93cygpOyBpbmRleCsrKSB7XG4gICAgLy8gbm90ZTogY2FuIG1hdGVyaWFsaXplIHRoZSByb3dcbiAgICBjb25zdCBkYXR1bSA9IGRhdGFDb250YWluZXIucm93QXNBcnJheShpbmRleCk7XG4gICAgY29uc3QgaWQgPSBkYXR1bVtjb2x1bW5zLmlkLmZpZWxkSWR4XTtcbiAgICBjb25zdCBsYXQgPSBkYXR1bVtjb2x1bW5zLmxhdC5maWVsZElkeF07XG4gICAgY29uc3QgbG9uID0gZGF0dW1bY29sdW1ucy5sbmcuZmllbGRJZHhdO1xuICAgIGNvbnN0IGFsdGl0dWRlID0gY29sdW1ucy5hbHRpdHVkZSA/IGRhdHVtW2NvbHVtbnMuYWx0aXR1ZGUuZmllbGRJZHhdIDogMDtcbiAgICBjb25zdCBzb3J0QnkgPSBzb3J0QnlGaWVsZElkeCA+IC0xID8gZGF0dW1bc29ydEJ5RmllbGRJZHhdIDogbnVsbDtcbiAgICAvLyBAdHMtZXhwZWN0LWVycm9yXG4gICAgY29uc3QgY29vcmRzOiBDb29yZHNUeXBlID0gW2xvbiwgbGF0LCBhbHRpdHVkZSwgc29ydEJ5XTtcbiAgICAvLyBBZGRpbmcgcmVmZXJlbmNlcyB0byB0aGUgb3JpZ2luYWwgZGF0YSB0byB0aGUgY29vcmRpbmF0ZXMgYXJyYXlcbiAgICBjb29yZHMuZGF0dW1JbmRleCA9IGluZGV4O1xuICAgIGNvb3Jkcy5kYXR1bSA9IGRhdHVtO1xuICAgIGlmICghZ3JvdXBlZEJ5SWRbaWRdKSBncm91cGVkQnlJZFtpZF0gPSBbXTtcblxuICAgIGlmIChcbiAgICAgIE51bWJlci5pc0Zpbml0ZShsb24pICYmXG4gICAgICBOdW1iZXIuaXNGaW5pdGUobGF0KSAmJlxuICAgICAgKCFzb3J0QnlSZXF1aXJlZCB8fCAoc29ydEJ5UmVxdWlyZWQgJiYgc29ydEJ5KSlcbiAgICApIHtcbiAgICAgIC8vIG9ubHkgcHVzaCBwb2ludHMgaWYgbGF0LGxuZyxhbmQgc29ydGJ5IGV4aXN0XG4gICAgICBncm91cGVkQnlJZFtpZF0ucHVzaChjb29yZHMpO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IHJlc3VsdDogRmVhdHVyZVtdID0gT2JqZWN0LmVudHJpZXMoZ3JvdXBlZEJ5SWQpLm1hcChcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICAgKFtfLCBpdGVtc106IFtzdHJpbmcsIENvb3Jkc1R5cGVbXV0sIGluZGV4KSA9PiAoe1xuICAgICAgdHlwZTogJ0ZlYXR1cmUnIGFzIGNvbnN0LFxuICAgICAgZ2VvbWV0cnk6IHtcbiAgICAgICAgdHlwZTogJ0xpbmVTdHJpbmcnIGFzIGNvbnN0LFxuICAgICAgICAvLyBTb3J0IGJ5IGNvbHVtbnMgaWYgaGFzIHNvcnRCeUZpZWxkXG4gICAgICAgIC8vIFRPRE86IGl0ZW1zIGFyZSBleHBlY3RlZCBpbiBQb3NpdGlvbltdIGZvcm1hdD9cbiAgICAgICAgY29vcmRpbmF0ZXM6IChzb3J0QnlGaWVsZElkeCA+IC0xXG4gICAgICAgICAgPyBpdGVtcy5zb3J0KChhLCBiKSA9PiBhc2NlbmRpbmcoYVszXSBhcyBhbnksIGJbM10gYXMgYW55KSlcbiAgICAgICAgICA6IGl0ZW1zKSBhcyBQb3NpdGlvbltdXG4gICAgICB9LFxuICAgICAgcHJvcGVydGllczoge1xuICAgICAgICBpbmRleCxcbiAgICAgICAgLy8gdmFsdWVzIGFyZSB1c2VkIGZvciB2YWx1ZUFjY2Vzc29yIGluIFRyaXBMYXllci5mb3JtYXRMYXllckRhdGEoKVxuICAgICAgICAvLyBOb3RlOiB0aGlzIGNhbiBjYXVzZSByb3cgbWF0ZXJpYWxpemF0aW9uIGluIGNhc2Ugb2Ygbm9uLXJvdyBiYXNlZCBjb250YWluZXJzXG4gICAgICAgIHZhbHVlczogaXRlbXMubWFwKGl0ZW0gPT4gZGF0YUNvbnRhaW5lci5yb3dBc0FycmF5KGl0ZW0uZGF0dW1JbmRleCkpXG4gICAgICB9XG4gICAgfSlcbiAgKTtcbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuLyoqXG4gKiBGaW5kIGlkIC8gdHMgLyBsYXQgLyBsbmcgY29sdW1ucyBmcm9tIGEgdGFibGUgYW5kIGFzc2lnbiBpdCB0byBsYXllciBjb2x1bW5zXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkZXRlY3RUYWJsZUNvbHVtbnMoXG4gIGRhdGFzZXQ6IEtlcGxlclRhYmxlLFxuICBsYXllckNvbHVtbnM6IExheWVyQ29sdW1ucyxcbiAgc29ydEJ5ID0gJ3RpbWVzdGFtcCdcbikge1xuICBjb25zdCB7ZmllbGRzLCBmaWVsZFBhaXJzfSA9IGRhdGFzZXQ7XG4gIGlmICghZmllbGRQYWlycy5sZW5ndGggfHwgIWZpZWxkcy5sZW5ndGgpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICAvLyBmaW5kIHNvcnQgYnkgZmllbGRcbiAgY29uc3Qgc29ydEJ5RmllbGRJZHggPSBmaWVsZHMuZmluZEluZGV4KGYgPT4gZi50eXBlID09PSBBTExfRklFTERfVFlQRVMudGltZXN0YW1wKTtcbiAgLy8gZmluZCBpZCBjb2x1bW5cbiAgY29uc3QgaWRGaWVsZElkeCA9IGZpZWxkcy5maW5kSW5kZXgoZiA9PiBmLm5hbWU/LnRvTG93ZXJDYXNlKCkubWF0Y2goL14oaWR8dXVpZCkkL2cpKTtcblxuICBpZiAoc29ydEJ5RmllbGRJZHggPiAtMSAmJiBpZEZpZWxkSWR4ID4gLTEpIHtcbiAgICBjb25zdCBwb2ludENvbHVtbnMgPSBhc3NpZ25Qb2ludFBhaXJUb0xheWVyQ29sdW1uKGZpZWxkUGFpcnNbMF0sIHRydWUpO1xuICAgIHJldHVybiB7XG4gICAgICBjb2x1bW5zOiB7XG4gICAgICAgIC4uLk9iamVjdC5rZXlzKGxheWVyQ29sdW1ucykucmVkdWNlKFxuICAgICAgICAgIChhY2N1LCBjb2wpID0+ICh7XG4gICAgICAgICAgICAuLi5hY2N1LFxuICAgICAgICAgICAgW2NvbF06IHBvaW50Q29sdW1uc1tjb2xdID8/IGxheWVyQ29sdW1uc1tjb2xdXG4gICAgICAgICAgfSksXG4gICAgICAgICAge31cbiAgICAgICAgKSxcbiAgICAgICAgZ2VvanNvbjoge1xuICAgICAgICAgIHZhbHVlOiBudWxsLFxuICAgICAgICAgIGZpZWxkSWR4OiAtMVxuICAgICAgICAgIC8vIG9wdGlvbmFsOiB0cnVlXG4gICAgICAgIH0sXG4gICAgICAgIGlkOiB7XG4gICAgICAgICAgdmFsdWU6IGZpZWxkc1tpZEZpZWxkSWR4XS5uYW1lLFxuICAgICAgICAgIGZpZWxkSWR4OiBpZEZpZWxkSWR4XG4gICAgICAgICAgLy8gb3B0aW9uYWw6IGZhbHNlXG4gICAgICAgIH0sXG4gICAgICAgIFtzb3J0QnldOiB7XG4gICAgICAgICAgdmFsdWU6IGZpZWxkc1tzb3J0QnlGaWVsZElkeF0ubmFtZSxcbiAgICAgICAgICBmaWVsZElkeDogc29ydEJ5RmllbGRJZHhcbiAgICAgICAgICAvLyBvcHRpb25hbDogZmFsc2VcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIGxhYmVsOiBmaWVsZFBhaXJzWzBdLmRlZmF1bHROYW1lXG4gICAgfTtcbiAgfVxuXG4gIHJldHVybiBudWxsO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gYXBwbHlGaWx0ZXJzVG9UYWJsZUNvbHVtbnMoXG4gIGRhdGFzZXQ6IEtlcGxlclRhYmxlLFxuICBkYXRhVG9GZWF0dXJlOiBHZW9qc29uRGF0YU1hcHNcbik6IEdlb2pzb25EYXRhTWFwcyB7XG4gIGNvbnN0IHtkYXRhQ29udGFpbmVyLCBmaWx0ZXJlZEluZGV4fSA9IGRhdGFzZXQ7XG4gIGlmIChmaWx0ZXJlZEluZGV4Lmxlbmd0aCA9PT0gZGF0YUNvbnRhaW5lci5udW1Sb3dzKCkpIHtcbiAgICAvLyBPbmx5IGFwcGx5IHRoZSBmaWx0ZXJpbmcgd2hlbiBzb21ldGhpbmcgaXMgdG8gYmUgZmlsdGVyZWQgb3V0XG4gICAgcmV0dXJuIGRhdGFUb0ZlYXR1cmU7XG4gIH1cblxuICBjb25zdCBmaWx0ZXJlZEluZGV4U2V0ID0gbmV3IFNldChmaWx0ZXJlZEluZGV4KTtcbiAgY29uc3QgZmlsdGVyZWRGZWF0dXJlczogR2VvanNvbkRhdGFNYXBzID0gW107XG4gIGZvciAoY29uc3QgZmVhdHVyZSBvZiBkYXRhVG9GZWF0dXJlKSB7XG4gICAgLy8gQHRzLWV4cGVjdC1lcnJvciBnZW9tZXRyeS5jb29yZGluYXRlcyBub3QgYXZhaWxhYmxlIGZvciBHZW9tZXRyeUNvbGxlY3Rpb25cbiAgICBjb25zdCBmaWx0ZXJlZENvb3JkcyA9IGZlYXR1cmUuZ2VvbWV0cnkuY29vcmRpbmF0ZXMuZmlsdGVyKGMgPT5cbiAgICAgIGZpbHRlcmVkSW5kZXhTZXQuaGFzKGMuZGF0dW1JbmRleClcbiAgICApO1xuICAgIGlmIChmaWx0ZXJlZENvb3Jkcy5sZW5ndGggPiAwICYmIGZlYXR1cmUpIHtcbiAgICAgIGZpbHRlcmVkRmVhdHVyZXMucHVzaCh7XG4gICAgICAgIC4uLmZlYXR1cmUsXG4gICAgICAgIGdlb21ldHJ5OiB7XG4gICAgICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvciBCaW5hcnlGZWF0dXJlQ29sbGVjdGlvblxuICAgICAgICAgIC4uLmZlYXR1cmUuZ2VvbWV0cnksXG4gICAgICAgICAgY29vcmRpbmF0ZXM6IGZpbHRlcmVkQ29vcmRzXG4gICAgICAgIH0sXG4gICAgICAgIHByb3BlcnRpZXM6IHtcbiAgICAgICAgICAvLyBAdHMtZXhwZWN0LWVycm9yIEJpbmFyeUZlYXR1cmVDb2xsZWN0aW9uXG4gICAgICAgICAgLi4uZmVhdHVyZS5wcm9wZXJ0aWVzLFxuICAgICAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3IgQmluYXJ5RmVhdHVyZUNvbGxlY3Rpb25cbiAgICAgICAgICB2YWx1ZXM6IGZlYXR1cmUuZ2VvbWV0cnkuY29vcmRpbmF0ZXMubWFwKGMgPT4gZGF0YUNvbnRhaW5lci5yb3dBc0FycmF5KGMuZGF0dW1JbmRleCkpXG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuICByZXR1cm4gZmlsdGVyZWRGZWF0dXJlcztcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUdBLElBQUFBLE9BQUEsR0FBQUMsT0FBQTtBQUVBLElBQUFDLGlCQUFBLEdBQUFDLHNCQUFBLENBQUFGLE9BQUE7QUFDQSxJQUFBRyxLQUFBLEdBQUFELHNCQUFBLENBQUFGLE9BQUE7QUFDQSxJQUFBSSxRQUFBLEdBQUFKLE9BQUE7QUFDQSxJQUFBSyxPQUFBLEdBQUFILHNCQUFBLENBQUFGLE9BQUE7QUFFQSxJQUFBTSxLQUFBLEdBQUFOLE9BQUE7QUFDQSxJQUFBTyxJQUFBLEdBQUFQLE9BQUE7QUFDQSxJQUFBUSxJQUFBLEdBQUFSLE9BQUE7QUFFQSxJQUFBUyxNQUFBLEdBQUFULE9BQUE7QUFDQSxJQUFBVSxVQUFBLEdBQUFWLE9BQUE7QUFJQSxJQUFBVyxXQUFBLEdBQUFYLE9BQUE7QUFBbUYsU0FBQVksMkJBQUFDLENBQUEsRUFBQUMsQ0FBQSxRQUFBQyxDQUFBLHlCQUFBQyxNQUFBLElBQUFILENBQUEsQ0FBQUcsTUFBQSxDQUFBQyxRQUFBLEtBQUFKLENBQUEscUJBQUFFLENBQUEsUUFBQUcsS0FBQSxDQUFBQyxPQUFBLENBQUFOLENBQUEsTUFBQUUsQ0FBQSxHQUFBSywyQkFBQSxDQUFBUCxDQUFBLE1BQUFDLENBQUEsSUFBQUQsQ0FBQSx1QkFBQUEsQ0FBQSxDQUFBUSxNQUFBLElBQUFOLENBQUEsS0FBQUYsQ0FBQSxHQUFBRSxDQUFBLE9BQUFPLEVBQUEsTUFBQUMsQ0FBQSxZQUFBQSxFQUFBLGVBQUFDLENBQUEsRUFBQUQsQ0FBQSxFQUFBRSxDQUFBLFdBQUFBLEVBQUEsV0FBQUgsRUFBQSxJQUFBVCxDQUFBLENBQUFRLE1BQUEsS0FBQUssSUFBQSxXQUFBQSxJQUFBLE1BQUFDLEtBQUEsRUFBQWQsQ0FBQSxDQUFBUyxFQUFBLFVBQUFSLENBQUEsV0FBQUEsRUFBQUQsQ0FB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