UNPKG

kepler.gl

Version:

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

480 lines (475 loc) 65.8 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof3 = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.restoreGeoarrowMetadata = exports.KeplerGlDuckDbTable = void 0; var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); 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 arrow = _interopRequireWildcard(require("apache-arrow")); var _constants = require("@kepler.gl/constants"); var _processors = require("@kepler.gl/processors"); var _table = require("@kepler.gl/table"); var _utils = require("@kepler.gl/utils"); var _dataProcessor = require("../processors/data-processor"); var _duckdbTableUtils = require("./duckdb-table-utils"); var _duckdbTableUtils2 = require("../table/duckdb-table-utils"); 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" != _typeof3(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 // TODO use files from disk or url directly, without parsing by loaders and then ingection into DeckDb /** * Default DuckDb geometry columns created by ST_READ */ var DUCKDB_GEOM_COLUMN = 'geom'; var DUCKDB_WKB_COLUMN = 'wkb_geometry'; /** Default column name for processed geojson in Kepler. Use this name to rename default 'geom' column from DuckDb in order to support Kepler maps saved before introduction of DuckDb plugin. */ var KEPLER_GEOM_FROM_GEOJSON_COLUMN = '_geojson'; /** * Names of columns that most likely contain binary wkb geometry */ var SUGGESTED_GEOM_COLUMNS = (0, _defineProperty2["default"])((0, _defineProperty2["default"])((0, _defineProperty2["default"])({}, KEPLER_GEOM_FROM_GEOJSON_COLUMN, _constants.GEOARROW_EXTENSIONS.WKB), DUCKDB_GEOM_COLUMN, _constants.GEOARROW_EXTENSIONS.WKB), "geometry", _constants.GEOARROW_EXTENSIONS.WKB); var KeplerGlDuckDbTable = exports.KeplerGlDuckDbTable = /*#__PURE__*/function (_KeplerTable) { function KeplerGlDuckDbTable(props) { (0, _classCallCheck2["default"])(this, KeplerGlDuckDbTable); return _callSuper(this, KeplerGlDuckDbTable, [props]); } (0, _inherits2["default"])(KeplerGlDuckDbTable, _KeplerTable); return (0, _createClass2["default"])(KeplerGlDuckDbTable, [{ key: "importRowData", value: function () { var _importRowData = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(_ref) { var data, db, c, fields, rows, rowsForDb, columns, createTableSql; return _regenerator["default"].wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: data = _ref.data, db = _ref.db, c = _ref.c; _context.prev = 1; fields = data.fields, rows = data.rows; // DATASET_FORMATS.keplergl loads data as any[][] instead of [{}] // TODO potential memory usage explosion: original data, new object and then DuckDb table rowsForDb = Array.isArray(rows[0]) ? rows.map(function (row) { var newRow = {}; row.forEach(function (value, index) { newRow[fields[index].name] = value; }); return newRow; }) : rows; _context.next = 6; return db.registerFileText(this.id, JSON.stringify(rowsForDb)); case 6: columns = fields.reduce(function (acc, field, index) { // @ts-expect-error TODO extend fields to contain duckDBColumnType return "".concat(acc).concat(index > 0 ? ',' : '', " '").concat(field.name, "': '").concat(field.duckDBColumnType, "'"); }, ''); createTableSql = "\n CREATE TABLE '".concat(this.label, "' AS\n SELECT *\n FROM read_json('").concat(this.id, "',\n columns = {").concat(columns, "});\n "); _context.next = 10; return c.query(createTableSql); case 10: _context.next = 16; break; case 12: _context.prev = 12; _context.t0 = _context["catch"](1); console.log('importRowData', _context.t0); throw _context.t0; case 16: case "end": return _context.stop(); } }, _callee, this, [[1, 12]]); })); function importRowData(_x) { return _importRowData.apply(this, arguments); } return importRowData; }() }, { key: "importGeoJsonData", value: function () { var _importGeoJsonData = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(_ref2) { var data, db, c, rows, createTableSql; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) switch (_context2.prev = _context2.next) { case 0: data = _ref2.data, db = _ref2.db, c = _ref2.c; _context2.prev = 1; rows = data.rows; _context2.next = 5; return db.registerFileText(this.id, JSON.stringify(rows)); case 5: createTableSql = "\n install spatial;\n load spatial;\n CREATE TABLE '".concat(this.label, "' AS \n SELECT *\n FROM ST_READ('").concat(this.id, "', keep_wkb = TRUE);\n ALTER TABLE '").concat(this.label, "' RENAME '").concat(DUCKDB_WKB_COLUMN, "' TO '").concat(KEPLER_GEOM_FROM_GEOJSON_COLUMN, "';\n "); _context2.next = 8; return c.query(createTableSql); case 8: _context2.next = 14; break; case 10: _context2.prev = 10; _context2.t0 = _context2["catch"](1); console.error('importGeoJsonData', _context2.t0); throw _context2.t0; case 14: return _context2.abrupt("return", { // _geojson column is created from geometry with keep_wkb flag and contains valid WKB data. geoarrowMetadata: (0, _defineProperty2["default"])({}, KEPLER_GEOM_FROM_GEOJSON_COLUMN, _constants.GEOARROW_EXTENSIONS.WKB) }); case 15: case "end": return _context2.stop(); } }, _callee2, this, [[1, 10]]); })); function importGeoJsonData(_x2) { return _importGeoJsonData.apply(this, arguments); } return importGeoJsonData; }() }, { key: "importArrowData", value: function () { var _importArrowData = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3(_ref3) { var data, c, adjustedMetadata, arrowTable, setupSql; return _regenerator["default"].wrap(function _callee3$(_context3) { while (1) switch (_context3.prev = _context3.next) { case 0: data = _ref3.data, c = _ref3.c; adjustedMetadata = {}; _context3.prev = 2; // 1) data.rows contains an arrow table created by Add to Map data from DuckDb query. // 2) arrow table is in cols & fields when a file is dragged & dropped into Add Data To Map dialog. arrowTable = data.rows instanceof arrow.Table ? data.rows : (0, _duckdbTableUtils2.restoreArrowTable)(data.cols || [], data.fields, data.arrowSchema); // remove unsupported extensions from an arrow table that throw exceptions in DuckDB. adjustedMetadata = (0, _duckdbTableUtils2.removeUnsupportedExtensions)(arrowTable); setupSql = "\n install spatial;\n load spatial;\n "; _context3.next = 8; return c.query(setupSql); case 8: _context3.next = 10; return c.insertArrowTable(arrowTable, { name: this.label }); case 10: // restore unsupported extensions that throw exceptions in DuckDb (0, _duckdbTableUtils2.restoreUnsupportedExtensions)(arrowTable, adjustedMetadata); _context3.next = 17; break; case 13: _context3.prev = 13; _context3.t0 = _context3["catch"](2); // Known issues: // 1) Arrow Type with extension name: geoarrow.point and format: +w:2 is not currently supported in DuckDB. console.error('importArrowData', _context3.t0); throw _context3.t0; case 17: return _context3.abrupt("return", { geoarrowMetadata: _objectSpread(_objectSpread({}, SUGGESTED_GEOM_COLUMNS), adjustedMetadata), // use fields generated from the created arrow table useNewFields: true }); case 18: case "end": return _context3.stop(); } }, _callee3, this, [[2, 13]]); })); function importArrowData(_x3) { return _importArrowData.apply(this, arguments); } return importArrowData; }() /** * Creates a table from data, returns an arrow table with the data * @param data * @returns {Promise<{fields: Field[], cols: any[]}>} */ }, { key: "createTableAndGetArrow", value: (function () { var _createTableAndGetArrow = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4(data) { var db, c, tableName, format, _data$rows, _data$rows2, _data$rows3, _data$cols, importDetails, fields, cols, _data$fields, _ref4, _ref4$geoarrowMetadat, geoarrowMetadata, _ref4$useNewFields, useNewFields, duckDbColumns, tableDuckDBTypes, adjustedQuery, arrowResult; return _regenerator["default"].wrap(function _callee4$(_context4) { while (1) switch (_context4.prev = _context4.next) { case 0: _context4.next = 2; return (0, _utils.getApplicationConfig)().database; case 2: db = _context4.sent; if (db) { _context4.next = 6; break; } console.error('The database is not configured properly.'); return _context4.abrupt("return", { fields: [], cols: [] }); case 6: _context4.next = 8; return db.connect(); case 8: c = _context4.sent; tableName = this.label; _context4.next = 12; return (0, _duckdbTableUtils2.dropTableIfExists)(c, tableName); case 12: format = this.metadata.format; if (!format) { // format is missing when we load Kepler.gl examples if (Array.isArray((_data$rows = data.rows) === null || _data$rows === void 0 ? void 0 : _data$rows[0]) || (0, _typeof2["default"])((_data$rows2 = data.rows) === null || _data$rows2 === void 0 ? void 0 : _data$rows2[0]) === 'object') { format = _constants.DATASET_FORMATS.row; } else if (((_data$rows3 = data.rows) === null || _data$rows3 === void 0 ? void 0 : _data$rows3.type) === 'FeatureCollection') { format = _constants.DATASET_FORMATS.geojson; } else if (((_data$cols = data.cols) === null || _data$cols === void 0 ? void 0 : _data$cols[0]) instanceof arrow.Vector) { format = _constants.DATASET_FORMATS.arrow; } } if (!(format === _constants.DATASET_FORMATS.row)) { _context4.next = 19; break; } _context4.next = 17; return this.importRowData({ data: data, db: db, c: c }); case 17: _context4.next = 32; break; case 19: if (!(format === _constants.DATASET_FORMATS.geojson)) { _context4.next = 25; break; } _context4.next = 22; return this.importGeoJsonData({ data: data, db: db, c: c }); case 22: importDetails = _context4.sent; _context4.next = 32; break; case 25: if (!(format === _constants.DATASET_FORMATS.arrow)) { _context4.next = 31; break; } _context4.next = 28; return this.importArrowData({ data: data, db: db, c: c }); case 28: importDetails = _context4.sent; _context4.next = 32; break; case 31: console.error('Unrecognized format', format); case 32: fields = []; cols = []; _context4.prev = 34; _ref4 = importDetails || {}, _ref4$geoarrowMetadat = _ref4.geoarrowMetadata, geoarrowMetadata = _ref4$geoarrowMetadat === void 0 ? {} : _ref4$geoarrowMetadat, _ref4$useNewFields = _ref4.useNewFields, useNewFields = _ref4$useNewFields === void 0 ? false : _ref4$useNewFields; _context4.next = 38; return (0, _duckdbTableUtils2.getDuckDBColumnTypes)(c, tableName); case 38: duckDbColumns = _context4.sent; tableDuckDBTypes = (0, _duckdbTableUtils2.getDuckDBColumnTypesMap)(duckDbColumns); adjustedQuery = (0, _duckdbTableUtils2.castDuckDBTypesForKepler)(tableName, duckDbColumns); _context4.next = 43; return c.query(adjustedQuery); case 43: arrowResult = _context4.sent; // TODO if format is an arrow table then just use the original one, instead of the new table from the query? restoreGeoarrowMetadata(arrowResult, geoarrowMetadata); fields = useNewFields ? (0, _processors.arrowSchemaToFields)(arrowResult, tableDuckDBTypes) : (_data$fields = data.fields) !== null && _data$fields !== void 0 ? _data$fields : (0, _processors.arrowSchemaToFields)(arrowResult, tableDuckDBTypes); cols = (0, _toConsumableArray2["default"])(Array(arrowResult.numCols).keys()).map(function (i) { return arrowResult.getChildAt(i); }).filter(function (col) { return col; }); _context4.next = 53; break; case 49: _context4.prev = 49; _context4.t0 = _context4["catch"](34); console.error('DuckDB table: createTableAndGetArrow', _context4.t0); throw _context4.t0; case 53: _context4.next = 55; return c.close(); case 55: return _context4.abrupt("return", { fields: fields, cols: cols }); case 56: case "end": return _context4.stop(); } }, _callee4, this, [[34, 49]]); })); function createTableAndGetArrow(_x4) { return _createTableAndGetArrow.apply(this, arguments); } return createTableAndGetArrow; }()) }, { key: "importData", value: function () { var _importData = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee5(_ref5) { var data, _yield$this$createTab, fields, cols; return _regenerator["default"].wrap(function _callee5$(_context5) { while (1) switch (_context5.prev = _context5.next) { case 0: data = _ref5.data; if (!(this.type === _constants.DatasetType.VECTOR_TILE)) { _context5.next = 4; break; } _superPropGet(KeplerGlDuckDbTable, "importData", this, 3)([{ data: _objectSpread(_objectSpread({}, data), {}, { rows: [] }) }]); return _context5.abrupt("return"); case 4: _context5.next = 6; return this.createTableAndGetArrow(data); case 6: _yield$this$createTab = _context5.sent; fields = _yield$this$createTab.fields; cols = _yield$this$createTab.cols; _superPropGet(KeplerGlDuckDbTable, "importData", this, 3)([{ data: { fields: fields, cols: cols, rows: [] } }]); case 10: case "end": return _context5.stop(); } }, _callee5, this); })); function importData(_x5) { return _importData.apply(this, arguments); } return importData; }() }, { key: "update", value: function () { var _update = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee6(data) { var _yield$this$createTab2, cols; return _regenerator["default"].wrap(function _callee6$(_context6) { while (1) switch (_context6.prev = _context6.next) { case 0: if (!(this.type === _constants.DatasetType.VECTOR_TILE)) { _context6.next = 3; break; } _superPropGet(KeplerGlDuckDbTable, "importData", this, 3)([{ data: data }]); return _context6.abrupt("return", this); case 3: _context6.next = 5; return this.createTableAndGetArrow(data); case 5: _yield$this$createTab2 = _context6.sent; cols = _yield$this$createTab2.cols; return _context6.abrupt("return", _superPropGet(KeplerGlDuckDbTable, "update", this, 3)([{ cols: cols, rows: [], fields: [] }])); case 8: case "end": return _context6.stop(); } }, _callee6, this); })); function update(_x6) { return _update.apply(this, arguments); } return update; }() }]); }(_table.KeplerTable); /** * Try to restore geoarrow metadata lost during DuckDb ingestion. * Note that this function can generate wrong geometry types. * @param arrowTable Arrow table to update. * @param geoarrowMetadata A map with field names that usually used to store geoarrow geometry. */ (0, _defineProperty2["default"])(KeplerGlDuckDbTable, "getFileProcessor", function (data, inputFormat) { var processor; var format; if (inputFormat === _constants.DATASET_FORMATS.arrow || (0, _processors.isArrowData)(data)) { format = _constants.DATASET_FORMATS.arrow; processor = _processors.processArrowBatches; } else if (inputFormat === _constants.DATASET_FORMATS.keplergl || (0, _processors.isKeplerGlMap)(data)) { format = _constants.DATASET_FORMATS.keplergl; processor = _dataProcessor.processKeplerglJSONforDuckDb; } else if (inputFormat === _constants.DATASET_FORMATS.row || (0, _processors.isRowObject)(data)) { // csv file goes here format = _constants.DATASET_FORMATS.row; processor = _dataProcessor.processCsvRowObject; // directly import json object into duckdb-wasm } else if (inputFormat === _constants.DATASET_FORMATS.geojson || (0, _processors.isGeoJson)(data)) { format = _constants.DATASET_FORMATS.geojson; processor = _dataProcessor.processGeojson; } return { processor: processor, format: format }; }); (0, _defineProperty2["default"])(KeplerGlDuckDbTable, "getInputDataValidator", function () { // In DuckDB mode data is validated later during import. return function (d) { return d; }; }); var restoreGeoarrowMetadata = exports.restoreGeoarrowMetadata = function restoreGeoarrowMetadata(arrowTable, geoarrowMetadata) { arrowTable.schema.fields.forEach(function (f) { if (arrow.DataType.isBinary(f.type) && geoarrowMetadata[f.name]) { f.metadata.set(_constants.GEOARROW_METADATA_KEY, geoarrowMetadata[f.name]); } else if ((0, _duckdbTableUtils.isGeoArrowPoint)(f.type)) { f.metadata.set(_constants.GEOARROW_METADATA_KEY, _constants.GEOARROW_EXTENSIONS.POINT); } else if ((0, _duckdbTableUtils.isGeoArrowLineString)(f.type)) { f.metadata.set(_constants.GEOARROW_METADATA_KEY, _constants.GEOARROW_EXTENSIONS.LINESTRING); } else if ((0, _duckdbTableUtils.isGeoArrowPolygon)(f.type)) { f.metadata.set(_constants.GEOARROW_METADATA_KEY, _constants.GEOARROW_EXTENSIONS.POLYGON); } else if ((0, _duckdbTableUtils.isGeoArrowMultiPoint)(f.type)) { f.metadata.set(_constants.GEOARROW_METADATA_KEY, _constants.GEOARROW_EXTENSIONS.MULTIPOINT); } else if ((0, _duckdbTableUtils.isGeoArrowMultiLineString)(f.type)) { f.metadata.set(_constants.GEOARROW_METADATA_KEY, _constants.GEOARROW_EXTENSIONS.MULTILINESTRING); } else if ((0, _duckdbTableUtils.isGeoArrowMultiPolygon)(f.type)) { f.metadata.set(_constants.GEOARROW_METADATA_KEY, _constants.GEOARROW_EXTENSIONS.MULTIPOLYGON); } }); }; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJhcnJvdyIsIl9pbnRlcm9wUmVxdWlyZVdpbGRjYXJkIiwicmVxdWlyZSIsIl9jb25zdGFudHMiLCJfcHJvY2Vzc29ycyIsIl90YWJsZSIsIl91dGlscyIsIl9kYXRhUHJvY2Vzc29yIiwiX2R1Y2tkYlRhYmxlVXRpbHMiLCJfZHVja2RiVGFibGVVdGlsczIiLCJfZ2V0UmVxdWlyZVdpbGRjYXJkQ2FjaGUiLCJlIiwiV2Vha01hcCIsInIiLCJ0IiwiX19lc01vZHVsZSIsIl90eXBlb2YzIiwiaGFzIiwiZ2V0IiwibiIsIl9fcHJvdG9fXyIsImEiLCJPYmplY3QiLCJkZWZpbmVQcm9wZXJ0eSIsImdldE93blByb3BlcnR5RGVzY3JpcHRvciIsInUiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJpIiwic2V0Iiwib3duS2V5cyIsImtleXMiLCJnZXRPd25Qcm9wZXJ0eVN5bWJvbHMiLCJvIiwiZmlsdGVyIiwiZW51bWVyYWJsZSIsInB1c2giLCJhcHBseSIsIl9vYmplY3RTcHJlYWQiLCJhcmd1bWVudHMiLCJsZW5ndGgiLCJmb3JFYWNoIiwiX2RlZmluZVByb3BlcnR5MiIsImdldE93blByb3BlcnR5RGVzY3JpcHRvcnMiLCJkZWZpbmVQcm9wZXJ0aWVzIiwiX2NhbGxTdXBlciIsIl9nZXRQcm90b3R5cGVPZjIiLCJfcG9zc2libGVDb25zdHJ1Y3RvclJldHVybjIiLCJfaXNOYXRpdmVSZWZsZWN0Q29uc3RydWN0IiwiUmVmbGVjdCIsImNvbnN0cnVjdCIsImNvbnN0cnVjdG9yIiwiQm9vbGVhbiIsInByb3RvdHlwZSIsInZhbHVlT2YiLCJfc3VwZXJQcm9wR2V0IiwicCIsIl9nZXQyIiwiRFVDS0RCX0dFT01fQ09MVU1OIiwiRFVDS0RCX1dLQl9DT0xVTU4iLCJLRVBMRVJfR0VPTV9GUk9NX0dFT0pTT05fQ09MVU1OIiwiU1VHR0VTVEVEX0dFT01fQ09MVU1OUyIsIkdFT0FSUk9XX0VYVEVOU0lPTlMiLCJXS0IiLCJLZXBsZXJHbER1Y2tEYlRhYmxlIiwiZXhwb3J0cyIsIl9LZXBsZXJUYWJsZSIsInByb3BzIiwiX2NsYXNzQ2FsbENoZWNrMiIsIl9pbmhlcml0czIiLCJfY3JlYXRlQ2xhc3MyIiwia2V5IiwidmFsdWUiLCJfaW1wb3J0Um93RGF0YSIsIl9hc3luY1RvR2VuZXJhdG9yMiIsIl9yZWdlbmVyYXRvciIsIm1hcmsiLCJfY2FsbGVlIiwiX3JlZiIsImRhdGEiLCJkYiIsImMiLCJmaWVsZHMiLCJyb3dzIiwicm93c0ZvckRiIiwiY29sdW1ucyIsImNyZWF0ZVRhYmxlU3FsIiwid3JhcCIsIl9jYWxsZWUkIiwiX2NvbnRleHQiLCJwcmV2IiwibmV4dCIsIkFycmF5IiwiaXNBcnJheSIsIm1hcCIsInJvdyIsIm5ld1JvdyIsImluZGV4IiwibmFtZSIsInJlZ2lzdGVyRmlsZVRleHQiLCJpZCIsIkpTT04iLCJzdHJpbmdpZnkiLCJyZWR1Y2UiLCJhY2MiLCJmaWVsZCIsImNvbmNhdCIsImR1Y2tEQkNvbHVtblR5cGUiLCJsYWJlbCIsInF1ZXJ5IiwidDAiLCJjb25zb2xlIiwibG9nIiwic3RvcCIsImltcG9ydFJvd0RhdGEiLCJfeCIsIl9pbXBvcnRHZW9Kc29uRGF0YSIsIl9jYWxsZWUyIiwiX3JlZjIiLCJfY2FsbGVlMiQiLCJfY29udGV4dDIiLCJlcnJvciIsImFicnVwdCIsImdlb2Fycm93TWV0YWRhdGEiLCJpbXBvcnRHZW9Kc29uRGF0YSIsIl94MiIsIl9pbXBvcnRBcnJvd0RhdGEiLCJfY2FsbGVlMyIsIl9yZWYzIiwiYWRqdXN0ZWRNZXRhZGF0YSIsImFycm93VGFibGUiLCJzZXR1cFNxbCIsIl9jYWxsZWUzJCIsIl9jb250ZXh0MyIsIlRhYmxlIiwicmVzdG9yZUFycm93VGFibGUiLCJjb2xzIiwiYXJyb3dTY2hlbWEiLCJyZW1vdmVVbnN1cHBvcnRlZEV4dGVuc2lvbnMiLCJpbnNlcnRBcnJvd1RhYmxlIiwicmVzdG9yZVVuc3VwcG9ydGVkRXh0ZW5zaW9ucyIsInVzZU5ld0ZpZWxkcyIsImltcG9ydEFycm93RGF0YSIsIl94MyIsIl9jcmVhdGVUYWJsZUFuZEdldEFycm93IiwiX2NhbGxlZTQiLCJ0YWJsZU5hbWUiLCJmb3JtYXQiLCJfZGF0YSRyb3dzIiwiX2RhdGEkcm93czIiLCJfZGF0YSRyb3dzMyIsIl9kYXRhJGNvbHMiLCJpbXBvcnREZXRhaWxzIiwiX2RhdGEkZmllbGRzIiwiX3JlZjQiLCJfcmVmNCRnZW9hcnJvd01ldGFkYXQiLCJfcmVmNCR1c2VOZXdGaWVsZHMiLCJkdWNrRGJDb2x1bW5zIiwidGFibGVEdWNrREJUeXBlcyIsImFkanVzdGVkUXVlcnkiLCJhcnJvd1Jlc3VsdCIsIl9jYWxsZWU0JCIsIl9jb250ZXh0NCIsImdldEFwcGxpY2F0aW9uQ29uZmlnIiwiZGF0YWJhc2UiLCJzZW50IiwiY29ubmVjdCIsImRyb3BUYWJsZUlmRXhpc3RzIiwibWV0YWRhdGEiLCJfdHlwZW9mMiIsIkRBVEFTRVRfRk9STUFUUyIsInR5cGUiLCJnZW9qc29uIiwiVmVjdG9yIiwiZ2V0RHVja0RCQ29sdW1uVHlwZXMiLCJnZXREdWNrREJDb2x1bW5UeXBlc01hcCIsImNhc3REdWNrREJUeXBlc0ZvcktlcGxlciIsInJlc3RvcmVHZW9hcnJvd01ldGFkYXRhIiwiYXJyb3dTY2hlbWFUb0ZpZWxkcyIsIl90b0NvbnN1bWFibGVBcnJheTIiLCJudW1Db2xzIiwiZ2V0Q2hpbGRBdCIsImNvbCIsImNsb3NlIiwiY3JlYXRlVGFibGVBbmRHZXRBcnJvdyIsIl94NCIsIl9pbXBvcnREYXRhIiwiX2NhbGxlZTUiLCJfcmVmNSIsIl95aWVsZCR0aGlzJGNyZWF0ZVRhYiIsIl9jYWxsZWU1JCIsIl9jb250ZXh0NSIsIkRhdGFzZXRUeXBlIiwiVkVDVE9SX1RJTEUiLCJpbXBvcnREYXRhIiwiX3g1IiwiX3VwZGF0ZSIsIl9jYWxsZWU2IiwiX3lpZWxkJHRoaXMkY3JlYXRlVGFiMiIsIl9jYWxsZWU2JCIsIl9jb250ZXh0NiIsInVwZGF0ZSIsIl94NiIsIktlcGxlclRhYmxlIiwiaW5wdXRGb3JtYXQiLCJwcm9jZXNzb3IiLCJpc0Fycm93RGF0YSIsInByb2Nlc3NBcnJvd0JhdGNoZXMiLCJrZXBsZXJnbCIsImlzS2VwbGVyR2xNYXAiLCJwcm9jZXNzS2VwbGVyZ2xKU09OZm9yRHVja0RiIiwiaXNSb3dPYmplY3QiLCJwcm9jZXNzQ3N2Um93T2JqZWN0IiwiaXNHZW9Kc29uIiwicHJvY2Vzc0dlb2pzb24iLCJkIiwic2NoZW1hIiwiZiIsIkRhdGFUeXBlIiwiaXNCaW5hcnkiLCJHRU9BUlJPV19NRVRBREFUQV9LRVkiLCJpc0dlb0Fycm93UG9pbnQiLCJQT0lOVCIsImlzR2VvQXJyb3dMaW5lU3RyaW5nIiwiTElORVNUUklORyIsImlzR2VvQXJyb3dQb2x5Z29uIiwiUE9MWUdPTiIsImlzR2VvQXJyb3dNdWx0aVBvaW50IiwiTVVMVElQT0lOVCIsImlzR2VvQXJyb3dNdWx0aUxpbmVTdHJpbmciLCJNVUxUSUxJTkVTVFJJTkciLCJpc0dlb0Fycm93TXVsdGlQb2x5Z29uIiwiTVVMVElQT0xZR09OIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3RhYmxlL2R1Y2tkYi10YWJsZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogTUlUXG4vLyBDb3B5cmlnaHQgY29udHJpYnV0b3JzIHRvIHRoZSBrZXBsZXIuZ2wgcHJvamVjdFxuXG5pbXBvcnQgKiBhcyBhcnJvdyBmcm9tICdhcGFjaGUtYXJyb3cnO1xuXG5pbXBvcnQge1xuICBEYXRhc2V0VHlwZSxcbiAgREFUQVNFVF9GT1JNQVRTLFxuICBHRU9BUlJPV19FWFRFTlNJT05TLFxuICBHRU9BUlJPV19NRVRBREFUQV9LRVlcbn0gZnJvbSAnQGtlcGxlci5nbC9jb25zdGFudHMnO1xuaW1wb3J0IHtcbiAgYXJyb3dTY2hlbWFUb0ZpZWxkcyxcbiAgaXNBcnJvd0RhdGEsXG4gIGlzR2VvSnNvbixcbiAgaXNLZXBsZXJHbE1hcCxcbiAgaXNSb3dPYmplY3QsXG4gIHByb2Nlc3NBcnJvd0JhdGNoZXNcbn0gZnJvbSAnQGtlcGxlci5nbC9wcm9jZXNzb3JzJztcbmltcG9ydCB7S2VwbGVyVGFibGV9IGZyb20gJ0BrZXBsZXIuZ2wvdGFibGUnO1xuaW1wb3J0IHtGaWVsZH0gZnJvbSAnQGtlcGxlci5nbC90eXBlcyc7XG5pbXBvcnQge2dldEFwcGxpY2F0aW9uQ29uZmlnLCBEYXRhYmFzZUFkYXB0ZXIsIERhdGFiYXNlQ29ubmVjdGlvbn0gZnJvbSAnQGtlcGxlci5nbC91dGlscyc7XG5cbmltcG9ydCB7XG4gIHByb2Nlc3NDc3ZSb3dPYmplY3QsXG4gIHByb2Nlc3NHZW9qc29uLFxuICBwcm9jZXNzS2VwbGVyZ2xKU09OZm9yRHVja0RiLFxuICBQcm9jZXNzb3JSZXN1bHRcbn0gZnJvbSAnLi4vcHJvY2Vzc29ycy9kYXRhLXByb2Nlc3Nvcic7XG5cbmltcG9ydCB7XG4gIGlzR2VvQXJyb3dQb2ludCxcbiAgaXNHZW9BcnJvd0xpbmVTdHJpbmcsXG4gIGlzR2VvQXJyb3dQb2x5Z29uLFxuICBpc0dlb0Fycm93TXVsdGlQb2ludCxcbiAgaXNHZW9BcnJvd011bHRpTGluZVN0cmluZyxcbiAgaXNHZW9BcnJvd011bHRpUG9seWdvblxufSBmcm9tICcuL2R1Y2tkYi10YWJsZS11dGlscyc7XG5cbmltcG9ydCB7XG4gIGNhc3REdWNrREJUeXBlc0ZvcktlcGxlcixcbiAgZHJvcFRhYmxlSWZFeGlzdHMsXG4gIGdldER1Y2tEQkNvbHVtblR5cGVzLFxuICBnZXREdWNrREJDb2x1bW5UeXBlc01hcCxcbiAgcmVtb3ZlVW5zdXBwb3J0ZWRFeHRlbnNpb25zLFxuICByZXN0b3JlQXJyb3dUYWJsZSxcbiAgcmVzdG9yZVVuc3VwcG9ydGVkRXh0ZW5zaW9uc1xufSBmcm9tICcuLi90YWJsZS9kdWNrZGItdGFibGUtdXRpbHMnO1xuXG4vLyBUT0RPIHVzZSBmaWxlcyBmcm9tIGRpc2sgb3IgdXJsIGRpcmVjdGx5LCB3aXRob3V0IHBhcnNpbmcgYnkgbG9hZGVycyBhbmQgdGhlbiBpbmdlY3Rpb24gaW50byBEZWNrRGJcblxuLyoqXG4gKiBEZWZhdWx0IER1Y2tEYiBnZW9tZXRyeSBjb2x1bW5zIGNyZWF0ZWQgYnkgU1RfUkVBRFxuICovXG5jb25zdCBEVUNLREJfR0VPTV9DT0xVTU4gPSAnZ2VvbSc7XG5jb25zdCBEVUNLREJfV0tCX0NPTFVNTiA9ICd3a2JfZ2VvbWV0cnknO1xuXG4vKipcbiBEZWZhdWx0IGNvbHVtbiBuYW1lIGZvciBwcm9jZXNzZWQgZ2VvanNvbiBpbiBLZXBsZXIuXG4gVXNlIHRoaXMgbmFtZSB0byByZW5hbWUgZGVmYXVsdCAnZ2VvbScgY29sdW1uIGZyb20gRHVja0RiXG4gaW4gb3JkZXIgdG8gc3VwcG9ydCBLZXBsZXIgbWFwcyBzYXZlZCBiZWZvcmUgaW50cm9kdWN0aW9uIG9mIER1Y2tEYiBwbHVnaW4uXG4gKi9cbmNvbnN0IEtFUExFUl9HRU9NX0ZST01fR0VPSlNPTl9DT0xVTU4gPSAnX2dlb2pzb24nO1xuXG4vKipcbiAqIE5hbWVzIG9mIGNvbHVtbnMgdGhhdCBtb3N0IGxpa2VseSBjb250YWluIGJpbmFyeSB3a2IgZ2VvbWV0cnlcbiAqL1xuY29uc3QgU1VHR0VTVEVEX0dFT01fQ09MVU1OUyA9IHtcbiAgW0tFUExFUl9HRU9NX0ZST01fR0VPSlNPTl9DT0xVTU5dOiBHRU9BUlJPV19FWFRFTlNJT05TLldLQixcbiAgW0RVQ0tEQl9HRU9NX0NPTFVNTl06IEdFT0FSUk9XX0VYVEVOU0lPTlMuV0tCLFxuICBnZW9tZXRyeTogR0VPQVJST1dfRVhURU5TSU9OUy5XS0Jcbn07XG5cbnR5cGUgSW1wb3J0RGF0YVRvRHVja1Byb3BzID0ge1xuICBkYXRhOiBQcm9jZXNzb3JSZXN1bHQgJiB7YXJyb3dTY2hlbWE6IGFycm93LlNjaGVtYX07XG4gIGRiOiBEYXRhYmFzZUFkYXB0ZXI7XG4gIGM6IERhdGFiYXNlQ29ubmVjdGlvbjtcbn07XG5cbnR5cGUgSW1wb3J0RGF0YVRvRHVja1Jlc3VsdCA9IHtcbiAgLy8gRHVja0RiIGRyb3BzIGdlb2Fycm93IG1ldGFkYXRhLCBzbyB0cnkgdG8gcHJlc2VydmUgYW5kIHRoZW4gcmVzdG9yZSB0aGUgZXh0ZW5zaW9uIG5hbWVcbiAgZ2VvYXJyb3dNZXRhZGF0YT86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIC8vIFVzZSBmaWVsZHMgZnJvbSBhcnJvdyB0YWJsZSBldmVuIGlmIGZpZWxkcyBhcmUgcHJvdmlkZWRcbiAgdXNlTmV3RmllbGRzPzogYm9vbGVhbjtcbn07XG5cbmV4cG9ydCBjbGFzcyBLZXBsZXJHbER1Y2tEYlRhYmxlIGV4dGVuZHMgS2VwbGVyVGFibGUge1xuICBkZWNsYXJlIHJlYWRvbmx5IGlkOiBzdHJpbmc7XG4gIGRlY2xhcmUgbGFiZWw6IHN0cmluZztcbiAgZGVjbGFyZSB0eXBlOiBzdHJpbmc7XG4gIGRlY2xhcmUgbWV0YWRhdGE6IFJlY29yZDxzdHJpbmcsIGFueT47XG5cbiAgY29uc3RydWN0b3IocHJvcHMpIHtcbiAgICBzdXBlcihwcm9wcyk7XG4gIH1cblxuICBhc3luYyBpbXBvcnRSb3dEYXRhKHtkYXRhLCBkYiwgY306IEltcG9ydERhdGFUb0R1Y2tQcm9wcyk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCB7ZmllbGRzLCByb3dzfSA9IGRhdGE7XG5cbiAgICAgIC8vIERBVEFTRVRfRk9STUFUUy5rZXBsZXJnbCBsb2FkcyBkYXRhIGFzIGFueVtdW10gaW5zdGVhZCBvZiBbe31dXG4gICAgICAvLyBUT0RPIHBvdGVudGlhbCBtZW1vcnkgdXNhZ2UgZXhwbG9zaW9uOiBvcmlnaW5hbCBkYXRhLCBuZXcgb2JqZWN0IGFuZCB0aGVuIER1Y2tEYiB0YWJsZVxuICAgICAgY29uc3Qgcm93c0ZvckRiID0gQXJyYXkuaXNBcnJheShyb3dzWzBdKVxuICAgICAgICA/IHJvd3MubWFwKHJvdyA9PiB7XG4gICAgICAgICAgICBjb25zdCBuZXdSb3cgPSB7fTtcbiAgICAgICAgICAgIHJvdy5mb3JFYWNoKCh2YWx1ZSwgaW5kZXgpID0+IHtcbiAgICAgICAgICAgICAgbmV3Um93W2ZpZWxkc1tpbmRleF0ubmFtZV0gPSB2YWx1ZTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIG5ld1JvdztcbiAgICAgICAgICB9KVxuICAgICAgICA6IHJvd3M7XG5cbiAgICAgIGF3YWl0IGRiLnJlZ2lzdGVyRmlsZVRleHQodGhpcy5pZCwgSlNPTi5zdHJpbmdpZnkocm93c0ZvckRiKSk7XG5cbiAgICAgIGNvbnN0IGNvbHVtbnMgPSBmaWVsZHMucmVkdWNlKChhY2MsIGZpZWxkLCBpbmRleCkgPT4ge1xuICAgICAgICAvLyBAdHMtZXhwZWN0LWVycm9yIFRPRE8gZXh0ZW5kIGZpZWxkcyB0byBjb250YWluIGR1Y2tEQkNvbHVtblR5cGVcbiAgICAgICAgcmV0dXJuIGAke2FjY30ke2luZGV4ID4gMCA/ICcsJyA6ICcnfSAnJHtmaWVsZC5uYW1lfSc6ICcke2ZpZWxkLmR1Y2tEQkNvbHVtblR5cGV9J2A7XG4gICAgICB9LCAnJyk7XG5cbiAgICAgIGNvbnN0IGNyZWF0ZVRhYmxlU3FsID0gYFxuICAgICAgICBDUkVBVEUgVEFCTEUgJyR7dGhpcy5sYWJlbH0nIEFTXG4gICAgICAgIFNFTEVDVCAqXG4gICAgICAgIEZST00gcmVhZF9qc29uKCcke3RoaXMuaWR9JyxcbiAgICAgICAgICAgICAgICAgICAgICAgY29sdW1ucyA9IHske2NvbHVtbnN9fSk7XG4gICAgICBgO1xuICAgICAgYXdhaXQgYy5xdWVyeShjcmVhdGVUYWJsZVNxbCk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUubG9nKCdpbXBvcnRSb3dEYXRhJywgZXJyb3IpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgaW1wb3J0R2VvSnNvbkRhdGEoe2RhdGEsIGRiLCBjfTogSW1wb3J0RGF0YVRvRHVja1Byb3BzKTogUHJvbWlzZTxJbXBvcnREYXRhVG9EdWNrUmVzdWx0PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHtyb3dzfSA9IGRhdGE7XG4gICAgICBhd2FpdCBkYi5yZWdpc3RlckZpbGVUZXh0KHRoaXMuaWQsIEpTT04uc3RyaW5naWZ5KHJvd3MpKTtcblxuICAgICAgY29uc3QgY3JlYXRlVGFibGVTcWwgPSBgXG4gICAgICAgIGluc3RhbGwgc3BhdGlhbDtcbiAgICAgICAgbG9hZCBzcGF0aWFsO1xuICAgICAgICBDUkVBVEUgVEFCTEUgJyR7dGhpcy5sYWJlbH0nIEFTIFxuICAgICAgICBTRUxFQ1QgKlxuICAgICAgICBGUk9NIFNUX1JFQUQoJyR7dGhpcy5pZH0nLCBrZWVwX3drYiA9IFRSVUUpO1xuICAgICAgICBBTFRFUiBUQUJMRSAnJHt0aGlzLmxhYmVsfScgUkVOQU1FICcke0RVQ0tEQl9XS0JfQ09MVU1OfScgVE8gJyR7S0VQTEVSX0dFT01fRlJPTV9HRU9KU09OX0NPTFVNTn0nO1xuICAgICAgYDtcblxuICAgICAgYXdhaXQgYy5xdWVyeShjcmVhdGVUYWJsZVNxbCk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ2ltcG9ydEdlb0pzb25EYXRhJywgZXJyb3IpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIC8vIF9nZW9qc29uIGNvbHVtbiBpcyBjcmVhdGVkIGZyb20gZ2VvbWV0cnkgd2l0aCBrZWVwX3drYiBmbGFnIGFuZCBjb250YWlucyB2YWxpZCBXS0IgZGF0YS5cbiAgICAgIGdlb2Fycm93TWV0YWRhdGE6IHtbS0VQTEVSX0dFT01fRlJPTV9HRU9KU09OX0NPTFVNTl06IEdFT0FSUk9XX0VYVEVOU0lPTlMuV0tCfVxuICAgIH07XG4gIH1cblxuICBhc3luYyBpbXBvcnRBcnJvd0RhdGEoe2RhdGEsIGN9OiBJbXBvcnREYXRhVG9EdWNrUHJvcHMpOiBQcm9taXNlPEltcG9ydERhdGFUb0R1Y2tSZXN1bHQ+IHtcbiAgICBsZXQgYWRqdXN0ZWRNZXRhZGF0YSA9IHt9O1xuICAgIHRyeSB7XG4gICAgICAvLyAxKSBkYXRhLnJvd3MgY29udGFpbnMgYW4gYXJyb3cgdGFibGUgY3JlYXRlZCBieSBBZGQgdG8gTWFwIGRhdGEgZnJvbSBEdWNrRGIgcXVlcnkuXG4gICAgICAvLyAyKSBhcnJvdyB0YWJsZSBpcyBpbiBjb2xzICYgZmllbGRzIHdoZW4gYSBmaWxlIGlzIGRyYWdnZWQgJiBkcm9wcGVkIGludG8gQWRkIERhdGEgVG8gTWFwIGRpYWxvZy5cbiAgICAgIGNvbnN0IGFycm93VGFibGUgPVxuICAgICAgICBkYXRhLnJvd3MgaW5zdGFuY2VvZiBhcnJvdy5UYWJsZVxuICAgICAgICAgID8gZGF0YS5yb3dzXG4gICAgICAgICAgOiByZXN0b3JlQXJyb3dUYWJsZShkYXRhLmNvbHMgfHwgW10sIGRhdGEuZmllbGRzLCBkYXRhLmFycm93U2NoZW1hKTtcblxuICAgICAgLy8gcmVtb3ZlIHVuc3VwcG9ydGVkIGV4dGVuc2lvbnMgZnJvbSBhbiBhcnJvdyB0YWJsZSB0aGF0IHRocm93IGV4Y2VwdGlvbnMgaW4gRHVja0RCLlxuICAgICAgYWRqdXN0ZWRNZXRhZGF0YSA9IHJlbW92ZVVuc3VwcG9ydGVkRXh0ZW5zaW9ucyhhcnJvd1RhYmxlKTtcblxuICAgICAgY29uc3Qgc2V0dXBTcWwgPSBgXG4gICAgICAgIGluc3RhbGwgc3BhdGlhbDtcbiAgICAgICAgbG9hZCBzcGF0aWFsO1xuICAgICAgYDtcbiAgICAgIGF3YWl0IGMucXVlcnkoc2V0dXBTcWwpO1xuICAgICAgYXdhaXQgYy5pbnNlcnRBcnJvd1RhYmxlKGFycm93VGFibGUsIHtuYW1lOiB0aGlzLmxhYmVsfSk7XG5cbiAgICAgIC8vIHJlc3RvcmUgdW5zdXBwb3J0ZWQgZXh0ZW5zaW9ucyB0aGF0IHRocm93IGV4Y2VwdGlvbnMgaW4gRHVja0RiXG4gICAgICByZXN0b3JlVW5zdXBwb3J0ZWRFeHRlbnNpb25zKGFycm93VGFibGUsIGFkanVzdGVkTWV0YWRhdGEpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAvLyBLbm93biBpc3N1ZXM6XG4gICAgICAvLyAxKSBBcnJvdyBUeXBlIHdpdGggZXh0ZW5zaW9uIG5hbWU6IGdlb2Fycm93LnBvaW50IGFuZCBmb3JtYXQ6ICt3OjIgaXMgbm90IGN1cnJlbnRseSBzdXBwb3J0ZWQgaW4gRHVja0RCLlxuICAgICAgY29uc29sZS5lcnJvcignaW1wb3J0QXJyb3dEYXRhJywgZXJyb3IpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGdlb2Fycm93TWV0YWRhdGE6IHsuLi5TVUdHRVNURURfR0VPTV9DT0xVTU5TLCAuLi5hZGp1c3RlZE1ldGFkYXRhfSxcbiAgICAgIC8vIHVzZSBmaWVsZHMgZ2VuZXJhdGVkIGZyb20gdGhlIGNyZWF0ZWQgYXJyb3cgdGFibGVcbiAgICAgIHVzZU5ld0ZpZWxkczogdHJ1ZVxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIHRhYmxlIGZyb20gZGF0YSwgcmV0dXJucyBhbiBhcnJvdyB0YWJsZSB3aXRoIHRoZSBkYXRhXG4gICAqIEBwYXJhbSBkYXRhXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHtmaWVsZHM6IEZpZWxkW10sIGNvbHM6IGFueVtdfT59XG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgY3JlYXRlVGFibGVBbmRHZXRBcnJvdyhkYXRhKTogUHJvbWlzZTx7ZmllbGRzOiBhbnlbXTsgY29sczogYXJyb3cuVmVjdG9yW119PiB7XG4gICAgY29uc3QgZGIgPSBhd2FpdCBnZXRBcHBsaWNhdGlvbkNvbmZpZygpLmRhdGFiYXNlO1xuICAgIGlmICghZGIpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ1RoZSBkYXRhYmFzZSBpcyBub3QgY29uZmlndXJlZCBwcm9wZXJseS4nKTtcbiAgICAgIHJldHVybiB7ZmllbGRzOiBbXSwgY29sczogW119O1xuICAgIH1cbiAgICBjb25zdCBjID0gYXdhaXQgZGIuY29ubmVjdCgpO1xuXG4gICAgY29uc3QgdGFibGVOYW1lID0gdGhpcy5sYWJlbDtcbiAgICBhd2FpdCBkcm9wVGFibGVJZkV4aXN0cyhjLCB0YWJsZU5hbWUpO1xuXG4gICAgbGV0IGZvcm1hdCA9IHRoaXMubWV0YWRhdGEuZm9ybWF0O1xuICAgIGlmICghZm9ybWF0KSB7XG4gICAgICAvLyBmb3JtYXQgaXMgbWlzc2luZyB3aGVuIHdlIGxvYWQgS2VwbGVyLmdsIGV4YW1wbGVzXG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShkYXRhLnJvd3M/LlswXSkgfHwgdHlwZW9mIGRhdGEucm93cz8uWzBdID09PSAnb2JqZWN0Jykge1xuICAgICAgICBmb3JtYXQgPSBEQVRBU0VUX0ZPUk1BVFMucm93O1xuICAgICAgfSBlbHNlIGlmIChkYXRhLnJvd3M/LnR5cGUgPT09ICdGZWF0dXJlQ29sbGVjdGlvbicpIHtcbiAgICAgICAgZm9ybWF0ID0gREFUQVNFVF9GT1JNQVRTLmdlb2pzb247XG4gICAgICB9IGVsc2UgaWYgKGRhdGEuY29scz8uWzBdIGluc3RhbmNlb2YgYXJyb3cuVmVjdG9yKSB7XG4gICAgICAgIGZvcm1hdCA9IERBVEFTRVRfRk9STUFUUy5hcnJvdztcbiAgICAgIH1cbiAgICB9XG5cbiAgICBsZXQgaW1wb3J0RGV0YWlsczogSW1wb3J0RGF0YVRvRHVja1Jlc3VsdCB8IHVuZGVmaW5lZDtcbiAgICBpZiAoZm9ybWF0ID09PSBEQVRBU0VUX0ZPUk1BVFMucm93KSB7XG4gICAgICBhd2FpdCB0aGlzLmltcG9ydFJvd0RhdGEoe2RhdGEsIGRiLCBjfSk7XG4gICAgfSBlbHNlIGlmIChmb3JtYXQgPT09IERBVEFTRVRfRk9STUFUUy5nZW9qc29uKSB7XG4gICAgICBpbXBvcnREZXRhaWxzID0gYXdhaXQgdGhpcy5pbXBvcnRHZW9Kc29uRGF0YSh7ZGF0YSwgZGIsIGN9KTtcbiAgICB9IGVsc2UgaWYgKGZvcm1hdCA9PT0gREFUQVNFVF9GT1JNQVRTLmFycm93KSB7XG4gICAgICBpbXBvcnREZXRhaWxzID0gYXdhaXQgdGhpcy5pbXBvcnRBcnJvd0RhdGEoe2RhdGEsIGRiLCBjfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ1VucmVjb2duaXplZCBmb3JtYXQnLCBmb3JtYXQpO1xuICAgIH1cblxuICAgIGxldCBmaWVsZHM6IEZpZWxkW10gPSBbXTtcbiAgICBsZXQgY29sczogYXJyb3cuVmVjdG9yW10gPSBbXTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCB7Z2VvYXJyb3dNZXRhZGF0YSA9IHt9LCB1c2VOZXdGaWVsZHMgPSBmYWxzZX0gPSBpbXBvcnREZXRhaWxzIHx8IHt9O1xuXG4gICAgICBjb25zdCBkdWNrRGJDb2x1bW5zID0gYXdhaXQgZ2V0RHVja0RCQ29sdW1uVHlwZXMoYywgdGFibGVOYW1lKTtcbiAgICAgIGNvbnN0IHRhYmxlRHVja0RCVHlwZXMgPSBnZXREdWNrREJDb2x1bW5UeXBlc01hcChkdWNrRGJDb2x1bW5zKTtcbiAgICAgIGNvbnN0IGFkanVzdGVkUXVlcnkgPSBjYXN0RHVja0RCVHlwZXNGb3JLZXBsZXIodGFibGVOYW1lLCBkdWNrRGJDb2x1bW5zKTtcbiAgICAgIGNvbnN0IGFycm93UmVzdWx0ID0gYXdhaXQgYy5xdWVyeShhZGp1c3RlZFF1ZXJ5KTtcblxuICAgICAgLy8gVE9ETyBpZiBmb3JtYXQgaXMgYW4gYXJyb3cgdGFibGUgdGhlbiBqdXN0IHVzZSB0aGUgb3JpZ2luYWwgb25lLCBpbnN0ZWFkIG9mIHRoZSBuZXcgdGFibGUgZnJvbSB0aGUgcXVlcnk/XG5cbiAgICAgIHJlc3RvcmVHZW9hcnJvd01ldGFkYXRhKGFycm93UmVzdWx0LCBnZW9hcnJvd01ldGFkYXRhKTtcblxuICAgICAgZmllbGRzID0gdXNlTmV3RmllbGRzXG4gICAgICAgID8gYXJyb3dTY2hlbWFUb0ZpZWxkcyhhcnJvd1Jlc3VsdCwgdGFibGVEdWNrREJUeXBlcylcbiAgICAgICAgOiBkYXRhLmZpZWxkcyA/PyBhcnJvd1NjaGVtYVRvRmllbGRzKGFycm93UmVzdWx0LCB0YWJsZUR1Y2tEQlR5cGVzKTtcbiAgICAgIGNvbHMgPSBbLi4uQXJyYXkoYXJyb3dSZXN1bHQubnVtQ29scykua2V5cygpXVxuICAgICAgICAubWFwKGkgPT4gYXJyb3dSZXN1bHQuZ2V0Q2hpbGRBdChpKSlcbiAgICAgICAgLmZpbHRlcihjb2wgPT4gY29sKSBhcyBhcnJvdy5WZWN0b3JbXTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignRHVja0RCIHRhYmxlOiBjcmVhdGVUYWJsZUFuZEdldEFycm93JywgZXJyb3IpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuXG4gICAgYXdhaXQgYy5jbG9zZSgpO1xuXG4gICAgcmV0dXJuIHtmaWVsZHMsIGNvbHN9O1xuICB9XG5cbiAgYXN5bmMgaW1wb3J0RGF0YSh7ZGF0YX06IHtkYXRhOiBQcm9jZXNzb3JSZXN1bHR9KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gVmVjdG9yVGlsZSBpcyBhIHNwZWNpYWwgY2FzZSwgaWdub3JlIGZvciBub3dcbiAgICBpZiAodGhpcy50eXBlID09PSBEYXRhc2V0VHlwZS5WRUNUT1JfVElMRSkge1xuICAgICAgc3VwZXIuaW1wb3J0RGF0YSh7ZGF0YTogey4uLmRhdGEsIHJvd3M6IFtdfX0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHtmaWVsZHMsIGNvbHN9ID0gYXdhaXQgdGhpcy5jcmVhdGVUYWJsZUFuZEdldEFycm93KGRhdGEpO1xuXG4gICAgc3VwZXIuaW1wb3J0RGF0YSh7ZGF0YToge2ZpZWxkcywgY29scywgcm93czogW119fSk7XG4gIH1cblxuICBhc3luYyB1cGRhdGUoZGF0YSkge1xuICAgIC8vIFZlY3RvclRpbGUgaXMgYSBzcGVjaWFsIGNhc2UsIGlnbm9yZSBmb3Igbm93XG4gICAgaWYgKHRoaXMudHlwZSA9PT0gRGF0YXNldFR5cGUuVkVDVE9SX1RJTEUpIHtcbiAgICAgIHN1cGVyLmltcG9ydERhdGEoe2RhdGF9KTtcbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIGNvbnN0IHtjb2xzfSA9IGF3YWl0IHRoaXMuY3JlYXRlVGFibGVBbmRHZXRBcnJvdyhkYXRhKTtcblxuICAgIHJldHVybiBzdXBlci51cGRhdGUoe2NvbHMsIHJvd3M6IFtdLCBmaWVsZHM6IFtdfSk7XG4gIH1cblxuICBzdGF0aWMgZ2V0RmlsZVByb2Nlc3NvciA9IGZ1bmN0aW9uIChkYXRhOiBhbnksIGlucHV0Rm9ybWF0Pzogc3RyaW5nKSB7XG4gICAgbGV0IHByb2Nlc3NvcjtcbiAgICBsZXQgZm9ybWF0O1xuICAgIGlmIChpbnB1dEZvcm1hdCA9PT0gREFUQVNFVF9GT1JNQVRTLmFycm93IHx8IGlzQXJyb3dEYXRhKGRhdGEpKSB7XG4gICAgICBmb3JtYXQgPSBEQVRBU0VUX0ZPUk1BVFMuYXJyb3c7XG4gICAgICBwcm9jZXNzb3IgPSBwcm9jZXNzQXJyb3dCYXRjaGVzO1xuICAgIH0gZWxzZSBpZiAoaW5wdXRGb3JtYXQgPT09IERBVEFTRVRfRk9STUFUUy5rZXBsZXJnbCB8fCBpc0tlcGxlckdsTWFwKGRhdGEpKSB7XG4gICAgICBmb3JtYXQgPSBEQVRBU0VUX0ZPUk1BVFMua2VwbGVyZ2w7XG4gICAgICBwcm9jZXNzb3IgPSBwcm9jZXNzS2VwbGVyZ2xKU09OZm9yRHVja0RiO1xuICAgIH0gZWxzZSBpZiAoaW5wdXRGb3JtYXQgPT09IERBVEFTRVRfRk9STUFUUy5yb3cgfHwgaXNSb3dPYmplY3QoZGF0YSkpIHtcbiAgICAgIC8vIGNzdiBmaWxlIGdvZXMgaGVyZVxuICAgICAgZm9ybWF0ID0gREFUQVNFVF9GT1JNQVRTLnJvdztcbiAgICAgIHByb2Nlc3NvciA9IHByb2Nlc3NDc3ZSb3dPYmplY3Q7IC8vIGRpcmVjdGx5IGltcG9ydCBqc29uIG9iamVjdCBpbnRvIGR1Y2tkYi13YXNtXG4gICAgfSBlbHNlIGlmIChpbnB1dEZvcm1hdCA9PT0gREFUQVNFVF9GT1JNQVRTLmdlb2pzb24gfHwgaXNHZW9Kc29uKGRhdGEpKSB7XG4gICAgICBmb3JtYXQgPSBEQVRBU0VUX0ZPUk1BVFMuZ2VvanNvbjtcbiAgICAgIHByb2Nlc3NvciA9IHByb2Nlc3NHZW9qc29uO1xuICAgIH1cbiAgICByZXR1cm4ge3Byb2Nlc3NvciwgZm9ybWF0fTtcbiAgfTtcblxuICBzdGF0aWMgZ2V0SW5wdXREYXRhVmFsaWRhdG9yID0gZnVuY3Rpb24gKCkge1xuICAgIC8vIEluIER1Y2tEQiBtb2RlIGRhdGEgaXMgdmFsaWRhdGVkIGxhdGVyIGR1cmluZyBpbXBvcnQuXG4gICAgcmV0dXJuIGQgPT4gZDtcbiAgfTtcbn1cblxuLyoqXG4gKiBUcnkgdG8gcmVzdG9yZSBnZW9hcnJvdyBtZXRhZGF0YSBsb3N0IGR1cmluZyBEdWNrRGIgaW5nZXN0aW9uLlxuICogTm90ZSB0aGF0IHRoaXMgZnVuY3Rpb24gY2FuIGdlbmVyYXRlIHdyb25nIGdlb21ldHJ5IHR5cGVzLlxuICogQHBhcmFtIGFycm93VGFibGUgQXJyb3cgdGFibGUgdG8gdXBkYXRlLlxuICogQHBhcmFtIGdlb2Fycm93TWV0YWRhdGEgQSBtYXAgd2l0aCBmaWVsZCBuYW1lcyB0aGF0IHVzdWFsbHkgdXNlZCB0byBzdG9yZSBnZW9hcnJvdyBnZW9tZXRyeS5cbiAqL1xuZXhwb3J0IGNvbnN0IHJlc3RvcmVHZW9hcnJvd01ldGFkYXRhID0gKFxuICBhcnJvd1RhYmxlOiBhcnJvdy5UYWJsZSxcbiAgZ2VvYXJyb3dNZXRhZGF0YTogUmVjb3JkPHN0cmluZywgc3RyaW5nPlxuKSA9PiB7XG4gIGFycm93VGFibGUuc2NoZW1hLmZpZWxkcy5mb3JFYWNoKGYgPT4ge1xuICAgIGlmIChhcnJvdy5EYXRhVHlwZS5pc0JpbmFyeShmLnR5cGUpICYmIGdlb2Fycm93TWV0YWRhdGFbZi5uYW1lXSkge1xuICAgICAgZi5tZXRhZGF0YS5zZXQoR0VPQVJST1dfTUVUQURBVEFfS0VZLCBnZW9hcnJvd01ldGFkYXRhW2YubmFtZV0pO1xuICAgIH0gZWxzZSBpZiAoaXNHZW9BcnJvd1BvaW50KGYudHlwZSkpIHtcbiAgICAgIGYubWV0YWRhdGEuc2V0KEdFT0FSUk9XX01FVEFEQVRBX0tFWSwgR0VPQVJST1dfRVhURU5TSU9OUy5QT0lOVCk7XG4gICAgfSBlbHNlIGlmIChpc0dlb0Fycm93TGluZVN0cmluZyhmLnR5cGUpKSB7XG4gICAgICBmLm1ldGFkYXRhLnNldChHRU9BUlJPV19NRVRBREFUQV9LRVksIEdFT0FSUk9XX0VYVEVOU0lPTlMuTElORVNUUklORyk7XG4gICAgfSBlbHNlIGlmIChpc0dlb0Fycm93UG9seWdvbihmLnR5cGUpKSB7XG4gICAgICBmLm1ldGFkYXRhLnNldChHRU9BUlJPV19NRVRBREFUQV9LRVksIEdFT0FSUk9XX0VYVEVOU0lPTlMuUE9MWUdPTik7XG4gICAgfSBlbHNlIGlmIChpc0dlb0Fycm93TXVsdGlQb2ludChmLnR5cGUpKSB7XG4gICAgICBmLm1ldGFkYXRhLnNldChHRU9BUlJPV19NRVRBREFUQV9LRVksIEdFT0FSUk9XX0VYVEVOU0lPTlMuTVVMVElQT0lOVCk7XG4gICAgfSBlbHNlIGlmIChpc0dlb0Fycm93TXVsdGlMaW5lU3RyaW5nKGYudHlwZSkpIHtcbiAgICAgIGYubWV0YWRhdGEuc2V0KEdFT0FSUk9XX01FVEFEQVRBX0tFWSwgR0VPQVJST1dfRVhURU5TSU9OUy5NVUxUSUxJTkVTVFJJTkcpO1xuICAgIH0gZWxzZSBpZiAoaXNHZW9BcnJvd011bHRpUG9seWdvbihmLnR5cGUpKSB7XG4gICAgICBmLm1ldGFkYXRhLnNldChHRU9BUlJPV19NRVRBREFUQV9LRVksIEdFT0FSUk9XX0VYVEVOU0lPTlMuTVVMVElQT0xZR09OKTtcbiAgICB9XG4gIH0pO1xufTtcbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUdBLElBQUFBLEtBQUEsR0FBQUMsdUJBQUEsQ0FBQUMsT0FBQTtBQUVBLElBQUFDLFVBQUEsR0FBQUQsT0FBQTtBQU1BLElBQUFFLFdBQUEsR0FBQUYsT0FBQTtBQVFBLElBQUFHLE1BQUEsR0FBQUgsT0FBQTtBQUVBLElBQUFJLE1BQUEsR0FBQUosT0FBQTtBQUVBLElBQUFLLGNBQUEsR0FBQUwsT0FBQTtBQU9BLElBQUFNLGlCQUFBLEdBQUFOLE9BQUE7QUFTQSxJQUFBTyxrQkFBQSxHQUFBUCxPQUFBO0FBUXFDLFNBQUFRLHlCQUFBQyxDQUFBLDZCQUFBQyxPQUFBLG1CQUFBQyxD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