kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
396 lines (393 loc) • 64.2 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SqlPanel = void 0;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral"));
var _react = _interopRequireWildcard(require("react"));
var _reactRedux = require("react-redux");
var _styledComponents = _interopRequireDefault(require("styled-components"));
var _reactResizablePanels = require("react-resizable-panels");
var _actions = require("@kepler.gl/actions");
var _commonUtils = require("@kepler.gl/common-utils");
var _components = require("@kepler.gl/components");
var _processors = require("@kepler.gl/processors");
var _styles = require("@kepler.gl/styles");
var _utils = require("@kepler.gl/utils");
var _monacoEditor = _interopRequireDefault(require("./monaco-editor"));
var _schemaPanel = require("./schema-panel");
var _previewDataPanel = require("./preview-data-panel");
var _duckdbTableUtils = require("../table/duckdb-table-utils");
var _templateObject, _templateObject2, _templateObject3, _templateObject4, _templateObject5, _templateObject6, _templateObject7, _templateObject8, _templateObject9, _templateObject10, _templateObject11, _templateObject12; // SPDX-License-Identifier: MIT
// Copyright contributors to the kepler.gl project
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 _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; }
var StyledSqlPanel = _styledComponents["default"].div(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2["default"])(["\n display: flex;\n height: 100%;\n background-color: ", ";\n border-left: 1px solid #333;\n"])), _styles.sidePanelBg);
var StyledSqlActions = _styledComponents["default"].div(_templateObject2 || (_templateObject2 = (0, _taggedTemplateLiteral2["default"])(["\n flex: 0 0 50px;\n display: flex;\n padding-top: 12px;\n align-items: center;\n flex-direction: column;\n justify-content: flex-start;\n border-bottom: 1px solid #333;\n"])));
var StyledSqlEditor = _styledComponents["default"].div(_templateObject3 || (_templateObject3 = (0, _taggedTemplateLiteral2["default"])(["\n display: flex;\n flex-direction: row;\n flex: 1;\n min-width: 0; // Prevents flex child from overflowing\n height: 100%;\n"])));
var StyledEditorPanel = _styledComponents["default"].div(_templateObject4 || (_templateObject4 = (0, _taggedTemplateLiteral2["default"])(["\n background-color: ", ";\n display: flex;\n height: 100%;\n flex-direction: row;\n gap: 5px;\n flex-grow: 1;\n"])), _styles.sidePanelBg);
var StyledDataPanel = _styledComponents["default"].div(_templateObject5 || (_templateObject5 = (0, _taggedTemplateLiteral2["default"])(["\n display: flex;\n flex-direction: column;\n height: 100%;\n background: white;\n"])));
var StyledEditor = _styledComponents["default"].div(_templateObject6 || (_templateObject6 = (0, _taggedTemplateLiteral2["default"])(["\n display: flex;\n padding: 12px 12px 12px 0;\n background-color: rgb(30, 30, 30);\n opacity: ", ";\n width: 100%;\n height: 100%;\n min-height: 0; // Prevents flex child from overflowing\n"])), function (props) {
return props.isRunning ? 0.5 : 1;
});
var StyledResultActions = _styledComponents["default"].div(_templateObject7 || (_templateObject7 = (0, _taggedTemplateLiteral2["default"])(["\n background-color: white;\n padding: 2px 12px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n font-size: 12px;\n"])));
var StyledResizeHandle = (0, _styledComponents["default"])(_reactResizablePanels.PanelResizeHandle)(_templateObject8 || (_templateObject8 = (0, _taggedTemplateLiteral2["default"])(["\n background-color: ", ";\n width: 4px;\n cursor: col-resize;\n\n &:hover {\n background-color: #555;\n }\n"])), _styles.panelBorderColor);
var StyledVerticalResizeHandle = (0, _styledComponents["default"])(_reactResizablePanels.PanelResizeHandle)(_templateObject9 || (_templateObject9 = (0, _taggedTemplateLiteral2["default"])(["\n background-color: ", ";\n height: 4px;\n cursor: row-resize;\n\n &:hover {\n background-color: #555;\n }\n"])), _styles.panelBorderColor);
var StyledLoadingContainer = _styledComponents["default"].div(_templateObject10 || (_templateObject10 = (0, _taggedTemplateLiteral2["default"])(["\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100%;\n"])));
var StyledErrorContainer = _styledComponents["default"].pre(_templateObject11 || (_templateObject11 = (0, _taggedTemplateLiteral2["default"])(["\n padding: 12px;\n color: red;\n font-size: 12px;\n background-color: ", ";\n height: 100%;\n overflow: auto;\n"])), _styles.sidePanelBg);
var StyledFileDropArea = (0, _styledComponents["default"])(_components.FileDrop)(_templateObject12 || (_templateObject12 = (0, _taggedTemplateLiteral2["default"])(["\n height: 100%;\n border-width: 1px;\n border: 1px ", "\n ", ";\n .file-drop-target {\n height: 100%;\n }\n"])), function (props) {
return props.dragOver ? 'solid' : 'dashed';
}, function (props) {
return props.dragOver ? props.theme.subtextColorLT : 'transparent';
});
var SCHEMA_PANEL_STYLE = {
overflow: 'auto'
};
var SqlPanel = exports.SqlPanel = function SqlPanel(_ref) {
var _ref$initialSql = _ref.initialSql,
initialSql = _ref$initialSql === void 0 ? '' : _ref$initialSql;
var _useState = (0, _react.useState)(function () {
var params = new URLSearchParams(window.location.search);
return params.get('sql') || initialSql;
}),
_useState2 = (0, _slicedToArray2["default"])(_useState, 2),
sql = _useState2[0],
setSql = _useState2[1];
var _useState3 = (0, _react.useState)(null),
_useState4 = (0, _slicedToArray2["default"])(_useState3, 2),
droppedFile = _useState4[0],
setDroppedFile = _useState4[1];
var _useState5 = (0, _react.useState)(false),
_useState6 = (0, _slicedToArray2["default"])(_useState5, 2),
dragState = _useState6[0],
setDragState = _useState6[1];
var _useState7 = (0, _react.useState)(null),
_useState8 = (0, _slicedToArray2["default"])(_useState7, 2),
result = _useState8[0],
setResult = _useState8[1];
var _useState9 = (0, _react.useState)(0),
_useState10 = (0, _slicedToArray2["default"])(_useState9, 2),
schemaUpdateTrigger = _useState10[0],
setSchemaUpdateTrigger = _useState10[1];
var _useState11 = (0, _react.useState)(null),
_useState12 = (0, _slicedToArray2["default"])(_useState11, 2),
error = _useState12[0],
setError = _useState12[1];
var _useState13 = (0, _react.useState)(0),
_useState14 = (0, _slicedToArray2["default"])(_useState13, 2),
counter = _useState14[0],
setCounter = _useState14[1];
var _useState15 = (0, _react.useState)([]),
_useState16 = (0, _slicedToArray2["default"])(_useState15, 2),
tableSchema = _useState16[0],
setTableSchema = _useState16[1];
var _useState17 = (0, _react.useState)(false),
_useState18 = (0, _slicedToArray2["default"])(_useState17, 2),
isRunning = _useState18[0],
setIsRunning = _useState18[1];
var _useState19 = (0, _react.useState)(function () {
return (0, _utils.isAppleDevice)();
}),
_useState20 = (0, _slicedToArray2["default"])(_useState19, 1),
isMac = _useState20[0];
var dispatch = (0, _reactRedux.useDispatch)();
var droppedFileAreaRef = (0, _react.useRef)(null);
(0, _react.useEffect)(function () {
var currentUrl = new URL(window.location.href);
if (sql) {
currentUrl.searchParams.set('sql', sql);
} else {
currentUrl.searchParams["delete"]('sql');
}
window.history.replaceState({}, '', currentUrl.toString());
}, [sql]);
var runQuery = (0, _react.useCallback)( /*#__PURE__*/(0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee() {
var adjustedQuery, db, connection, tempTableName, sqlStatements, arrowResult, tableDuckDBTypes, _iterator, _step, statement, isLastQuery, duckDbColumns, _adjustedQuery;
return _regenerator["default"].wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
setIsRunning(true);
_context.prev = 1;
adjustedQuery = sql ? (0, _duckdbTableUtils.removeSQLComments)(sql) : null;
if (adjustedQuery) {
_context.next = 6;
break;
}
setError(new Error('Query is empty'));
return _context.abrupt("return");
case 6:
db = (0, _utils.getApplicationConfig)().database;
if (db) {
_context.next = 10;
break;
}
setError(new Error('The database is not configured properly.'));
return _context.abrupt("return");
case 10:
_context.next = 12;
return db.connect();
case 12:
connection = _context.sent;
// TODO find a cheap way to get DuckDb types with a single query to a remote resource - temp table? cte?
tempTableName = 'temp_keplergl_table'; // remove comments
sqlStatements = (0, _duckdbTableUtils.splitSqlStatements)(adjustedQuery);
arrowResult = null;
tableDuckDBTypes = {};
_iterator = _createForOfIteratorHelper(sqlStatements);
_context.prev = 18;
_iterator.s();
case 20:
if ((_step = _iterator.n()).done) {
_context.next = 48;
break;
}
statement = _step.value;
isLastQuery = statement === sqlStatements[sqlStatements.length - 1];
_context.t0 = isLastQuery;
if (!_context.t0) {
_context.next = 28;
break;
}
_context.next = 27;
return (0, _duckdbTableUtils.checkIsSelectQuery)(connection, statement);
case 27:
_context.t0 = _context.sent;
case 28:
if (!_context.t0) {
_context.next = 44;
break;
}
_context.next = 31;
return connection.query("CREATE OR REPLACE TABLE '".concat(tempTableName, "' AS ").concat(statement));
case 31:
_context.next = 33;
return (0, _duckdbTableUtils.getDuckDBColumnTypes)(connection, tempTableName);
case 33:
duckDbColumns = _context.sent;
tableDuckDBTypes = (0, _duckdbTableUtils.getDuckDBColumnTypesMap)(duckDbColumns);
// 3) cast GEOMETRY columns to WKB and BigInt to double.
_adjustedQuery = (0, _duckdbTableUtils.castDuckDBTypesForKepler)(tempTableName, duckDbColumns);
_context.next = 38;
return connection.query(_adjustedQuery);
case 38:
arrowResult = _context.sent;
// 4) set geoarrow extension for the arrow table as DuckDB doesn't support the geoarrow extension.
(0, _duckdbTableUtils.setGeoArrowWKBExtension)(arrowResult, duckDbColumns);
// 5) remove temp table
_context.next = 42;
return connection.query("DROP TABLE ".concat(tempTableName, ";"));
case 42:
_context.next = 46;
break;
case 44:
_context.next = 46;
return connection.query(statement);
case 46:
_context.next = 20;
break;
case 48:
_context.next = 53;
break;
case 50:
_context.prev = 50;
_context.t1 = _context["catch"](18);
_iterator.e(_context.t1);
case 53:
_context.prev = 53;
_iterator.f();
return _context.finish(53);
case 56:
// Show preview only for the result of the last query
if (arrowResult) {
setResult({
table: arrowResult,
tableDuckDBTypes: tableDuckDBTypes
});
setError(null);
}
_context.next = 59;
return connection.close();
case 59:
_context.next = 64;
break;
case 61:
_context.prev = 61;
_context.t2 = _context["catch"](1);
setError(_context.t2);
case 64:
_context.prev = 64;
setIsRunning(false);
return _context.finish(64);
case 67:
// Indicate that there may be a possible change in DuckDB.
setSchemaUpdateTrigger(Date.now());
case 68:
case "end":
return _context.stop();
}
}, _callee, null, [[1, 61, 64, 67], [18, 50, 53, 56]]);
})), [sql]);
var onChange = (0, _react.useCallback)(function (value) {
setSql(value);
}, [setSql]);
var onAddResultToMap = (0, _react.useCallback)(function () {
if (!result) return;
var keplerFields = (0, _processors.arrowSchemaToFields)(result.table, result.tableDuckDBTypes);
var datasetToAdd = {
data: {
fields: keplerFields,
// TODO type AddDataToMapPayload -> rows -> + arrow.Table
rows: result.table
},
info: {
id: (0, _commonUtils.generateHashId)(),
label: "query_result".concat(counter > 0 ? "_".concat(counter) : ''),
format: 'arrow'
}
};
dispatch((0, _actions.addDataToMap)({
datasets: [datasetToAdd]
}));
setCounter(counter + 1);
}, [result, counter, dispatch]);
var isValidFileType = (0, _react.useCallback)(function (filename) {
var fileExt = _duckdbTableUtils.SUPPORTED_DUCKDB_DROP_EXTENSIONS.find(function (ext) {
return filename.endsWith(ext);
});
return Boolean(fileExt);
}, []);
var createTableFromDroppedFile = (0, _react.useCallback)( /*#__PURE__*/function () {
var _ref3 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(droppedFile) {
var _error;
return _regenerator["default"].wrap(function _callee2$(_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
if (!droppedFile) {
_context2.next = 5;
break;
}
_context2.next = 3;
return (0, _duckdbTableUtils.tableFromFile)(droppedFile);
case 3:
_error = _context2.sent;
if (_error) {
setError(_error);
} else {
setError(null);
}
case 5:
setDroppedFile(null);
setDragState(false);
case 7:
case "end":
return _context2.stop();
}
}, _callee2);
}));
return function (_x) {
return _ref3.apply(this, arguments);
};
}(), []);
(0, _react.useEffect)(function () {
createTableFromDroppedFile(droppedFile);
}, [droppedFile, createTableFromDroppedFile]);
var handleFileInput = (0, _react.useCallback)(function (fileList, event) {
if (event) {
event.preventDefault();
event.stopPropagation();
}
var files = (0, _toConsumableArray2["default"])(fileList).filter(Boolean);
var disableExtensionFilter = false;
var filesToLoad = [];
var errorFiles = [];
var _iterator2 = _createForOfIteratorHelper(files),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var file = _step2.value;
if (disableExtensionFilter || isValidFileType(file.name)) {
filesToLoad.push(file);
} else {
errorFiles.push(file.name);
}
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
if (filesToLoad.length > 0) {
setDroppedFile(filesToLoad[0]);
} else if (errorFiles.length > 0) {
setError(new Error("Unsupported file formats: ".concat(errorFiles.join(', '))));
}
}, [isValidFileType]);
return /*#__PURE__*/_react["default"].createElement(StyledSqlPanel, null, /*#__PURE__*/_react["default"].createElement(_reactResizablePanels.PanelGroup, {
direction: "horizontal"
}, /*#__PURE__*/_react["default"].createElement(_reactResizablePanels.Panel, {
defaultSize: 20,
minSize: 15,
style: SCHEMA_PANEL_STYLE,
className: "schema-panel"
}, /*#__PURE__*/_react["default"].createElement(StyledFileDropArea, {
dragOver: dragState,
onDragOver: function onDragOver() {
return setDragState(true);
},
onDragLeave: function onDragLeave() {
return setDragState(false);
},
frame: droppedFileAreaRef.current || document,
onDrop: handleFileInput,
className: "file-uploader__file-drop"
}, /*#__PURE__*/_react["default"].createElement(_schemaPanel.SchemaPanel, {
setTableSchema: setTableSchema,
droppedFile: droppedFile,
schemaUpdateTrigger: schemaUpdateTrigger
}))), /*#__PURE__*/_react["default"].createElement(StyledResizeHandle, null), /*#__PURE__*/_react["default"].createElement(_reactResizablePanels.Panel, {
minSize: 40
}, /*#__PURE__*/_react["default"].createElement(StyledSqlEditor, null, /*#__PURE__*/_react["default"].createElement(_reactResizablePanels.PanelGroup, {
direction: "vertical"
}, /*#__PURE__*/_react["default"].createElement(_reactResizablePanels.Panel, {
defaultSize: 30,
className: "editor-panel"
}, /*#__PURE__*/_react["default"].createElement(StyledEditorPanel, null, /*#__PURE__*/_react["default"].createElement(StyledSqlActions, null, /*#__PURE__*/_react["default"].createElement(_components.IconButton, {
"data-tip": true,
"data-for": "run-query-tooltip",
onClick: runQuery,
disabled: isRunning || !sql
}, /*#__PURE__*/_react["default"].createElement(_components.Icons.Play, {
height: "18px"
}), /*#__PURE__*/_react["default"].createElement(_components.Tooltip, {
id: "run-query-tooltip",
place: "top",
effect: "solid"
}, "Run Query (", isMac ? '⌘Enter' : 'Ctrl+Enter', " or Shift+Enter)"))), /*#__PURE__*/_react["default"].createElement(StyledEditor, {
isRunning: isRunning
}, /*#__PURE__*/_react["default"].createElement(_monacoEditor["default"], {
isReadOnly: isRunning,
onRunQuery: runQuery,
onChange: onChange,
tableSchema: tableSchema,
code: sql
})))), /*#__PURE__*/_react["default"].createElement(StyledVerticalResizeHandle, null), /*#__PURE__*/_react["default"].createElement(_reactResizablePanels.Panel, {
className: "preview-panel"
}, isRunning ? /*#__PURE__*/_react["default"].createElement(StyledLoadingContainer, null, /*#__PURE__*/_react["default"].createElement(_components.LoadingSpinner, null)) : error ? /*#__PURE__*/_react["default"].createElement(StyledErrorContainer, null, /*#__PURE__*/_react["default"].createElement("div", null, error.message)) : result ? /*#__PURE__*/_react["default"].createElement(StyledDataPanel, null, /*#__PURE__*/_react["default"].createElement(StyledResultActions, null, /*#__PURE__*/_react["default"].createElement(_components.Button, {
secondary: true,
onClick: onAddResultToMap
}, "Add to Map"), /*#__PURE__*/_react["default"].createElement("div", null, result.table.numRows, " rows")), /*#__PURE__*/_react["default"].createElement(_previewDataPanel.PreviewDataPanel, {
result: result,
dataTableStyle: {},
onAddResultToMap: onAddResultToMap
})) : null))))));
};
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVXaWxkY2FyZCIsInJlcXVpcmUiLCJfcmVhY3RSZWR1eCIsIl9zdHlsZWRDb21wb25lbnRzIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsIl9yZWFjdFJlc2l6YWJsZVBhbmVscyIsIl9hY3Rpb25zIiwiX2NvbW1vblV0aWxzIiwiX2NvbXBvbmVudHMiLCJfcHJvY2Vzc29ycyIsIl9zdHlsZXMiLCJfdXRpbHMiLCJfbW9uYWNvRWRpdG9yIiwiX3NjaGVtYVBhbmVsIiwiX3ByZXZpZXdEYXRhUGFuZWwiLCJfZHVja2RiVGFibGVVdGlscyIsIl90ZW1wbGF0ZU9iamVjdCIsIl90ZW1wbGF0ZU9iamVjdDIiLCJfdGVtcGxhdGVPYmplY3QzIiwiX3RlbXBsYXRlT2JqZWN0NCIsIl90ZW1wbGF0ZU9iamVjdDUiLCJfdGVtcGxhdGVPYmplY3Q2IiwiX3RlbXBsYXRlT2JqZWN0NyIsIl90ZW1wbGF0ZU9iamVjdDgiLCJfdGVtcGxhdGVPYmplY3Q5IiwiX3RlbXBsYXRlT2JqZWN0MTAiLCJfdGVtcGxhdGVPYmplY3QxMSIsIl90ZW1wbGF0ZU9iamVjdDEyIiwiX2dldFJlcXVpcmVXaWxkY2FyZENhY2hlIiwiZSIsIldlYWtNYXAiLCJyIiwidCIsIl9fZXNNb2R1bGUiLCJfdHlwZW9mIiwiaGFzIiwiZ2V0IiwibiIsIl9fcHJvdG9fXyIsImEiLCJPYmplY3QiLCJkZWZpbmVQcm9wZXJ0eSIsImdldE93blByb3BlcnR5RGVzY3JpcHRvciIsInUiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJpIiwic2V0IiwiX2NyZWF0ZUZvck9mSXRlcmF0b3JIZWxwZXIiLCJTeW1ib2wiLCJpdGVyYXRvciIsIkFycmF5IiwiaXNBcnJheSIsIl91bnN1cHBvcnRlZEl0ZXJhYmxlVG9BcnJheSIsImxlbmd0aCIsIl9uIiwiRiIsInMiLCJkb25lIiwidmFsdWUiLCJmIiwiVHlwZUVycm9yIiwibyIsIm5leHQiLCJfYXJyYXlMaWtlVG9BcnJheSIsInRvU3RyaW5nIiwic2xpY2UiLCJjb25zdHJ1Y3RvciIsIm5hbWUiLCJmcm9tIiwidGVzdCIsIlN0eWxlZFNxbFBhbmVsIiwic3R5bGVkIiwiZGl2IiwiX3RhZ2dlZFRlbXBsYXRlTGl0ZXJhbDIiLCJzaWRlUGFuZWxCZyIsIlN0eWxlZFNxbEFjdGlvbnMiLCJTdHlsZWRTcWxFZGl0b3IiLCJTdHlsZWRFZGl0b3JQYW5lbCIsIlN0eWxlZERhdGFQYW5lbCIsIlN0eWxlZEVkaXRvciIsInByb3BzIiwiaXNSdW5uaW5nIiwiU3R5bGVkUmVzdWx0QWN0aW9ucyIsIlN0eWxlZFJlc2l6ZUhhbmRsZSIsIlBhbmVsUmVzaXplSGFuZGxlIiwicGFuZWxCb3JkZXJDb2xvciIsIlN0eWxlZFZlcnRpY2FsUmVzaXplSGFuZGxlIiwiU3R5bGVkTG9hZGluZ0NvbnRhaW5lciIsIlN0eWxlZEVycm9yQ29udGFpbmVyIiwicHJlIiwiU3R5bGVkRmlsZURyb3BBcmVhIiwiRmlsZURyb3AiLCJkcmFnT3ZlciIsInRoZW1lIiwic3VidGV4dENvbG9yTFQiLCJTQ0hFTUFfUEFORUxfU1RZTEUiLCJvdmVyZmxvdyIsIlNxbFBhbmVsIiwiZXhwb3J0cyIsIl9yZWYiLCJfcmVmJGluaXRpYWxTcWwiLCJpbml0aWFsU3FsIiwiX3VzZVN0YXRlIiwidXNlU3RhdGUiLCJwYXJhbXMiLCJVUkxTZWFyY2hQYXJhbXMiLCJ3aW5kb3ciLCJsb2NhdGlvbiIsInNlYXJjaCIsIl91c2VTdGF0ZTIiLCJfc2xpY2VkVG9BcnJheTIiLCJzcWwiLCJzZXRTcWwiLCJfdXNlU3RhdGUzIiwiX3VzZVN0YXRlNCIsImRyb3BwZWRGaWxlIiwic2V0RHJvcHBlZEZpbGUiLCJfdXNlU3RhdGU1IiwiX3VzZVN0YXRlNiIsImRyYWdTdGF0ZSIsInNldERyYWdTdGF0ZSIsIl91c2VTdGF0ZTciLCJfdXNlU3RhdGU4IiwicmVzdWx0Iiwic2V0UmVzdWx0IiwiX3VzZVN0YXRlOSIsIl91c2VTdGF0ZTEwIiwic2NoZW1hVXBkYXRlVHJpZ2dlciIsInNldFNjaGVtYVVwZGF0ZVRyaWdnZXIiLCJfdXNlU3RhdGUxMSIsIl91c2VTdGF0ZTEyIiwiZXJyb3IiLCJzZXRFcnJvciIsIl91c2VTdGF0ZTEzIiwiX3VzZVN0YXRlMTQiLCJjb3VudGVyIiwic2V0Q291bnRlciIsIl91c2VTdGF0ZTE1IiwiX3VzZVN0YXRlMTYiLCJ0YWJsZVNjaGVtYSIsInNldFRhYmxlU2NoZW1hIiwiX3VzZVN0YXRlMTciLCJfdXNlU3RhdGUxOCIsInNldElzUnVubmluZyIsIl91c2VTdGF0ZTE5IiwiaXNBcHBsZURldmljZSIsIl91c2VTdGF0ZTIwIiwiaXNNYWMiLCJkaXNwYXRjaCIsInVzZURpc3BhdGNoIiwiZHJvcHBlZEZpbGVBcmVhUmVmIiwidXNlUmVmIiwidXNlRWZmZWN0IiwiY3VycmVudFVybCIsIlVSTCIsImhyZWYiLCJzZWFyY2hQYXJhbXMiLCJoaXN0b3J5IiwicmVwbGFjZVN0YXRlIiwicnVuUXVlcnkiLCJ1c2VDYWxsYmFjayIsIl9hc3luY1RvR2VuZXJhdG9yMiIsIl9yZWdlbmVyYXRvciIsIm1hcmsiLCJfY2FsbGVlIiwiYWRqdXN0ZWRRdWVyeSIsImRiIiwiY29ubmVjdGlvbiIsInRlbXBUYWJsZU5hbWUiLCJzcWxTdGF0ZW1lbnRzIiwiYXJyb3dSZXN1bHQiLCJ0YWJsZUR1Y2tEQlR5cGVzIiwiX2l0ZXJhdG9yIiwiX3N0ZXAiLCJzdGF0ZW1lbnQiLCJpc0xhc3RRdWVyeSIsImR1Y2tEYkNvbHVtbnMiLCJfYWRqdXN0ZWRRdWVyeSIsIndyYXAiLCJfY2FsbGVlJCIsIl9jb250ZXh0IiwicHJldiIsInJlbW92ZVNRTENvbW1lbnRzIiwiRXJyb3IiLCJhYnJ1cHQiLCJnZXRBcHBsaWNhdGlvbkNvbmZpZyIsImRhdGFiYXNlIiwiY29ubmVjdCIsInNlbnQiLCJzcGxpdFNxbFN0YXRlbWVudHMiLCJ0MCIsImNoZWNrSXNTZWxlY3RRdWVyeSIsInF1ZXJ5IiwiY29uY2F0IiwiZ2V0RHVja0RCQ29sdW1uVHlwZXMiLCJnZXREdWNrREJDb2x1bW5UeXBlc01hcCIsImNhc3REdWNrREJUeXBlc0ZvcktlcGxlciIsInNldEdlb0Fycm93V0tCRXh0ZW5zaW9uIiwidDEiLCJmaW5pc2giLCJ0YWJsZSIsImNsb3NlIiwidDIiLCJEYXRlIiwibm93Iiwic3RvcCIsIm9uQ2hhbmdlIiwib25BZGRSZXN1bHRUb01hcCIsImtlcGxlckZpZWxkcyIsImFycm93U2NoZW1hVG9GaWVsZHMiLCJkYXRhc2V0VG9BZGQiLCJkYXRhIiwiZmllbGRzIiwicm93cyIsImluZm8iLCJpZCIsImdlbmVyYXRlSGFzaElkIiwibGFiZWwiLCJmb3JtYXQiLCJhZGREYXRhVG9NYXAiLCJkYXRhc2V0cyIsImlzVmFsaWRGaWxlVHlwZSIsImZpbGVuYW1lIiwiZmlsZUV4dCIsIlNVUFBPUlRFRF9EVUNLREJfRFJPUF9FWFRFTlNJT05TIiwiZmluZCIsImV4dCIsImVuZHNXaXRoIiwiQm9vbGVhbiIsImNyZWF0ZVRhYmxlRnJvbURyb3BwZWRGaWxlIiwiX3JlZjMiLCJfY2FsbGVlMiIsIl9lcnJvciIsIl9jYWxsZWUyJCIsIl9jb250ZXh0MiIsInRhYmxlRnJvbUZpbGUiLCJfeCIsImFwcGx5IiwiYXJndW1lbnRzIiwiaGFuZGxlRmlsZUlucHV0IiwiZmlsZUxpc3QiLCJldmVudCIsInByZXZlbnREZWZhdWx0Iiwic3RvcFByb3BhZ2F0aW9uIiwiZmlsZXMiLCJfdG9Db25zdW1hYmxlQXJyYXkyIiwiZmlsdGVyIiwiZGlzYWJsZUV4dGVuc2lvbkZpbHRlciIsImZpbGVzVG9Mb2FkIiwiZXJyb3JGaWxlcyIsIl9pdGVyYXRvcjIiLCJfc3RlcDIiLCJmaWxlIiwicHVzaCIsImVyciIsImpvaW4iLCJjcmVhdGVFbGVtZW50IiwiUGFuZWxHcm91cCIsImRpcmVjdGlvbiIsIlBhbmVsIiwiZGVmYXVsdFNpemUiLCJtaW5TaXplIiwic3R5bGUiLCJjbGFzc05hbWUiLCJvbkRyYWdPdmVyIiwib25EcmFnTGVhdmUiLCJmcmFtZSIsImN1cnJlbnQiLCJkb2N1bWVudCIsIm9uRHJvcCIsIlNjaGVtYVBhbmVsIiwiSWNvbkJ1dHRvbiIsIm9uQ2xpY2siLCJkaXNhYmxlZCIsIkljb25zIiwiUGxheSIsImhlaWdodCIsIlRvb2x0aXAiLCJwbGFjZSIsImVmZmVjdCIsImlzUmVhZE9ubHkiLCJvblJ1blF1ZXJ5IiwiY29kZSIsIkxvYWRpbmdTcGlubmVyIiwibWVzc2FnZSIsIkJ1dHRvbiIsInNlY29uZGFyeSIsIm51bVJvd3MiLCJQcmV2aWV3RGF0YVBhbmVsIiwiZGF0YVRhYmxlU3R5bGUiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvY29tcG9uZW50cy9zcWwtcGFuZWwudHN4Il0sInNvdXJjZXNDb250ZW50IjpbIi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBNSVRcbi8vIENvcHlyaWdodCBjb250cmlidXRvcnMgdG8gdGhlIGtlcGxlci5nbCBwcm9qZWN0XG5cbmltcG9ydCAqIGFzIGFycm93IGZyb20gJ2FwYWNoZS1hcnJvdyc7XG5pbXBvcnQgUmVhY3QsIHt1c2VDYWxsYmFjaywgdXNlU3RhdGUsIHVzZUVmZmVjdCwgdXNlUmVmfSBmcm9tICdyZWFjdCc7XG5pbXBvcnQge3VzZURpc3BhdGNofSBmcm9tICdyZWFjdC1yZWR1eCc7XG5pbXBvcnQgc3R5bGVkIGZyb20gJ3N0eWxlZC1jb21wb25lbnRzJztcbmltcG9ydCB7UGFuZWwsIFBhbmVsR3JvdXAsIFBhbmVsUmVzaXplSGFuZGxlfSBmcm9tICdyZWFjdC1yZXNpemFibGUtcGFuZWxzJztcblxuaW1wb3J0IHthZGREYXRhVG9NYXB9IGZyb20gJ0BrZXBsZXIuZ2wvYWN0aW9ucyc7XG5pbXBvcnQge2dlbmVyYXRlSGFzaElkfSBmcm9tICdAa2VwbGVyLmdsL2NvbW1vbi11dGlscyc7XG5pbXBvcnQge0J1dHRvbiwgRmlsZURyb3AsIEljb25CdXR0b24sIEljb25zLCBMb2FkaW5nU3Bpbm5lciwgVG9vbHRpcH0gZnJvbSAnQGtlcGxlci5nbC9jb21wb25lbnRzJztcbmltcG9ydCB7YXJyb3dTY2hlbWFUb0ZpZWxkc30gZnJvbSAnQGtlcGxlci5nbC9wcm9jZXNzb3JzJztcbmltcG9ydCB7c2lkZVBhbmVsQmcsIHBhbmVsQm9yZGVyQ29sb3J9IGZyb20gJ0BrZXBsZXIuZ2wvc3R5bGVzJztcbmltcG9ydCB7aXNBcHBsZURldmljZSwgZ2V0QXBwbGljYXRpb25Db25maWd9IGZyb20gJ0BrZXBsZXIuZ2wvdXRpbHMnO1xuXG5pbXBvcnQgTW9uYWNvRWRpdG9yIGZyb20gJy4vbW9uYWNvLWVkaXRvcic7XG5pbXBvcnQge1NjaGVtYVBhbmVsLCBTY2hlbWFTdWdnZXN0aW9ufSBmcm9tICcuL3NjaGVtYS1wYW5lbCc7XG5pbXBvcnQge1ByZXZpZXdEYXRhUGFuZWwsIFF1ZXJ5UmVzdWx0fSBmcm9tICcuL3ByZXZpZXctZGF0YS1wYW5lbCc7XG5cbmltcG9ydCB7XG4gIGNhc3REdWNrREJUeXBlc0ZvcktlcGxlcixcbiAgZ2V0RHVja0RCQ29sdW1uVHlwZXMsXG4gIGdldER1Y2tEQkNvbHVtblR5cGVzTWFwLFxuICBzZXRHZW9BcnJvd1dLQkV4dGVuc2lvbixcbiAgc3BsaXRTcWxTdGF0ZW1lbnRzLFxuICBjaGVja0lzU2VsZWN0UXVlcnksXG4gIHJlbW92ZVNRTENvbW1lbnRzLFxuICB0YWJsZUZyb21GaWxlLFxuICBTVVBQT1JURURfRFVDS0RCX0RST1BfRVhURU5TSU9OU1xufSBmcm9tICcuLi90YWJsZS9kdWNrZGItdGFibGUtdXRpbHMnO1xuXG5jb25zdCBTdHlsZWRTcWxQYW5lbCA9IHN0eWxlZC5kaXZgXG4gIGRpc3BsYXk6IGZsZXg7XG4gIGhlaWdodDogMTAwJTtcbiAgYmFja2dyb3VuZC1jb2xvcjogJHtzaWRlUGFuZWxCZ307XG4gIGJvcmRlci1sZWZ0OiAxcHggc29saWQgIzMzMztcbmA7XG5cbmNvbnN0IFN0eWxlZFNxbEFjdGlvbnMgPSBzdHlsZWQuZGl2YFxuICBmbGV4OiAwIDAgNTBweDtcbiAgZGlzcGxheTogZmxleDtcbiAgcGFkZGluZy10b3A6IDEycHg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gIGp1c3RpZnktY29udGVudDogZmxleC1zdGFydDtcbiAgYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICMzMzM7XG5gO1xuXG5jb25zdCBTdHlsZWRTcWxFZGl0b3IgPSBzdHlsZWQuZGl2YFxuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogcm93O1xuICBmbGV4OiAxO1xuICBtaW4td2lkdGg6IDA7IC8vIFByZXZlbnRzIGZsZXggY2hpbGQgZnJvbSBvdmVyZmxvd2luZ1xuICBoZWlnaHQ6IDEwMCU7XG5gO1xuXG5jb25zdCBTdHlsZWRFZGl0b3JQYW5lbCA9IHN0eWxlZC5kaXZgXG4gIGJhY2tncm91bmQtY29sb3I6ICR7c2lkZVBhbmVsQmd9O1xuICBkaXNwbGF5OiBmbGV4O1xuICBoZWlnaHQ6IDEwMCU7XG4gIGZsZXgtZGlyZWN0aW9uOiByb3c7XG4gIGdhcDogNXB4O1xuICBmbGV4LWdyb3c6IDE7XG5gO1xuXG5jb25zdCBTdHlsZWREYXRhUGFuZWwgPSBzdHlsZWQuZGl2YFxuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xuICBoZWlnaHQ6IDEwMCU7XG4gIGJhY2tncm91bmQ6IHdoaXRlO1xuYDtcblxuY29uc3QgU3R5bGVkRWRpdG9yID0gc3R5bGVkLmRpdjx7aXNSdW5uaW5nOiBib29sZWFufT5gXG4gIGRpc3BsYXk6IGZsZXg7XG4gIHBhZGRpbmc6IDEycHggMTJweCAxMnB4IDA7XG4gIGJhY2tncm91bmQtY29sb3I6IHJnYigzMCwgMzAsIDMwKTtcbiAgb3BhY2l0eTogJHtwcm9wcyA9PiAocHJvcHMuaXNSdW5uaW5nID8gMC41IDogMSl9O1xuICB3aWR0aDogMTAwJTtcbiAgaGVpZ2h0OiAxMDAlO1xuICBtaW4taGVpZ2h0OiAwOyAvLyBQcmV2ZW50cyBmbGV4IGNoaWxkIGZyb20gb3ZlcmZsb3dpbmdcbmA7XG5cbmNvbnN0IFN0eWxlZFJlc3VsdEFjdGlvbnMgPSBzdHlsZWQuZGl2YFxuICBiYWNrZ3JvdW5kLWNvbG9yOiB3aGl0ZTtcbiAgcGFkZGluZzogMnB4IDEycHg7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgZm9udC1zaXplOiAxMnB4O1xuYDtcblxuY29uc3QgU3R5bGVkUmVzaXplSGFuZGxlID0gc3R5bGVkKFBhbmVsUmVzaXplSGFuZGxlKWBcbiAgYmFja2dyb3VuZC1jb2xvcjogJHtwYW5lbEJvcmRlckNvbG9yfTtcbiAgd2lkdGg6IDRweDtcbiAgY3Vyc29yOiBjb2wtcmVzaXplO1xuXG4gICY6aG92ZXIge1xuICAgIGJhY2tncm91bmQtY29sb3I6ICM1NTU7XG4gIH1cbmA7XG5cbmNvbnN0IFN0eWxlZFZlcnRpY2FsUmVzaXplSGFuZGxlID0gc3R5bGVkKFBhbmVsUmVzaXplSGFuZGxlKWBcbiAgYmFja2dyb3VuZC1jb2xvcjogJHtwYW5lbEJvcmRlckNvbG9yfTtcbiAgaGVpZ2h0OiA0cHg7XG4gIGN1cnNvcjogcm93LXJlc2l6ZTtcblxuICAmOmhvdmVyIHtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjNTU1O1xuICB9XG5gO1xuXG5jb25zdCBTdHlsZWRMb2FkaW5nQ29udGFpbmVyID0gc3R5bGVkLmRpdmBcbiAgZGlzcGxheTogZmxleDtcbiAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGhlaWdodDogMTAwJTtcbmA7XG5cbmNvbnN0IFN0eWxlZEVycm9yQ29udGFpbmVyID0gc3R5bGVkLnByZWBcbiAgcGFkZGluZzogMTJweDtcbiAgY29sb3I6IHJlZDtcbiAgZm9udC1zaXplOiAxMnB4O1xuICBiYWNrZ3JvdW5kLWNvbG9yOiAke3NpZGVQYW5lbEJnfTtcbiAgaGVpZ2h0OiAxMDAlO1xuICBvdmVyZmxvdzogYXV0bztcbmA7XG5cbmludGVyZmFjZSBTdHlsZWREcmFnUGFuZWxQcm9wcyB7XG4gIGRyYWdPdmVyPzogYm9vbGVhbjtcbn1cblxuY29uc3QgU3R5bGVkRmlsZURyb3BBcmVhID0gc3R5bGVkKEZpbGVEcm9wKTxTdHlsZWREcmFnUGFuZWxQcm9wcz5gXG4gIGhlaWdodDogMTAwJTtcbiAgYm9yZGVyLXdpZHRoOiAxcHg7XG4gIGJvcmRlcjogMXB4ICR7cHJvcHMgPT4gKHByb3BzLmRyYWdPdmVyID8gJ3NvbGlkJyA6ICdkYXNoZWQnKX1cbiAgICAke3Byb3BzID0+IChwcm9wcy5kcmFnT3ZlciA/IHByb3BzLnRoZW1lLnN1YnRleHRDb2xvckxUIDogJ3RyYW5zcGFyZW50Jyl9O1xuICAuZmlsZS1kcm9wLXRhcmdldCB7XG4gICAgaGVpZ2h0OiAxMDAlO1xuICB9XG5gO1xuXG50eXBlIFNxbFBhbmVsUHJvcHMgPSB7XG4gIGluaXRpYWxTcWw/OiBzdHJpbmc7XG59O1xuXG5jb25zdCBTQ0hFTUFfUEFORUxfU1RZTEUgPSB7b3ZlcmZsb3c6ICdhdXRvJ307XG5cbmV4cG9ydCBjb25zdCBTcWxQYW5lbDogUmVhY3QuRkM8U3FsUGFuZWxQcm9wcz4gPSAoe2luaXRpYWxTcWwgPSAnJ30pID0+IHtcbiAgY29uc3QgW3NxbCwgc2V0U3FsXSA9IHVzZVN0YXRlKCgpID0+IHtcbiAgICBjb25zdCBwYXJhbXMgPSBuZXcgVVJMU2VhcmNoUGFyYW1zKHdpbmRvdy5sb2NhdGlvbi5zZWFyY2gpO1xuICAgIHJldHVybiBwYXJhbXMuZ2V0KCdzcWwnKSB8fCBpbml0aWFsU3FsO1xuICB9KTtcbiAgY29uc3QgW2Ryb3BwZWRGaWxlLCBzZXREcm9wcGVkRmlsZV0gPSB1c2VTdGF0ZTxGaWxlIHwgbnVsbD4obnVsbCk7XG4gIGNvbnN0IFtkcmFnU3RhdGUsIHNldERyYWdTdGF0ZV0gPSB1c2VTdGF0ZShmYWxzZSk7XG4gIGNvbnN0IFtyZXN1bHQsIHNldFJlc3VsdF0gPSB1c2VTdGF0ZTxudWxsIHwgUXVlcnlSZXN1bHQ+KG51bGwpO1xuICBjb25zdCBbc2NoZW1hVXBkYXRlVHJpZ2dlciwgc2V0U2NoZW1hVXBkYXRlVHJpZ2dlcl0gPSB1c2VTdGF0ZTxudW1iZXI+KDApO1xuICBjb25zdCBbZXJyb3IsIHNldEVycm9yXSA9IHVzZVN0YXRlPEVycm9yIHwgbnVsbD4obnVsbCk7XG4gIGNvbnN0IFtjb3VudGVyLCBzZXRDb3VudGVyXSA9IHVzZVN0YXRlKDApO1xuICBjb25zdCBbdGFibGVTY2hlbWEsIHNldFRhYmxlU2NoZW1hXSA9IHVzZVN0YXRlPFNjaGVtYVN1Z2dlc3Rpb25bXT4oW10pO1xuICBjb25zdCBbaXNSdW5uaW5nLCBzZXRJc1J1bm5pbmddID0gdXNlU3RhdGUoZmFsc2UpO1xuICBjb25zdCBbaXNNYWNdID0gdXNlU3RhdGUoKCkgPT4gaXNBcHBsZURldmljZSgpKTtcbiAgY29uc3QgZGlzcGF0Y2ggPSB1c2VEaXNwYXRjaCgpO1xuXG4gIGNvbnN0IGRyb3BwZWRGaWxlQXJlYVJlZiA9IHVzZVJlZihudWxsKTtcblxuICB1c2VFZmZlY3QoKCkgPT4ge1xuICAgIGNvbnN0IGN1cnJlbnRVcmwgPSBuZXcgVVJMKHdpbmRvdy5sb2NhdGlvbi5ocmVmKTtcbiAgICBpZiAoc3FsKSB7XG4gICAgICBjdXJyZW50VXJsLnNlYXJjaFBhcmFtcy5zZXQoJ3NxbCcsIHNxbCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGN1cnJlbnRVcmwuc2VhcmNoUGFyYW1zLmRlbGV0ZSgnc3FsJyk7XG4gICAgfVxuICAgIHdpbmRvdy5oaXN0b3J5LnJlcGxhY2VTdGF0ZSh7fSwgJycsIGN1cnJlbnRVcmwudG9TdHJpbmcoKSk7XG4gIH0sIFtzcWxdKTtcblxuICBjb25zdCBydW5RdWVyeSA9IHVzZUNhbGxiYWNrKGFzeW5jICgpID0+IHtcbiAgICBzZXRJc1J1bm5pbmcodHJ1ZSk7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGFkanVzdGVkUXVlcnkgPSBzcWwgPyByZW1vdmVTUUxDb21tZW50cyhzcWwpIDogbnVsbDtcbiAgICAgIGlmICghYWRqdXN0ZWRRdWVyeSkge1xuICAgICAgICBzZXRFcnJvcihuZXcgRXJyb3IoJ1F1ZXJ5IGlzIGVtcHR5JykpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGRiID0gZ2V0QXBwbGljYXRpb25Db25maWcoKS5kYXRhYmFzZTtcbiAgICAgIGlmICghZGIpIHtcbiAgICAgICAgc2V0RXJyb3IobmV3IEVycm9yKCdUaGUgZGF0YWJhc2UgaXMgbm90IGNvbmZpZ3VyZWQgcHJvcGVybHkuJykpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBjb25zdCBjb25uZWN0aW9uID0gYXdhaXQgZGIuY29ubmVjdCgpO1xuXG4gICAgICAvLyBUT0RPIGZpbmQgYSBjaGVhcCB3YXkgdG8gZ2V0IER1Y2tEYiB0eXBlcyB3aXRoIGEgc2luZ2xlIHF1ZXJ5IHRvIGEgcmVtb3RlIHJlc291cmNlIC0gdGVtcCB0YWJsZT8gY3RlP1xuICAgICAgY29uc3QgdGVtcFRhYmxlTmFtZSA9ICd0ZW1wX2tlcGxlcmdsX3RhYmxlJztcblxuICAgICAgLy8gcmVtb3ZlIGNvbW1lbnRzXG4gICAgICBjb25zdCBzcWxTdGF0ZW1lbnRzID0gc3BsaXRTcWxTdGF0ZW1lbnRzKGFkanVzdGVkUXVlcnkpO1xuXG4gICAgICBsZXQgYXJyb3dSZXN1bHQ6IGFycm93LlRhYmxlIHwgbnVsbCA9IG51bGw7XG4gICAgICBsZXQgdGFibGVEdWNrREJUeXBlcyA9IHt9O1xuXG4gICAgICBmb3IgKGNvbnN0IHN0YXRlbWVudCBvZiBzcWxTdGF0ZW1lbnRzKSB7XG4gICAgICAgIGNvbnN0IGlzTGFzdFF1ZXJ5ID0gc3RhdGVtZW50ID09PSBzcWxTdGF0ZW1lbnRzW3NxbFN0YXRlbWVudHMubGVuZ3RoIC0gMV07XG4gICAgICAgIGlmIChpc0xhc3RRdWVyeSAmJiAoYXdhaXQgY2hlY2tJc1NlbGVjdFF1ZXJ5KGNvbm5lY3Rpb24sIHN0YXRlbWVudCkpKSB7XG4gICAgICAgICAgLy8gMSkgY3JlYXRlIHRlbXAgdGFibGUgZnJvbSB0aGUgb3JpZ2luYWwgcXVlcnkuXG4gICAgICAgICAgYXdhaXQgY29ubmVjdGlvbi5xdWVyeShgQ1JFQVRFIE9SIFJFUExBQ0UgVEFCTEUgJyR7dGVtcFRhYmxlTmFtZX0nIEFTICR7c3RhdGVtZW50fWApO1xuXG4gICAgICAgICAgLy8gMikgcXVlcnkgZHVja2RiIHR5cGVzIGFuZCBkZXRlY3QgY2FuZGlkYXRlIGNvbHVtbnMgZm9yIFNUX2FzV0tCIHRyYW5zZm9ybS5cbiAgICAgICAgICBjb25zdCBkdWNrRGJDb2x1bW5zID0gYXdhaXQgZ2V0RHVja0RCQ29sdW1uVHlwZXMoY29ubmVjdGlvbiwgdGVtcFRhYmxlTmFtZSk7XG4gICAgICAgICAgdGFibGVEdWNrREJUeXBlcyA9IGdldER1Y2tEQkNvbHVtblR5cGVzTWFwKGR1Y2tEYkNvbHVtbnMpO1xuXG4gICAgICAgICAgLy8gMykgY2FzdCBHRU9NRVRSWSBjb2x1bW5zIHRvIFdLQiBhbmQgQmlnSW50IHRvIGRvdWJsZS5cbiAgICAgICAgICBjb25zdCBhZGp1c3RlZFF1ZXJ5ID0gY2FzdER1Y2tEQlR5cGVzRm9yS2VwbGVyKHRlbXBUYWJsZU5hbWUsIGR1Y2tEYkNvbHVtbnMpO1xuICAgICAgICAgIGFycm93UmVzdWx0ID0gYXdhaXQgY29ubmVjdGlvbi5xdWVyeShhZGp1c3RlZFF1ZXJ5KTtcblxuICAgICAgICAgIC8vIDQpIHNldCBnZW9hcnJvdyBleHRlbnNpb24gZm9yIHRoZSBhcnJvdyB0YWJsZSBhcyBEdWNrREIgZG9lc24ndCBzdXBwb3J0IHRoZSBnZW9hcnJvdyBleHRlbnNpb24uXG4gICAgICAgICAgc2V0R2VvQXJyb3dXS0JFeHRlbnNpb24oYXJyb3dSZXN1bHQsIGR1Y2tEYkNvbHVtbnMpO1xuXG4gICAgICAgICAgLy8gNSkgcmVtb3ZlIHRlbXAgdGFibGVcbiAgICAgICAgICBhd2FpdCBjb25uZWN0aW9uLnF1ZXJ5KGBEUk9QIFRBQkxFICR7dGVtcFRhYmxlTmFtZX07YCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgYXdhaXQgY29ubmVjdGlvbi5xdWVyeShzdGF0ZW1lbnQpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIFNob3cgcHJldmlldyBvbmx5IGZvciB0aGUgcmVzdWx0IG9mIHRoZSBsYXN0IHF1ZXJ5XG4gICAgICBpZiAoYXJyb3dSZXN1bHQpIHtcbiAgICAgICAgc2V0UmVzdWx0KHt0YWJsZTogYXJyb3dSZXN1bHQsIHRhYmxlRHVja0RCVHlwZXN9KTtcbiAgICAgICAgc2V0RXJyb3IobnVsbCk7XG4gICAgICB9XG5cbiAgICAgIGF3YWl0IGNvbm5lY3Rpb24uY2xvc2UoKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBzZXRFcnJvcihlIGFzIEVycm9yKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgc2V0SXNSdW5uaW5nKGZhbHNlKTtcbiAgICB9XG5cbiAgICAvLyBJbmRpY2F0ZSB0aGF0IHRoZXJlIG1heSBiZSBhIHBvc3NpYmxlIGNoYW5nZSBpbiBEdWNrREIuXG4gICAgc2V0U2NoZW1hVXBkYXRlVHJpZ2dlcihEYXRlLm5vdygpKTtcbiAgfSwgW3NxbF0pO1xuXG4gIGNvbnN0IG9uQ2hhbmdlID0gdXNlQ2FsbGJhY2soXG4gICAgdmFsdWUgPT4ge1xuICAgICAgc2V0U3FsKHZhbHVlKTtcbiAgICB9LFxuICAgIFtzZXRTcWxdXG4gICk7XG5cbiAgY29uc3Qgb25BZGRSZXN1bHRUb01hcCA9IHVzZUNhbGxiYWNrKCgpID0+IHtcbiAgICBpZiAoIXJlc3VsdCkgcmV0dXJuO1xuXG4gICAgY29uc3Qga2VwbGVyRmllbGRzID0gYXJyb3dTY2hlbWFUb0ZpZWxkcyhyZXN1bHQudGFibGUsIHJlc3VsdC50YWJsZUR1Y2tEQlR5cGVzKTtcblxuICAgIGNvbnN0IGRhdGFzZXRUb0FkZCA9IHtcbiAgICAgIGRhdGE6IHtcbiAgICAgICAgZmllbGRzOiBrZXBsZXJGaWVsZHMsXG4gICAgICAgIC8vIFRPRE8gdHlwZSBBZGREYXRhVG9NYXBQYXlsb2FkIC0+IHJvd3MgLT4gKyBhcnJvdy5UYWJsZVxuICAgICAgICByb3dzOiByZXN1bHQudGFibGUgYXMgYW55XG4gICAgICB9LFxuICAgICAgaW5mbzoge1xuICAgICAgICBpZDogZ2VuZXJhdGVIYXNoSWQoKSxcbiAgICAgICAgbGFiZWw6IGBxdWVyeV9yZXN1bHQke2NvdW50ZXIgPiAwID8gYF8ke2NvdW50ZXJ9YCA6ICcnfWAsXG4gICAgICAgIGZvcm1hdDogJ2Fycm93J1xuICAgICAgfVxuICAgIH07XG5cbiAgICBkaXNwYXRjaChhZGREYXRhVG9NYXAoe2RhdGFzZXRzOiBbZGF0YXNldFRvQWRkXX0pKTtcbiAgICBzZXRDb3VudGVyKGNvdW50ZXIgKyAxKTtcbiAgfSwgW3Jlc3VsdCwgY291bnRlciwgZGlzcGF0Y2hdKTtcblxuICBjb25zdCBpc1ZhbGlkRmlsZVR5cGUgPSB1c2VDYWxsYmFjayhmaWxlbmFtZSA9PiB7XG4gICAgY29uc3QgZmlsZUV4dCA9IFNVUFBPUlRFRF9EVUNLREJfRFJPUF9FWFRFTlNJT05TLmZpbmQoZXh0ID0+IGZpbGVuYW1lLmVuZHNXaXRoKGV4dCkpO1xuICAgIHJldHVybiBCb29sZWFuKGZpbGVFeHQpO1xuICB9LCBbXSk7XG5cbiAgY29uc3QgY3JlYXRlVGFibGVGcm9tRHJvcHBlZEZpbGUgPSB1c2VDYWxsYmFjayhhc3luYyAoZHJvcHBlZEZpbGU6IEZpbGUgfCBudWxsKSA9PiB7XG4gICAgaWYgKGRyb3BwZWRGaWxlKSB7XG4gICAgICBjb25zdCBlcnJvciA9IGF3YWl0IHRhYmxlRnJvbUZpbGUoZHJvcHBlZEZpbGUpO1xuICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgIHNldEVycm9yKGVycm9yKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHNldEVycm9yKG51bGwpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHNldERyb3BwZWRGaWxlKG51bGwpO1xuICAgIHNldERyYWdTdGF0ZShmYWxzZSk7XG4gIH0sIFtdKTtcblxuICB1c2VFZmZlY3QoKCkgPT4ge1xuICAgIGNyZWF0ZVRhYmxlRnJvbURyb3BwZWRGaWxlKGRyb3BwZWRGaWxlKTtcbiAgfSwgW2Ryb3BwZWRGaWxlLCBjcmVhdGVUYWJsZUZyb21Ecm9wcGVkRmlsZV0pO1xuXG4gIGNvbnN0IGhhbmRsZUZpbGVJbnB1dCA9IHVzZUNhbGxiYWNrKFxuICAgIChmaWxlTGlzdDogRmlsZUxpc3QsIGV2ZW50OiBEcmFnRXZlbnQpID0+IHtcbiAgICAgIGlmIChldmVudCkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZmlsZXMgPSBbLi4uZmlsZUxpc3RdLmZpbHRlcihCb29sZWFuKTtcblxuICAgICAgY29uc3QgZGlzYWJsZUV4dGVuc2lvbkZpbHRlciA9IGZhbHNlO1xuXG4gICAgICBjb25zdCBmaWxlc1RvTG9hZDogRmlsZVtdID0gW107XG4gICAgICBjb25zdCBlcnJvckZpbGVzOiBzdHJpbmdbXSA9IFtdO1xuICAgICAgZm9yIChjb25zdCBmaWxlIG9mIGZpbGVzKSB7XG4gICAgICAgIGlmIChkaXNhYmxlRXh0ZW5zaW9uRmlsdGVyIHx8IGlzVmFsaWRGaWxlVHlwZShmaWxlLm5hbWUpKSB7XG4gICAgICAgICAgZmlsZXNUb0xvYWQucHVzaChmaWxlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBlcnJvckZpbGVzLnB1c2goZmlsZS5uYW1lKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoZmlsZXNUb0xvYWQubGVuZ3RoID4gMCkge1xuICAgICAgICBzZXREcm9wcGVkRmlsZShmaWxlc1RvTG9hZFswXSk7XG4gICAgICB9IGVsc2UgaWYgKGVycm9yRmlsZXMubGVuZ3RoID4gMCkge1xuICAgICAgICBzZXRFcnJvcihuZXcgRXJyb3IoYFVuc3VwcG9ydGVkIGZpbGUgZm9ybWF0czogJHtlcnJvckZpbGVzLmpvaW4oJywgJyl9YCkpO1xuICAgICAgfVxuICAgIH0sXG4gICAgW2lzVmFsaWRGaWxlVHlwZV1cbiAgKTtcblxuICByZXR1cm4gKFxuICAgIDxTdHlsZWRTcWxQYW5lbD5cbiAgICAgIDxQYW5lbEdyb3VwIGRpcmVjdGlvbj1cImhvcml6b250YWxcIj5cbiAgICAgICAgPFBhbmVsIGRlZmF1bHRTaXplPXsyMH0gbWluU2l6ZT17MTV9IHN0eWxlPXtTQ0hFTUFfUEFORUxfU1RZTEV9IGNsYXNzTmFtZT1cInNjaGVtYS1wYW5lbFwiPlxuICAgICAgICAgIDxTdHlsZWRGaWxlRHJvcEFyZWFcbiAgICAgICAgICAgIGRyYWdPdmVyPXtkcmFnU3RhdGV9XG4gICAgICAgICAgICBvbkRyYWdPdmVyPXsoKSA9PiBzZXREcmFnU3RhdGUodHJ1ZSl9XG4gICAgICAgICAgICBvbkRyYWdMZWF2ZT17KCkgPT4gc2V0RHJhZ1N0YXRlKGZhbHNlKX1cbiAgICAgICAgICAgIGZyYW1lPXtkcm9wcGVkRmlsZUFyZWFSZWYuY3VycmVudCB8fCBkb2N1bWVudH1cbiAgICAgICAgICAgIG9uRHJvcD17aGFuZGxlRmlsZUlucHV0fVxuICAgICAgICAgICAgY2xhc3NOYW1lPVwiZmlsZS11cGxvYWRlcl9fZmlsZS1kcm9wXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8U2NoZW1hUGFuZWxcbiAgICAgICAgICAgICAgc2V0VGFibGVTY2hlbWE9e3NldFRhYmxlU2NoZW1hfVxuICAgICAgICAgICAgICBkcm9wcGVkRmlsZT17ZHJvcHBlZEZpbGV9XG4gICAgICAgICAgICAgIHNjaGVtYVVwZGF0ZVRyaWdnZXI9e3NjaGVtYVVwZGF0ZVRyaWdnZXJ9XG4gICAgICAgICAgICAvPlxuICAgICAgICAgIDwvU3R5bGVkRmlsZURyb3BBcmVhPlxuICAgICAgICA8L1BhbmVsPlxuXG4gICAgICAgIDxTdHlsZWRSZXNpemVIYW5kbGUgLz5cblxuICAgICAgICA8UGFuZWwgbWluU2l6ZT17NDB9PlxuICAgICAgICAgIDxTdHlsZWRTcWxFZGl0b3I+XG4gICAgICAgICAgICA8UGFuZWxHcm91cCBkaXJlY3Rpb249XCJ2ZXJ0aWNhbFwiPlxuICAgICAgICAgICAgICA8UGFuZWwgZGVmYXVsdFNpemU9ezMwfSBjbGFzc05hbWU9XCJlZGl0b3ItcGFuZWxcIj5cbiAgICAgICAgICAgICAgICA8U3R5bGVkRWRpdG9yUGFuZWw+XG4gICAgICAgICAgICAgICAgICA8U3R5bGVkU3FsQWN0aW9ucz5cbiAgICAgICAgICAgICAgICAgICAgPEljb25CdXR0b25cbiAgICAgICAgICAgICAgICAgICAgICBkYXRhLXRpcFxuICAgICAgICAgICAgICAgICAgICAgIGRhdGEtZm9yPVwicnVuLXF1ZXJ5LXRvb2x0aXBcIlxuICAgICAgICAgICAgICAgICAgICAgIG9uQ2xpY2s9e3J1blF1ZXJ5fVxuICAgICAgICAgICAgICAgICAgICAgIGRpc2FibGVkPXtpc1J1bm5pbmcgfHwgIXNxbH1cbiAgICAgICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgICAgIDxJY29ucy5QbGF5IGhlaWdodD1cIjE4cHhcIiAvPlxuICAgICAgICAgICAgICAgICAgICAgIDxUb29sdGlwIGlkPVwicnVuLXF1ZXJ5LXRvb2x0aXBcIiBwbGFjZT1cInRvcFwiIGVmZmVjdD1cInNvbGlkXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICBSdW4gUXVlcnkgKHtpc01hYyA/ICfijJhFbnRlcicgOiAnQ3RybCtFbnRlcid9IG9yIFNoaWZ0K0VudGVyKVxuICAgICAgICAgICAgICAgICAgICAgIDwvVG9vbHRpcD5cbiAgICAgICAgICAgICAgICAgICAgPC9JY29uQnV0dG9uPlxuICAgICAgICAgICAgICAgICAgPC9TdHlsZWRTcWxBY3Rpb25zPlxuICAgICAgICAgICAgICAgICAgPFN0eWxlZEVkaXRvciBpc1J1bm5pbmc9e2lzUnVubmluZ30+XG4gICAgICAgICAgICAgICAgICAgIDxNb25hY29FZGl0b3JcbiAgICAgICAgICAgICAgICAgICAgICBpc1JlYWRPbmx5PXtpc1J1bm5pbmd9XG4gICAgICAgICAgICAgICAgICAgICAgb25SdW5RdWVyeT17cnVuUXVlcnl9XG4gICAgICAgICAgICAgICAgICAgICAgb25DaGFuZ2U9e29uQ2hhbmdlfVxuICAgICAgICAgICAgICAgICAgICAgIHRhYmxlU2NoZW1hPXt0YWJsZVNjaGVtYX1cbiAgICAgICAgICAgICAgICAgICAgICBjb2RlPXtzcWx9XG4gICAgICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgICAgICA8L1N0eWxlZEVkaXRvcj5cbiAgICAgICAgICAgICAgICA8L1N0eWxlZEVkaXRvclBhbmVsPlxuICAgICAgICAgICAgICA8L1BhbmVsPlxuXG4gICAgICAgICAgICAgIDxTdHlsZWRWZXJ0aWNhbFJlc2l6ZUhhbmRsZSAvPlxuICAgICAgICAgICAgICA8UGFuZWwgY2xhc3NOYW1lPVwicHJldmlldy1wYW5lbFwiPlxuICAgICAgICAgICAgICAgIHtpc1J1bm5pbmcgPyAoXG4gICAgICAgICAgICAgICAgICA8U3R5bGVkTG9hZGluZ0NvbnRhaW5lcj5cbiAgICAgICAgICAgICAgICAgICAgPExvYWRpbmdTcGlubmVyIC8+XG4gICAgICAgICAgICAgICAgICA8L1N0eWxlZExvYWRpbmdDb250YWluZXI+XG4gICAgICAgICAgICAgICAgKSA6IGVycm9yID8gKFxuICAgICAgICAgICAgICAgICAgPFN0eWxlZEVycm9yQ29udGFpbmVyPlxuICAgICAgICAgICAgICAgICAgICA8ZGl2PntlcnJvci5tZXNzYWdlfTwvZGl2PlxuICAgICAgICAgICAgICAgICAgPC9TdHlsZWRFcnJvckNvbnRhaW5lcj5cbiAgICAgICAgICAgICAgICApIDogcmVzdWx0ID8gKFxuICAgICAgICAgICAgICAgICAgPFN0eWxlZERhdGFQYW5lbD5cbiAgICAgICAgICAgICAgICAgICAgPFN0eWxlZFJlc3VsdEFjdGlvbnM+XG4gICAgICAgICAgICAgICAgICAgICAgPEJ1dHRvbiBzZWNvbmRhcnkgb25DbGljaz17b25BZGRSZXN1bHRUb01hcH0+XG4gICAgICAgICAgICAgICAgICAgICAgICBBZGQgdG8gTWFwXG4gICAgICAgICAgICAgICAgICAgICAgPC9CdXR0b24+XG4gICAgICAgICAgICAgICAgICAgICAgPGRpdj57cmVzdWx0LnRhYmxlLm51bVJvd3N9IHJvd3M8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgPC9TdHlsZWRSZXN1bHRBY3Rpb25zPlxuICAgICAgICAgICAgICAgICAgICA8UHJldmlld0RhdGFQYW5lbFxuICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdD17cmVzdWx0fVxuICAgICAgICAgICAgICAgICAgICAgIGRhdGFUYWJsZVN0eWxlPXt7fX1cbiAgICAgICAgICAgICAgICAgICAgICBvbkFkZFJlc3VsdFRvTWFwPXtvbkFkZFJlc3VsdFRvTWFwfVxuICAgICAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgICAgPC9TdHlsZWREYXRhUGFuZWw+XG4gICAgICAgICAgICAgICAgKSA6IG51bGx9XG4gICAgICAgICAgICAgIDwvUGFuZWw+XG4gICAgICAgICAgICA8L1BhbmVsR3JvdXA+XG4gICAgICAgICAgPC9TdHlsZWRTcWxFZGl0b3I+XG4gICAgICAgIDwvUGFuZWw+XG4gICAgICA8L1BhbmVsR3JvdXA+XG4gICAgPC9TdHlsZWRTcWxQYW5lbD5cbiAgKTtcbn07XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7QUFJQSxJQUFBQSxNQUFBLEdBQUFDLHVCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBQyxXQUFBLEdBQUFELE9BQUE7QUFDQSxJQUFBRSxpQkFBQSxHQUFBQyxzQkFBQSxDQUFBSCxPQUFBO0FBQ0EsSUFBQUkscUJBQUEsR0FBQUosT0FBQTtBQUVBLElBQUFLLFFBQUEsR0FBQUwsT0FBQTtBQUNBLElBQUFNLFlBQUEsR0FBQU4sT0FBQTtBQUNBLElBQUFPLFdBQUEsR0FBQVAsT0FBQTtBQUNBLElBQUFRLFdBQUEsR0FBQVIsT0FBQTtBQUNBLElBQUFTLE9BQUEsR0FBQVQsT0FBQTtBQUNBLElBQUFVLE1BQUEsR0FBQVYsT0FBQTtBQUVBLElBQUFXLGFBQUEsR0FBQVIsc0JBQUEsQ0FBQUgsT0FBQTtBQUNBLElBQUFZLFlBQUEsR0FBQVosT0FBQTtBQUNBLElBQUFhLGlCQUFBLEdBQUFiLE9BQUE7QUFFQSxJ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