UNPKG

matrix-react-sdk

Version:
329 lines (317 loc) 58.6 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.MatrixClientPeg = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _matrix = require("matrix-js-sdk/src/matrix"); var _types = require("matrix-js-sdk/src/types"); var utils = _interopRequireWildcard(require("matrix-js-sdk/src/utils")); var _logger = require("matrix-js-sdk/src/logger"); var _createMatrixClient = _interopRequireDefault(require("./utils/createMatrixClient")); var _SettingsStore = _interopRequireDefault(require("./settings/SettingsStore")); var _MatrixActionCreators = _interopRequireDefault(require("./actions/MatrixActionCreators")); var _Modal = _interopRequireDefault(require("./Modal")); var _MatrixClientBackedSettingsHandler = _interopRequireDefault(require("./settings/handlers/MatrixClientBackedSettingsHandler")); var StorageManager = _interopRequireWildcard(require("./utils/StorageManager")); var _IdentityAuthClient = _interopRequireDefault(require("./IdentityAuthClient")); var _SecurityManager = require("./SecurityManager"); var _SlidingSyncManager = require("./SlidingSyncManager"); var _languageHandler = require("./languageHandler"); var _SettingLevel = require("./settings/SettingLevel"); var _MatrixClientBackedController = _interopRequireDefault(require("./settings/controllers/MatrixClientBackedController")); var _ErrorDialog = _interopRequireDefault(require("./components/views/dialogs/ErrorDialog")); var _PlatformPeg = _interopRequireDefault(require("./PlatformPeg")); var _FormattingUtils = require("./utils/FormattingUtils"); var _SdkConfig = _interopRequireDefault(require("./SdkConfig")); var _Settings = require("./settings/Settings"); var _DeviceIsolationModeController = require("./settings/controllers/DeviceIsolationModeController.ts"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } /* Copyright 2024 New Vector Ltd. Copyright 2019-2023 The Matrix.org Foundation C.I.C. Copyright 2017, 2018 , 2019 New Vector Ltd Copyright 2017 Vector Creations Ltd. Copyright 2015, 2016 OpenMarket Ltd SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ /** * Holds the current instance of the `MatrixClient` to use across the codebase. * Looking for an `MatrixClient`? Just look for the `MatrixClientPeg` on the peg * board. "Peg" is the literal meaning of something you hang something on. So * you'll find a `MatrixClient` hanging on the `MatrixClientPeg`. */ /** * Wrapper object for handling the js-sdk Matrix Client object in the react-sdk * Handles the creation/initialisation of client objects. * This module provides a singleton instance of this class so the 'current' * Matrix Client object is available easily. */ class MatrixClientPegClass { constructor() { // These are the default options used when when the // client is started in 'start'. These can be altered // at any time up to after the 'will_start_client' // event is finished processing. (0, _defineProperty2.default)(this, "opts", { initialSyncLimit: 20 }); (0, _defineProperty2.default)(this, "matrixClient", null); (0, _defineProperty2.default)(this, "justRegisteredUserId", null); (0, _defineProperty2.default)(this, "onUnexpectedStoreClose", async () => { if (!this.matrixClient) return; this.matrixClient.stopClient(); // stop the client as the database has failed this.matrixClient.store.destroy(); if (!this.matrixClient.isGuest()) { // If the user is not a guest then prompt them to reload rather than doing it for them // For guests this is likely to happen during e-mail verification as part of registration const brand = _SdkConfig.default.get().brand; const platform = _PlatformPeg.default.get()?.getHumanReadableName(); // Determine the description based on the platform const description = platform === "Web Platform" ? (0, _languageHandler._t)("error_database_closed_description|for_web", { brand }) : (0, _languageHandler._t)("error_database_closed_description|for_desktop"); const [reload] = await _Modal.default.createDialog(_ErrorDialog.default, { title: (0, _languageHandler._t)("error_database_closed_title", { brand }), description, button: (0, _languageHandler._t)("action|reload") }).finished; if (!reload) return; } _PlatformPeg.default.get()?.reload(); }); } get() { return this.matrixClient; } safeGet() { if (!this.matrixClient) { throw new _languageHandler.UserFriendlyError("error_user_not_logged_in"); } return this.matrixClient; } unset() { this.matrixClient = null; _MatrixActionCreators.default.stop(); } setJustRegisteredUserId(uid) { this.justRegisteredUserId = uid; if (uid) { const registrationTime = Date.now().toString(); window.localStorage.setItem("mx_registration_time", registrationTime); } } currentUserIsJustRegistered() { return !!this.matrixClient && this.matrixClient.credentials.userId === this.justRegisteredUserId; } userRegisteredWithinLastHours(hours) { if (hours <= 0) { return false; } try { const registrationTime = parseInt(window.localStorage.getItem("mx_registration_time"), 10); const diff = Date.now() - registrationTime; return diff / 36e5 <= hours; } catch (e) { return false; } } userRegisteredAfter(timestamp) { try { const registrationTime = parseInt(window.localStorage.getItem("mx_registration_time"), 10); return timestamp.getTime() <= registrationTime; } catch (e) { return false; } } replaceUsingCreds(creds, tokenRefreshFunction) { this.createClient(creds, tokenRefreshFunction); } /** * Implementation of {@link IMatrixClientPeg.assign}. */ async assign(assignOpts = {}) { if (!this.matrixClient) { throw new Error("createClient must be called first"); } for (const dbType of ["indexeddb", "memory"]) { try { const promise = this.matrixClient.store.startup(); _logger.logger.log("MatrixClientPeg: waiting for MatrixClient store to initialise"); await promise; break; } catch (err) { if (dbType === "indexeddb") { _logger.logger.error("Error starting matrixclient store - falling back to memory store", err); this.matrixClient.store = new _matrix.MemoryStore({ localStorage: localStorage }); } else { _logger.logger.error("Failed to start memory store!", err); throw err; } } } this.matrixClient.store.on?.("closed", this.onUnexpectedStoreClose); // try to initialise e2e on the new client if (!_SettingsStore.default.getValue("lowBandwidth")) { await this.initClientCrypto(assignOpts.rustCryptoStoreKey, assignOpts.rustCryptoStorePassword); } const opts = utils.deepCopy(this.opts); // the react sdk doesn't work without this, so don't allow opts.pendingEventOrdering = _matrix.PendingEventOrdering.Detached; opts.lazyLoadMembers = true; opts.clientWellKnownPollPeriod = 2 * 60 * 60; // 2 hours opts.threadSupport = true; if (_SettingsStore.default.getValue("feature_sliding_sync")) { opts.slidingSync = await _SlidingSyncManager.SlidingSyncManager.instance.setup(this.matrixClient); } else { _SlidingSyncManager.SlidingSyncManager.instance.checkSupport(this.matrixClient); } // Connect the matrix client to the dispatcher and setting handlers _MatrixActionCreators.default.start(this.matrixClient); _MatrixClientBackedSettingsHandler.default.matrixClient = this.matrixClient; _MatrixClientBackedController.default.matrixClient = this.matrixClient; return opts; } /** * Attempt to initialize the crypto layer on a newly-created MatrixClient * * @param rustCryptoStoreKey - A key with which to encrypt the rust crypto indexeddb. * If provided, it must be exactly 32 bytes of data. If both this and `rustCryptoStorePassword` are * undefined, the store will be unencrypted. * * @param rustCryptoStorePassword - An alternative to `rustCryptoStoreKey`. Ignored if `rustCryptoStoreKey` is set. * A password which will be used to derive a key to encrypt the store with. Deriving a key from a password is * (deliberately) a slow operation, so prefer to pass a `rustCryptoStoreKey` directly where possible. */ async initClientCrypto(rustCryptoStoreKey, rustCryptoStorePassword) { if (!this.matrixClient) { throw new Error("createClient must be called first"); } if (!rustCryptoStoreKey && !rustCryptoStorePassword) { _logger.logger.error("Warning! Not using an encryption key for rust crypto store."); } // Record the fact that we used the Rust crypto stack with this client. This just guards against people // rolling back to versions of EW that did not default to Rust crypto (which would lead to an error, since // we cannot migrate from Rust to Legacy crypto). await _SettingsStore.default.setValue(_Settings.Features.RustCrypto, null, _SettingLevel.SettingLevel.DEVICE, true); await this.matrixClient.initRustCrypto({ storageKey: rustCryptoStoreKey, storagePassword: rustCryptoStorePassword }); StorageManager.setCryptoInitialised(true); (0, _DeviceIsolationModeController.setDeviceIsolationMode)(this.matrixClient, _SettingsStore.default.getValue("feature_exclude_insecure_devices")); // TODO: device dehydration and whathaveyou return; } /** * Implementation of {@link IMatrixClientPeg.start}. */ async start(assignOpts) { const opts = await this.assign(assignOpts); _logger.logger.log(`MatrixClientPeg: really starting MatrixClient`); await this.matrixClient.startClient(opts); _logger.logger.log(`MatrixClientPeg: MatrixClient started`); } namesToRoomName(names, count) { const countWithoutMe = count - 1; if (!names.length) { return (0, _languageHandler._t)("empty_room"); } if (names.length === 1 && countWithoutMe <= 1) { return names[0]; } } memberNamesToRoomName(names, count) { const name = this.namesToRoomName(names, count); if (name) return name; if (names.length === 2 && count === 2) { return (0, _FormattingUtils.formatList)(names); } return (0, _FormattingUtils.formatList)(names, 1); } inviteeNamesToRoomName(names, count) { const name = this.namesToRoomName(names, count); if (name) return name; if (names.length === 2 && count === 2) { return (0, _languageHandler._t)("inviting_user1_and_user2", { user1: names[0], user2: names[1] }); } return (0, _languageHandler._t)("inviting_user_and_n_others", { user: names[0], count: count - 1 }); } createClient(creds, tokenRefreshFunction) { const opts = { baseUrl: creds.homeserverUrl, idBaseUrl: creds.identityServerUrl, accessToken: creds.accessToken, refreshToken: creds.refreshToken, tokenRefreshFunction, userId: creds.userId, deviceId: creds.deviceId, pickleKey: creds.pickleKey, timelineSupport: true, forceTURN: !_SettingsStore.default.getValue("webRtcAllowPeerToPeer"), fallbackICEServerAllowed: !!_SettingsStore.default.getValue("fallbackICEServerAllowed"), // Gather up to 20 ICE candidates when a call arrives: this should be more than we'd // ever normally need, so effectively this should make all the gathering happen when // the call arrives. iceCandidatePoolSize: 20, verificationMethods: [_types.VerificationMethod.Sas, _types.VerificationMethod.ShowQrCode, _types.VerificationMethod.Reciprocate], identityServer: new _IdentityAuthClient.default(), // These are always installed regardless of the labs flag so that cross-signing features // can toggle on without reloading and also be accessed immediately after login. cryptoCallbacks: _objectSpread({}, _SecurityManager.crossSigningCallbacks), roomNameGenerator: (_, state) => { switch (state.type) { case _matrix.RoomNameType.Generated: switch (state.subtype) { case "Inviting": return this.inviteeNamesToRoomName(state.names, state.count); default: return this.memberNamesToRoomName(state.names, state.count); } case _matrix.RoomNameType.EmptyRoom: if (state.oldName) { return (0, _languageHandler._t)("empty_room_was_name", { oldName: state.oldName }); } else { return (0, _languageHandler._t)("empty_room"); } default: return null; } } }; this.matrixClient = (0, _createMatrixClient.default)(opts); this.matrixClient.setGuest(Boolean(creds.guest)); const notifTimelineSet = new _matrix.EventTimelineSet(undefined, { timelineSupport: true, pendingEvents: false }); // XXX: what is our initial pagination token?! it somehow needs to be synchronised with /sync. notifTimelineSet.getLiveTimeline().setPaginationToken("", _matrix.EventTimeline.BACKWARDS); this.matrixClient.setNotifTimelineSet(notifTimelineSet); } } /** * Note: You should be using a React context with access to a client rather than * using this, as in a multi-account world this will not exist! */ const MatrixClientPeg = exports.MatrixClientPeg = new MatrixClientPegClass(); if (!window.mxMatrixClientPeg) { window.mxMatrixClientPeg = MatrixClientPeg; } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbWF0cml4IiwicmVxdWlyZSIsIl90eXBlcyIsInV0aWxzIiwiX2ludGVyb3BSZXF1aXJlV2lsZGNhcmQiLCJfbG9nZ2VyIiwiX2NyZWF0ZU1hdHJpeENsaWVudCIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJfU2V0dGluZ3NTdG9yZSIsIl9NYXRyaXhBY3Rpb25DcmVhdG9ycyIsIl9Nb2RhbCIsIl9NYXRyaXhDbGllbnRCYWNrZWRTZXR0aW5nc0hhbmRsZXIiLCJTdG9yYWdlTWFuYWdlciIsIl9JZGVudGl0eUF1dGhDbGllbnQiLCJfU2VjdXJpdHlNYW5hZ2VyIiwiX1NsaWRpbmdTeW5jTWFuYWdlciIsIl9sYW5ndWFnZUhhbmRsZXIiLCJfU2V0dGluZ0xldmVsIiwiX01hdHJpeENsaWVudEJhY2tlZENvbnRyb2xsZXIiLCJfRXJyb3JEaWFsb2ciLCJfUGxhdGZvcm1QZWciLCJfRm9ybWF0dGluZ1V0aWxzIiwiX1Nka0NvbmZpZyIsIl9TZXR0aW5ncyIsIl9EZXZpY2VJc29sYXRpb25Nb2RlQ29udHJvbGxlciIsIl9nZXRSZXF1aXJlV2lsZGNhcmRDYWNoZSIsImUiLCJXZWFrTWFwIiwiciIsInQiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsImhhcyIsImdldCIsIm4iLCJfX3Byb3RvX18iLCJhIiwiT2JqZWN0IiwiZGVmaW5lUHJvcGVydHkiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJ1IiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiaSIsInNldCIsIm93bktleXMiLCJrZXlzIiwiZ2V0T3duUHJvcGVydHlTeW1ib2xzIiwibyIsImZpbHRlciIsImVudW1lcmFibGUiLCJwdXNoIiwiYXBwbHkiLCJfb2JqZWN0U3ByZWFkIiwiYXJndW1lbnRzIiwibGVuZ3RoIiwiZm9yRWFjaCIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzIiwiZGVmaW5lUHJvcGVydGllcyIsIk1hdHJpeENsaWVudFBlZ0NsYXNzIiwiY29uc3RydWN0b3IiLCJpbml0aWFsU3luY0xpbWl0IiwibWF0cml4Q2xpZW50Iiwic3RvcENsaWVudCIsInN0b3JlIiwiZGVzdHJveSIsImlzR3Vlc3QiLCJicmFuZCIsIlNka0NvbmZpZyIsInBsYXRmb3JtIiwiUGxhdGZvcm1QZWciLCJnZXRIdW1hblJlYWRhYmxlTmFtZSIsImRlc2NyaXB0aW9uIiwiX3QiLCJyZWxvYWQiLCJNb2RhbCIsImNyZWF0ZURpYWxvZyIsIkVycm9yRGlhbG9nIiwidGl0bGUiLCJidXR0b24iLCJmaW5pc2hlZCIsInNhZmVHZXQiLCJVc2VyRnJpZW5kbHlFcnJvciIsInVuc2V0IiwiTWF0cml4QWN0aW9uQ3JlYXRvcnMiLCJzdG9wIiwic2V0SnVzdFJlZ2lzdGVyZWRVc2VySWQiLCJ1aWQiLCJqdXN0UmVnaXN0ZXJlZFVzZXJJZCIsInJlZ2lzdHJhdGlvblRpbWUiLCJEYXRlIiwibm93IiwidG9TdHJpbmciLCJ3aW5kb3ciLCJsb2NhbFN0b3JhZ2UiLCJzZXRJdGVtIiwiY3VycmVudFVzZXJJc0p1c3RSZWdpc3RlcmVkIiwiY3JlZGVudGlhbHMiLCJ1c2VySWQiLCJ1c2VyUmVnaXN0ZXJlZFdpdGhpbkxhc3RIb3VycyIsImhvdXJzIiwicGFyc2VJbnQiLCJnZXRJdGVtIiwiZGlmZiIsInVzZXJSZWdpc3RlcmVkQWZ0ZXIiLCJ0aW1lc3RhbXAiLCJnZXRUaW1lIiwicmVwbGFjZVVzaW5nQ3JlZHMiLCJjcmVkcyIsInRva2VuUmVmcmVzaEZ1bmN0aW9uIiwiY3JlYXRlQ2xpZW50IiwiYXNzaWduIiwiYXNzaWduT3B0cyIsIkVycm9yIiwiZGJUeXBlIiwicHJvbWlzZSIsInN0YXJ0dXAiLCJsb2dnZXIiLCJsb2ciLCJlcnIiLCJlcnJvciIsIk1lbW9yeVN0b3JlIiwib24iLCJvblVuZXhwZWN0ZWRTdG9yZUNsb3NlIiwiU2V0dGluZ3NTdG9yZSIsImdldFZhbHVlIiwiaW5pdENsaWVudENyeXB0byIsInJ1c3RDcnlwdG9TdG9yZUtleSIsInJ1c3RDcnlwdG9TdG9yZVBhc3N3b3JkIiwib3B0cyIsImRlZXBDb3B5IiwicGVuZGluZ0V2ZW50T3JkZXJpbmciLCJQZW5kaW5nRXZlbnRPcmRlcmluZyIsIkRldGFjaGVkIiwibGF6eUxvYWRNZW1iZXJzIiwiY2xpZW50V2VsbEtub3duUG9sbFBlcmlvZCIsInRocmVhZFN1cHBvcnQiLCJzbGlkaW5nU3luYyIsIlNsaWRpbmdTeW5jTWFuYWdlciIsImluc3RhbmNlIiwic2V0dXAiLCJjaGVja1N1cHBvcnQiLCJzdGFydCIsIk1hdHJpeENsaWVudEJhY2tlZFNldHRpbmdzSGFuZGxlciIsIk1hdHJpeENsaWVudEJhY2tlZENvbnRyb2xsZXIiLCJzZXRWYWx1ZSIsIkZlYXR1cmVzIiwiUnVzdENyeXB0byIsIlNldHRpbmdMZXZlbCIsIkRFVklDRSIsImluaXRSdXN0Q3J5cHRvIiwic3RvcmFnZUtleSIsInN0b3JhZ2VQYXNzd29yZCIsInNldENyeXB0b0luaXRpYWxpc2VkIiwic2V0RGV2aWNlSXNvbGF0aW9uTW9kZSIsInN0YXJ0Q2xpZW50IiwibmFtZXNUb1Jvb21OYW1lIiwibmFtZXMiLCJjb3VudCIsImNvdW50V2l0aG91dE1lIiwibWVtYmVyTmFtZXNUb1Jvb21OYW1lIiwibmFtZSIsImZvcm1hdExpc3QiLCJpbnZpdGVlTmFtZXNUb1Jvb21OYW1lIiwidXNlcjEiLCJ1c2VyMiIsInVzZXIiLCJiYXNlVXJsIiwiaG9tZXNlcnZlclVybCIsImlkQmFzZVVybCIsImlkZW50aXR5U2VydmVyVXJsIiwiYWNjZXNzVG9rZW4iLCJyZWZyZXNoVG9rZW4iLCJkZXZpY2VJZCIsInBpY2tsZUtleSIsInRpbWVsaW5lU3VwcG9ydCIsImZvcmNlVFVSTiIsImZhbGxiYWNrSUNFU2VydmVyQWxsb3dlZCIsImljZUNhbmRpZGF0ZVBvb2xTaXplIiwidmVyaWZpY2F0aW9uTWV0aG9kcyIsIlZlcmlmaWNhdGlvbk1ldGhvZCIsIlNhcyIsIlNob3dRckNvZGUiLCJSZWNpcHJvY2F0ZSIsImlkZW50aXR5U2VydmVyIiwiSWRlbnRpdHlBdXRoQ2xpZW50IiwiY3J5cHRvQ2FsbGJhY2tzIiwiY3Jvc3NTaWduaW5nQ2FsbGJhY2tzIiwicm9vbU5hbWVHZW5lcmF0b3IiLCJfIiwic3RhdGUiLCJ0eXBlIiwiUm9vbU5hbWVUeXBlIiwiR2VuZXJhdGVkIiwic3VidHlwZSIsIkVtcHR5Um9vbSIsIm9sZE5hbWUiLCJjcmVhdGVNYXRyaXhDbGllbnQiLCJzZXRHdWVzdCIsIkJvb2xlYW4iLCJndWVzdCIsIm5vdGlmVGltZWxpbmVTZXQiLCJFdmVudFRpbWVsaW5lU2V0IiwidW5kZWZpbmVkIiwicGVuZGluZ0V2ZW50cyIsImdldExpdmVUaW1lbGluZSIsInNldFBhZ2luYXRpb25Ub2tlbiIsIkV2ZW50VGltZWxpbmUiLCJCQUNLV0FSRFMiLCJzZXROb3RpZlRpbWVsaW5lU2V0IiwiTWF0cml4Q2xpZW50UGVnIiwiZXhwb3J0cyIsIm14TWF0cml4Q2xpZW50UGVnIl0sInNvdXJjZXMiOlsiLi4vc3JjL01hdHJpeENsaWVudFBlZy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMjQgTmV3IFZlY3RvciBMdGQuXG5Db3B5cmlnaHQgMjAxOS0yMDIzIFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5Db3B5cmlnaHQgMjAxNywgMjAxOCAsIDIwMTkgTmV3IFZlY3RvciBMdGRcbkNvcHlyaWdodCAyMDE3IFZlY3RvciBDcmVhdGlvbnMgTHRkLlxuQ29weXJpZ2h0IDIwMTUsIDIwMTYgT3Blbk1hcmtldCBMdGRcblxuU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFHUEwtMy4wLW9ubHkgT1IgR1BMLTMuMC1vbmx5XG5QbGVhc2Ugc2VlIExJQ0VOU0UgZmlsZXMgaW4gdGhlIHJlcG9zaXRvcnkgcm9vdCBmb3IgZnVsbCBkZXRhaWxzLlxuKi9cblxuaW1wb3J0IHtcbiAgICBFdmVudFRpbWVsaW5lLFxuICAgIEV2ZW50VGltZWxpbmVTZXQsXG4gICAgSUNyZWF0ZUNsaWVudE9wdHMsXG4gICAgSVN0YXJ0Q2xpZW50T3B0cyxcbiAgICBNYXRyaXhDbGllbnQsXG4gICAgTWVtb3J5U3RvcmUsXG4gICAgUGVuZGluZ0V2ZW50T3JkZXJpbmcsXG4gICAgUm9vbU5hbWVTdGF0ZSxcbiAgICBSb29tTmFtZVR5cGUsXG4gICAgVG9rZW5SZWZyZXNoRnVuY3Rpb24sXG59IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tYXRyaXhcIjtcbmltcG9ydCB7IFZlcmlmaWNhdGlvbk1ldGhvZCB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy90eXBlc1wiO1xuaW1wb3J0ICogYXMgdXRpbHMgZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL3V0aWxzXCI7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbG9nZ2VyXCI7XG5cbmltcG9ydCBjcmVhdGVNYXRyaXhDbGllbnQgZnJvbSBcIi4vdXRpbHMvY3JlYXRlTWF0cml4Q2xpZW50XCI7XG5pbXBvcnQgU2V0dGluZ3NTdG9yZSBmcm9tIFwiLi9zZXR0aW5ncy9TZXR0aW5nc1N0b3JlXCI7XG5pbXBvcnQgTWF0cml4QWN0aW9uQ3JlYXRvcnMgZnJvbSBcIi4vYWN0aW9ucy9NYXRyaXhBY3Rpb25DcmVhdG9yc1wiO1xuaW1wb3J0IE1vZGFsIGZyb20gXCIuL01vZGFsXCI7XG5pbXBvcnQgTWF0cml4Q2xpZW50QmFja2VkU2V0dGluZ3NIYW5kbGVyIGZyb20gXCIuL3NldHRpbmdzL2hhbmRsZXJzL01hdHJpeENsaWVudEJhY2tlZFNldHRpbmdzSGFuZGxlclwiO1xuaW1wb3J0ICogYXMgU3RvcmFnZU1hbmFnZXIgZnJvbSBcIi4vdXRpbHMvU3RvcmFnZU1hbmFnZXJcIjtcbmltcG9ydCBJZGVudGl0eUF1dGhDbGllbnQgZnJvbSBcIi4vSWRlbnRpdHlBdXRoQ2xpZW50XCI7XG5pbXBvcnQgeyBjcm9zc1NpZ25pbmdDYWxsYmFja3MgfSBmcm9tIFwiLi9TZWN1cml0eU1hbmFnZXJcIjtcbmltcG9ydCB7IFNsaWRpbmdTeW5jTWFuYWdlciB9IGZyb20gXCIuL1NsaWRpbmdTeW5jTWFuYWdlclwiO1xuaW1wb3J0IHsgX3QsIFVzZXJGcmllbmRseUVycm9yIH0gZnJvbSBcIi4vbGFuZ3VhZ2VIYW5kbGVyXCI7XG5pbXBvcnQgeyBTZXR0aW5nTGV2ZWwgfSBmcm9tIFwiLi9zZXR0aW5ncy9TZXR0aW5nTGV2ZWxcIjtcbmltcG9ydCBNYXRyaXhDbGllbnRCYWNrZWRDb250cm9sbGVyIGZyb20gXCIuL3NldHRpbmdzL2NvbnRyb2xsZXJzL01hdHJpeENsaWVudEJhY2tlZENvbnRyb2xsZXJcIjtcbmltcG9ydCBFcnJvckRpYWxvZyBmcm9tIFwiLi9jb21wb25lbnRzL3ZpZXdzL2RpYWxvZ3MvRXJyb3JEaWFsb2dcIjtcbmltcG9ydCBQbGF0Zm9ybVBlZyBmcm9tIFwiLi9QbGF0Zm9ybVBlZ1wiO1xuaW1wb3J0IHsgZm9ybWF0TGlzdCB9IGZyb20gXCIuL3V0aWxzL0Zvcm1hdHRpbmdVdGlsc1wiO1xuaW1wb3J0IFNka0NvbmZpZyBmcm9tIFwiLi9TZGtDb25maWdcIjtcbmltcG9ydCB7IEZlYXR1cmVzIH0gZnJvbSBcIi4vc2V0dGluZ3MvU2V0dGluZ3NcIjtcbmltcG9ydCB7IHNldERldmljZUlzb2xhdGlvbk1vZGUgfSBmcm9tIFwiLi9zZXR0aW5ncy9jb250cm9sbGVycy9EZXZpY2VJc29sYXRpb25Nb2RlQ29udHJvbGxlci50c1wiO1xuXG5leHBvcnQgaW50ZXJmYWNlIElNYXRyaXhDbGllbnRDcmVkcyB7XG4gICAgaG9tZXNlcnZlclVybDogc3RyaW5nO1xuICAgIGlkZW50aXR5U2VydmVyVXJsPzogc3RyaW5nO1xuICAgIHVzZXJJZDogc3RyaW5nO1xuICAgIGRldmljZUlkPzogc3RyaW5nO1xuICAgIGFjY2Vzc1Rva2VuOiBzdHJpbmc7XG4gICAgcmVmcmVzaFRva2VuPzogc3RyaW5nO1xuICAgIGd1ZXN0PzogYm9vbGVhbjtcbiAgICBwaWNrbGVLZXk/OiBzdHJpbmc7XG4gICAgZnJlc2hMb2dpbj86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTWF0cml4Q2xpZW50UGVnQXNzaWduT3B0cyB7XG4gICAgLyoqXG4gICAgICogSWYgd2UgYXJlIHVzaW5nIFJ1c3QgY3J5cHRvLCBhIGtleSB3aXRoIHdoaWNoIHRvIGVuY3J5cHQgdGhlIGluZGV4ZWRkYi5cbiAgICAgKlxuICAgICAqIElmIHByb3ZpZGVkLCBpdCBtdXN0IGJlIGV4YWN0bHkgMzIgYnl0ZXMgb2YgZGF0YS4gSWYgYm90aCB0aGlzIGFuZFxuICAgICAqIHtAbGluayBNYXRyaXhDbGllbnRQZWdBc3NpZ25PcHRzLnJ1c3RDcnlwdG9TdG9yZVBhc3N3b3JkfSBhcmUgdW5kZWZpbmVkLFxuICAgICAqIHRoZSBzdG9yZSB3aWxsIGJlIHVuZW5jcnlwdGVkLlxuICAgICAqL1xuICAgIHJ1c3RDcnlwdG9TdG9yZUtleT86IFVpbnQ4QXJyYXk7XG5cbiAgICAvKipcbiAgICAgKiBJZiB3ZSBhcmUgdXNpbmcgUnVzdCBjcnlwdG8sIGEgcGFzc3dvcmQgd2hpY2ggd2lsbCBiZSB1c2VkIHRvIGRlcml2ZSBhIGtleSB0byBlbmNyeXB0IHRoZSBzdG9yZSB3aXRoLlxuICAgICAqXG4gICAgICogQW4gYWx0ZXJuYXRpdmUgdG8ge0BsaW5rIE1hdHJpeENsaWVudFBlZ0Fzc2lnbk9wdHMucnVzdENyeXB0b1N0b3JlS2V5fS4gSWdub3JlZCBpZiBgcnVzdENyeXB0b1N0b3JlS2V5YCBpcyBzZXQuXG4gICAgICpcbiAgICAgKiBEZXJpdmluZyBhIGtleSBmcm9tIGEgcGFzc3dvcmQgaXMgKGRlbGliZXJhdGVseSkgYSBzbG93IG9wZXJhdGlvbiwgc28gcHJlZmVyIHRvIHBhc3MgYSBgcnVzdENyeXB0b1N0b3JlS2V5YFxuICAgICAqIGRpcmVjdGx5IHdoZXJlIHBvc3NpYmxlLlxuICAgICAqL1xuICAgIHJ1c3RDcnlwdG9TdG9yZVBhc3N3b3JkPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIEhvbGRzIHRoZSBjdXJyZW50IGluc3RhbmNlIG9mIHRoZSBgTWF0cml4Q2xpZW50YCB0byB1c2UgYWNyb3NzIHRoZSBjb2RlYmFzZS5cbiAqIExvb2tpbmcgZm9yIGFuIGBNYXRyaXhDbGllbnRgPyBKdXN0IGxvb2sgZm9yIHRoZSBgTWF0cml4Q2xpZW50UGVnYCBvbiB0aGUgcGVnXG4gKiBib2FyZC4gXCJQZWdcIiBpcyB0aGUgbGl0ZXJhbCBtZWFuaW5nIG9mIHNvbWV0aGluZyB5b3UgaGFuZyBzb21ldGhpbmcgb24uIFNvXG4gKiB5b3UnbGwgZmluZCBhIGBNYXRyaXhDbGllbnRgIGhhbmdpbmcgb24gdGhlIGBNYXRyaXhDbGllbnRQZWdgLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIElNYXRyaXhDbGllbnRQZWcge1xuICAgIC8qKlxuICAgICAqIFRoZSBvcHRzIHVzZWQgdG8gc3RhcnQgdGhlIGNsaWVudFxuICAgICAqL1xuICAgIG9wdHM6IElTdGFydENsaWVudE9wdHM7XG5cbiAgICAvKipcbiAgICAgKiBHZXQgdGhlIGN1cnJlbnQgTWF0cml4Q2xpZW50LCBpZiBhbnlcbiAgICAgKi9cbiAgICBnZXQoKTogTWF0cml4Q2xpZW50IHwgbnVsbDtcblxuICAgIC8qKlxuICAgICAqIEdldCB0aGUgY3VycmVudCBNYXRyaXhDbGllbnQsIHRocm93aW5nIGFuIGVycm9yIGlmIHRoZXJlIGlzbid0IG9uZVxuICAgICAqL1xuICAgIHNhZmVHZXQoKTogTWF0cml4Q2xpZW50O1xuXG4gICAgLyoqXG4gICAgICogVW5zZXQgdGhlIGN1cnJlbnQgTWF0cml4Q2xpZW50XG4gICAgICovXG4gICAgdW5zZXQoKTogdm9pZDtcblxuICAgIC8qKlxuICAgICAqIFByZXBhcmUgdGhlIE1hdHJpeENsaWVudCBmb3IgdXNlLCBpbmNsdWRpbmcgaW5pdGlhbGlzaW5nIHRoZSBzdG9yZSBhbmQgY3J5cHRvLCBidXQgZG8gbm90IHN0YXJ0IGl0LlxuICAgICAqL1xuICAgIGFzc2lnbihvcHRzPzogTWF0cml4Q2xpZW50UGVnQXNzaWduT3B0cyk6IFByb21pc2U8SVN0YXJ0Q2xpZW50T3B0cz47XG5cbiAgICAvKipcbiAgICAgKiBQcmVwYXJlIHRoZSBNYXRyaXhDbGllbnQgZm9yIHVzZSwgaW5jbHVkaW5nIGluaXRpYWxpc2luZyB0aGUgc3RvcmUgYW5kIGNyeXB0bywgYW5kIHN0YXJ0IGl0LlxuICAgICAqL1xuICAgIHN0YXJ0KG9wdHM/OiBNYXRyaXhDbGllbnRQZWdBc3NpZ25PcHRzKTogUHJvbWlzZTx2b2lkPjtcblxuICAgIC8qKlxuICAgICAqIElmIHdlJ3ZlIHJlZ2lzdGVyZWQgYSB1c2VyIElEIHdlIHNldCB0aGlzIHRvIHRoZSBJRCBvZiB0aGVcbiAgICAgKiB1c2VyIHdlJ3ZlIGp1c3QgcmVnaXN0ZXJlZC4gSWYgdGhleSB0aGVuIGdvICYgbG9nIGluLCB3ZVxuICAgICAqIGNhbiBzZW5kIHRoZW0gdG8gdGhlIHdlbGNvbWUgdXNlciAob2J2aW91c2x5IHRoaXMgZG9lc24ndFxuICAgICAqIGd1YXJhbnRlZSB0aGV5J2xsIGdldCBhIGNoYXQgd2l0aCB0aGUgd2VsY29tZSB1c2VyKS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSB1aWQgVGhlIHVzZXIgSUQgb2YgdGhlIHVzZXIgd2UndmUganVzdCByZWdpc3RlcmVkXG4gICAgICovXG4gICAgc2V0SnVzdFJlZ2lzdGVyZWRVc2VySWQodWlkOiBzdHJpbmcgfCBudWxsKTogdm9pZDtcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgY3VycmVudCB1c2VyIGhhcyBqdXN0IGJlZW4gcmVnaXN0ZXJlZCBieSB0aGlzXG4gICAgICogY2xpZW50IGFzIGRldGVybWluZWQgYnkgc2V0SnVzdFJlZ2lzdGVyZWRVc2VySWQoKVxuICAgICAqXG4gICAgICogQHJldHVybnMge2Jvb2x9IFRydWUgaWYgdXNlciBoYXMganVzdCBiZWVuIHJlZ2lzdGVyZWRcbiAgICAgKi9cbiAgICBjdXJyZW50VXNlcklzSnVzdFJlZ2lzdGVyZWQoKTogYm9vbGVhbjtcblxuICAgIC8qKlxuICAgICAqIElmIHRoZSBjdXJyZW50IHVzZXIgaGFzIGJlZW4gcmVnaXN0ZXJlZCBieSB0aGlzIGRldmljZSB0aGVuIHRoaXNcbiAgICAgKiByZXR1cm5zIGEgYm9vbGVhbiBvZiB3aGV0aGVyIGl0IHdhcyB3aXRoaW4gdGhlIGxhc3QgTiBob3VycyBnaXZlbi5cbiAgICAgKi9cbiAgICB1c2VyUmVnaXN0ZXJlZFdpdGhpbkxhc3RIb3Vycyhob3VyczogbnVtYmVyKTogYm9vbGVhbjtcblxuICAgIC8qKlxuICAgICAqIElmIHRoZSBjdXJyZW50IHVzZXIgaGFzIGJlZW4gcmVnaXN0ZXJlZCBieSB0aGlzIGRldmljZSB0aGVuIHRoaXNcbiAgICAgKiByZXR1cm5zIGEgYm9vbGVhbiBvZiB3aGV0aGVyIGl0IHdhcyBhZnRlciBhIGdpdmVuIHRpbWVzdGFtcC5cbiAgICAgKi9cbiAgICB1c2VyUmVnaXN0ZXJlZEFmdGVyKGRhdGU6IERhdGUpOiBib29sZWFuO1xuXG4gICAgLyoqXG4gICAgICogUmVwbGFjZSB0aGlzIE1hdHJpeENsaWVudFBlZydzIGNsaWVudCB3aXRoIGEgY2xpZW50IGluc3RhbmNlIHRoYXQgaGFzXG4gICAgICogaG9tZXNlcnZlciAvIGlkZW50aXR5IHNlcnZlciBVUkxzIGFuZCBhY3RpdmUgY3JlZGVudGlhbHNcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7SU1hdHJpeENsaWVudENyZWRzfSBjcmVkcyBUaGUgbmV3IGNyZWRlbnRpYWxzIHRvIHVzZS5cbiAgICAgKiBAcGFyYW0ge1Rva2VuUmVmcmVzaEZ1bmN0aW9ufSB0b2tlblJlZnJlc2hGdW5jdGlvbiBPUFRJT05BTCBmdW5jdGlvbiB1c2VkIGJ5IE1hdHJpeENsaWVudCB0byBhdHRlbXB0IHRva2VuIHJlZnJlc2hcbiAgICAgKiAgICAgICAgICBzZWUge0BsaW5rIElDcmVhdGVDbGllbnRPcHRzLnRva2VuUmVmcmVzaEZ1bmN0aW9ufVxuICAgICAqL1xuICAgIHJlcGxhY2VVc2luZ0NyZWRzKGNyZWRzOiBJTWF0cml4Q2xpZW50Q3JlZHMsIHRva2VuUmVmcmVzaEZ1bmN0aW9uPzogVG9rZW5SZWZyZXNoRnVuY3Rpb24pOiB2b2lkO1xufVxuXG4vKipcbiAqIFdyYXBwZXIgb2JqZWN0IGZvciBoYW5kbGluZyB0aGUganMtc2RrIE1hdHJpeCBDbGllbnQgb2JqZWN0IGluIHRoZSByZWFjdC1zZGtcbiAqIEhhbmRsZXMgdGhlIGNyZWF0aW9uL2luaXRpYWxpc2F0aW9uIG9mIGNsaWVudCBvYmplY3RzLlxuICogVGhpcyBtb2R1bGUgcHJvdmlkZXMgYSBzaW5nbGV0b24gaW5zdGFuY2Ugb2YgdGhpcyBjbGFzcyBzbyB0aGUgJ2N1cnJlbnQnXG4gKiBNYXRyaXggQ2xpZW50IG9iamVjdCBpcyBhdmFpbGFibGUgZWFzaWx5LlxuICovXG5jbGFzcyBNYXRyaXhDbGllbnRQZWdDbGFzcyBpbXBsZW1lbnRzIElNYXRyaXhDbGllbnRQZWcge1xuICAgIC8vIFRoZXNlIGFyZSB0aGUgZGVmYXVsdCBvcHRpb25zIHVzZWQgd2hlbiB3aGVuIHRoZVxuICAgIC8vIGNsaWVudCBpcyBzdGFydGVkIGluICdzdGFydCcuIFRoZXNlIGNhbiBiZSBhbHRlcmVkXG4gICAgLy8gYXQgYW55IHRpbWUgdXAgdG8gYWZ0ZXIgdGhlICd3aWxsX3N0YXJ0X2NsaWVudCdcbiAgICAvLyBldmVudCBpcyBmaW5pc2hlZCBwcm9jZXNzaW5nLlxuICAgIHB1YmxpYyBvcHRzOiBJU3RhcnRDbGllbnRPcHRzID0ge1xuICAgICAgICBpbml0aWFsU3luY0xpbWl0OiAyMCxcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBtYXRyaXhDbGllbnQ6IE1hdHJpeENsaWVudCB8IG51bGwgPSBudWxsO1xuICAgIHByaXZhdGUganVzdFJlZ2lzdGVyZWRVc2VySWQ6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuXG4gICAgcHVibGljIGdldCgpOiBNYXRyaXhDbGllbnQgfCBudWxsIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubWF0cml4Q2xpZW50O1xuICAgIH1cblxuICAgIHB1YmxpYyBzYWZlR2V0KCk6IE1hdHJpeENsaWVudCB7XG4gICAgICAgIGlmICghdGhpcy5tYXRyaXhDbGllbnQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBVc2VyRnJpZW5kbHlFcnJvcihcImVycm9yX3VzZXJfbm90X2xvZ2dlZF9pblwiKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5tYXRyaXhDbGllbnQ7XG4gICAgfVxuXG4gICAgcHVibGljIHVuc2V0KCk6IHZvaWQge1xuICAgICAgICB0aGlzLm1hdHJpeENsaWVudCA9IG51bGw7XG5cbiAgICAgICAgTWF0cml4QWN0aW9uQ3JlYXRvcnMuc3RvcCgpO1xuICAgIH1cblxuICAgIHB1YmxpYyBzZXRKdXN0UmVnaXN0ZXJlZFVzZXJJZCh1aWQ6IHN0cmluZyB8IG51bGwpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5qdXN0UmVnaXN0ZXJlZFVzZXJJZCA9IHVpZDtcbiAgICAgICAgaWYgKHVpZCkge1xuICAgICAgICAgICAgY29uc3QgcmVnaXN0cmF0aW9uVGltZSA9IERhdGUubm93KCkudG9TdHJpbmcoKTtcbiAgICAgICAgICAgIHdpbmRvdy5sb2NhbFN0b3JhZ2Uuc2V0SXRlbShcIm14X3JlZ2lzdHJhdGlvbl90aW1lXCIsIHJlZ2lzdHJhdGlvblRpbWUpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIGN1cnJlbnRVc2VySXNKdXN0UmVnaXN0ZXJlZCgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuICEhdGhpcy5tYXRyaXhDbGllbnQgJiYgdGhpcy5tYXRyaXhDbGllbnQuY3JlZGVudGlhbHMudXNlcklkID09PSB0aGlzLmp1c3RSZWdpc3RlcmVkVXNlcklkO1xuICAgIH1cblxuICAgIHB1YmxpYyB1c2VyUmVnaXN0ZXJlZFdpdGhpbkxhc3RIb3Vycyhob3VyczogbnVtYmVyKTogYm9vbGVhbiB7XG4gICAgICAgIGlmIChob3VycyA8PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3QgcmVnaXN0cmF0aW9uVGltZSA9IHBhcnNlSW50KHdpbmRvdy5sb2NhbFN0b3JhZ2UuZ2V0SXRlbShcIm14X3JlZ2lzdHJhdGlvbl90aW1lXCIpISwgMTApO1xuICAgICAgICAgICAgY29uc3QgZGlmZiA9IERhdGUubm93KCkgLSByZWdpc3RyYXRpb25UaW1lO1xuICAgICAgICAgICAgcmV0dXJuIGRpZmYgLyAzNmU1IDw9IGhvdXJzO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgdXNlclJlZ2lzdGVyZWRBZnRlcih0aW1lc3RhbXA6IERhdGUpOiBib29sZWFuIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHJlZ2lzdHJhdGlvblRpbWUgPSBwYXJzZUludCh3aW5kb3cubG9jYWxTdG9yYWdlLmdldEl0ZW0oXCJteF9yZWdpc3RyYXRpb25fdGltZVwiKSEsIDEwKTtcbiAgICAgICAgICAgIHJldHVybiB0aW1lc3RhbXAuZ2V0VGltZSgpIDw9IHJlZ2lzdHJhdGlvblRpbWU7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyByZXBsYWNlVXNpbmdDcmVkcyhjcmVkczogSU1hdHJpeENsaWVudENyZWRzLCB0b2tlblJlZnJlc2hGdW5jdGlvbj86IFRva2VuUmVmcmVzaEZ1bmN0aW9uKTogdm9pZCB7XG4gICAgICAgIHRoaXMuY3JlYXRlQ2xpZW50KGNyZWRzLCB0b2tlblJlZnJlc2hGdW5jdGlvbik7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvblVuZXhwZWN0ZWRTdG9yZUNsb3NlID0gYXN5bmMgKCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICBpZiAoIXRoaXMubWF0cml4Q2xpZW50KSByZXR1cm47XG4gICAgICAgIHRoaXMubWF0cml4Q2xpZW50LnN0b3BDbGllbnQoKTsgLy8gc3RvcCB0aGUgY2xpZW50IGFzIHRoZSBkYXRhYmFzZSBoYXMgZmFpbGVkXG4gICAgICAgIHRoaXMubWF0cml4Q2xpZW50LnN0b3JlLmRlc3Ryb3koKTtcblxuICAgICAgICBpZiAoIXRoaXMubWF0cml4Q2xpZW50LmlzR3Vlc3QoKSkge1xuICAgICAgICAgICAgLy8gSWYgdGhlIHVzZXIgaXMgbm90IGEgZ3Vlc3QgdGhlbiBwcm9tcHQgdGhlbSB0byByZWxvYWQgcmF0aGVyIHRoYW4gZG9pbmcgaXQgZm9yIHRoZW1cbiAgICAgICAgICAgIC8vIEZvciBndWVzdHMgdGhpcyBpcyBsaWtlbHkgdG8gaGFwcGVuIGR1cmluZyBlLW1haWwgdmVyaWZpY2F0aW9uIGFzIHBhcnQgb2YgcmVnaXN0cmF0aW9uXG5cbiAgICAgICAgICAgIGNvbnN0IGJyYW5kID0gU2RrQ29uZmlnLmdldCgpLmJyYW5kO1xuICAgICAgICAgICAgY29uc3QgcGxhdGZvcm0gPSBQbGF0Zm9ybVBlZy5nZXQoKT8uZ2V0SHVtYW5SZWFkYWJsZU5hbWUoKTtcblxuICAgICAgICAgICAgLy8gRGV0ZXJtaW5lIHRoZSBkZXNjcmlwdGlvbiBiYXNlZCBvbiB0aGUgcGxhdGZvcm1cbiAgICAgICAgICAgIGNvbnN0IGRlc2NyaXB0aW9uID1cbiAgICAgICAgICAgICAgICBwbGF0Zm9ybSA9PT0gXCJXZWIgUGxhdGZvcm1cIlxuICAgICAgICAgICAgICAgICAgICA/IF90KFwiZXJyb3JfZGF0YWJhc2VfY2xvc2VkX2Rlc2NyaXB0aW9ufGZvcl93ZWJcIiwgeyBicmFuZCB9KVxuICAgICAgICAgICAgICAgICAgICA6IF90KFwiZXJyb3JfZGF0YWJhc2VfY2xvc2VkX2Rlc2NyaXB0aW9ufGZvcl9kZXNrdG9wXCIpO1xuXG4gICAgICAgICAgICBjb25zdCBbcmVsb2FkXSA9IGF3YWl0IE1vZGFsLmNyZWF0ZURpYWxvZyhFcnJvckRpYWxvZywge1xuICAgICAgICAgICAgICAgIHRpdGxlOiBfdChcImVycm9yX2RhdGFiYXNlX2Nsb3NlZF90aXRsZVwiLCB7IGJyYW5kIH0pLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uLFxuICAgICAgICAgICAgICAgIGJ1dHRvbjogX3QoXCJhY3Rpb258cmVsb2FkXCIpLFxuICAgICAgICAgICAgfSkuZmluaXNoZWQ7XG5cbiAgICAgICAgICAgIGlmICghcmVsb2FkKSByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBQbGF0Zm9ybVBlZy5nZXQoKT8ucmVsb2FkKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEltcGxlbWVudGF0aW9uIG9mIHtAbGluayBJTWF0cml4Q2xpZW50UGVnLmFzc2lnbn0uXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIGFzc2lnbihhc3NpZ25PcHRzOiBNYXRyaXhDbGllbnRQZWdBc3NpZ25PcHRzID0ge30pOiBQcm9taXNlPElTdGFydENsaWVudE9wdHM+IHtcbiAgICAgICAgaWYgKCF0aGlzLm1hdHJpeENsaWVudCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiY3JlYXRlQ2xpZW50IG11c3QgYmUgY2FsbGVkIGZpcnN0XCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgZm9yIChjb25zdCBkYlR5cGUgb2YgW1wiaW5kZXhlZGRiXCIsIFwibWVtb3J5XCJdKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHByb21pc2UgPSB0aGlzLm1hdHJpeENsaWVudC5zdG9yZS5zdGFydHVwKCk7XG4gICAgICAgICAgICAgICAgbG9nZ2VyLmxvZyhcIk1hdHJpeENsaWVudFBlZzogd2FpdGluZyBmb3IgTWF0cml4Q2xpZW50IHN0b3JlIHRvIGluaXRpYWxpc2VcIik7XG4gICAgICAgICAgICAgICAgYXdhaXQgcHJvbWlzZTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgIGlmIChkYlR5cGUgPT09IFwiaW5kZXhlZGRiXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgbG9nZ2VyLmVycm9yKFwiRXJyb3Igc3RhcnRpbmcgbWF0cml4Y2xpZW50IHN0b3JlIC0gZmFsbGluZyBiYWNrIHRvIG1lbW9yeSBzdG9yZVwiLCBlcnIpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLm1hdHJpeENsaWVudC5zdG9yZSA9IG5ldyBNZW1vcnlTdG9yZSh7XG4gICAgICAgICAgICAgICAgICAgICAgICBsb2NhbFN0b3JhZ2U6IGxvY2FsU3RvcmFnZSxcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgbG9nZ2VyLmVycm9yKFwiRmFpbGVkIHRvIHN0YXJ0IG1lbW9yeSBzdG9yZSFcIiwgZXJyKTtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLm1hdHJpeENsaWVudC5zdG9yZS5vbj8uKFwiY2xvc2VkXCIsIHRoaXMub25VbmV4cGVjdGVkU3RvcmVDbG9zZSk7XG5cbiAgICAgICAgLy8gdHJ5IHRvIGluaXRpYWxpc2UgZTJlIG9uIHRoZSBuZXcgY2xpZW50XG4gICAgICAgIGlmICghU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZShcImxvd0JhbmR3aWR0aFwiKSkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5pbml0Q2xpZW50Q3J5cHRvKGFzc2lnbk9wdHMucnVzdENyeXB0b1N0b3JlS2V5LCBhc3NpZ25PcHRzLnJ1c3RDcnlwdG9TdG9yZVBhc3N3b3JkKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IG9wdHMgPSB1dGlscy5kZWVwQ29weSh0aGlzLm9wdHMpO1xuICAgICAgICAvLyB0aGUgcmVhY3Qgc2RrIGRvZXNuJ3Qgd29yayB3aXRob3V0IHRoaXMsIHNvIGRvbid0IGFsbG93XG4gICAgICAgIG9wdHMucGVuZGluZ0V2ZW50T3JkZXJpbmcgPSBQZW5kaW5nRXZlbnRPcmRlcmluZy5EZXRhY2hlZDtcbiAgICAgICAgb3B0cy5sYXp5TG9hZE1lbWJlcnMgPSB0cnVlO1xuICAgICAgICBvcHRzLmNsaWVudFdlbGxLbm93blBvbGxQZXJpb2QgPSAyICogNjAgKiA2MDsgLy8gMiBob3Vyc1xuICAgICAgICBvcHRzLnRocmVhZFN1cHBvcnQgPSB0cnVlO1xuXG4gICAgICAgIGlmIChTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwiZmVhdHVyZV9zbGlkaW5nX3N5bmNcIikpIHtcbiAgICAgICAgICAgIG9wdHMuc2xpZGluZ1N5bmMgPSBhd2FpdCBTbGlkaW5nU3luY01hbmFnZXIuaW5zdGFuY2Uuc2V0dXAodGhpcy5tYXRyaXhDbGllbnQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgU2xpZGluZ1N5bmNNYW5hZ2VyLmluc3RhbmNlLmNoZWNrU3VwcG9ydCh0aGlzLm1hdHJpeENsaWVudCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBDb25uZWN0IHRoZSBtYXRyaXggY2xpZW50IHRvIHRoZSBkaXNwYXRjaGVyIGFuZCBzZXR0aW5nIGhhbmRsZXJzXG4gICAgICAgIE1hdHJpeEFjdGlvbkNyZWF0b3JzLnN0YXJ0KHRoaXMubWF0cml4Q2xpZW50KTtcbiAgICAgICAgTWF0cml4Q2xpZW50QmFja2VkU2V0dGluZ3NIYW5kbGVyLm1hdHJpeENsaWVudCA9IHRoaXMubWF0cml4Q2xpZW50O1xuICAgICAgICBNYXRyaXhDbGllbnRCYWNrZWRDb250cm9sbGVyLm1hdHJpeENsaWVudCA9IHRoaXMubWF0cml4Q2xpZW50O1xuXG4gICAgICAgIHJldHVybiBvcHRzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEF0dGVtcHQgdG8gaW5pdGlhbGl6ZSB0aGUgY3J5cHRvIGxheWVyIG9uIGEgbmV3bHktY3JlYXRlZCBNYXRyaXhDbGllbnRcbiAgICAgKlxuICAgICAqIEBwYXJhbSBydXN0Q3J5cHRvU3RvcmVLZXkgLSBBIGtleSB3aXRoIHdoaWNoIHRvIGVuY3J5cHQgdGhlIHJ1c3QgY3J5cHRvIGluZGV4ZWRkYi5cbiAgICAgKiAgIElmIHByb3ZpZGVkLCBpdCBtdXN0IGJlIGV4YWN0bHkgMzIgYnl0ZXMgb2YgZGF0YS4gSWYgYm90aCB0aGlzIGFuZCBgcnVzdENyeXB0b1N0b3JlUGFzc3dvcmRgIGFyZVxuICAgICAqICAgdW5kZWZpbmVkLCB0aGUgc3RvcmUgd2lsbCBiZSB1bmVuY3J5cHRlZC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBydXN0Q3J5cHRvU3RvcmVQYXNzd29yZCAtIEFuIGFsdGVybmF0aXZlIHRvIGBydXN0Q3J5cHRvU3RvcmVLZXlgLiBJZ25vcmVkIGlmIGBydXN0Q3J5cHRvU3RvcmVLZXlgIGlzIHNldC5cbiAgICAgKiAgICBBIHBhc3N3b3JkIHdoaWNoIHdpbGwgYmUgdXNlZCB0byBkZXJpdmUgYSBrZXkgdG8gZW5jcnlwdCB0aGUgc3RvcmUgd2l0aC4gRGVyaXZpbmcgYSBrZXkgZnJvbSBhIHBhc3N3b3JkIGlzXG4gICAgICogICAgKGRlbGliZXJhdGVseSkgYSBzbG93IG9wZXJhdGlvbiwgc28gcHJlZmVyIHRvIHBhc3MgYSBgcnVzdENyeXB0b1N0b3JlS2V5YCBkaXJlY3RseSB3aGVyZSBwb3NzaWJsZS5cbiAgICAgKi9cbiAgICBwcml2YXRlIGFzeW5jIGluaXRDbGllbnRDcnlwdG8ocnVzdENyeXB0b1N0b3JlS2V5PzogVWludDhBcnJheSwgcnVzdENyeXB0b1N0b3JlUGFzc3dvcmQ/OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKCF0aGlzLm1hdHJpeENsaWVudCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiY3JlYXRlQ2xpZW50IG11c3QgYmUgY2FsbGVkIGZpcnN0XCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFydXN0Q3J5cHRvU3RvcmVLZXkgJiYgIXJ1c3RDcnlwdG9TdG9yZVBhc3N3b3JkKSB7XG4gICAgICAgICAgICBsb2dnZXIuZXJyb3IoXCJXYXJuaW5nISBOb3QgdXNpbmcgYW4gZW5jcnlwdGlvbiBrZXkgZm9yIHJ1c3QgY3J5cHRvIHN0b3JlLlwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFJlY29yZCB0aGUgZmFjdCB0aGF0IHdlIHVzZWQgdGhlIFJ1c3QgY3J5cHRvIHN0YWNrIHdpdGggdGhpcyBjbGllbnQuIFRoaXMganVzdCBndWFyZHMgYWdhaW5zdCBwZW9wbGVcbiAgICAgICAgLy8gcm9sbGluZyBiYWNrIHRvIHZlcnNpb25zIG9mIEVXIHRoYXQgZGlkIG5vdCBkZWZhdWx0IHRvIFJ1c3QgY3J5cHRvICh3aGljaCB3b3VsZCBsZWFkIHRvIGFuIGVycm9yLCBzaW5jZVxuICAgICAgICAvLyB3ZSBjYW5ub3QgbWlncmF0ZSBmcm9tIFJ1c3QgdG8gTGVnYWN5IGNyeXB0bykuXG4gICAgICAgIGF3YWl0IFNldHRpbmdzU3RvcmUuc2V0VmFsdWUoRmVhdHVyZXMuUnVzdENyeXB0bywgbnVsbCwgU2V0dGluZ0xldmVsLkRFVklDRSwgdHJ1ZSk7XG5cbiAgICAgICAgYXdhaXQgdGhpcy5tYXRyaXhDbGllbnQuaW5pdFJ1c3RDcnlwdG8oe1xuICAgICAgICAgICAgc3RvcmFnZUtleTogcnVzdENyeXB0b1N0b3JlS2V5LFxuICAgICAgICAgICAgc3RvcmFnZVBhc3N3b3JkOiBydXN0Q3J5cHRvU3RvcmVQYXNzd29yZCxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgU3RvcmFnZU1hbmFnZXIuc2V0Q3J5cHRvSW5pdGlhbGlzZWQodHJ1ZSk7XG5cbiAgICAgICAgc2V0RGV2aWNlSXNvbGF0aW9uTW9kZSh0aGlzLm1hdHJpeENsaWVudCwgU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZShcImZlYXR1cmVfZXhjbHVkZV9pbnNlY3VyZV9kZXZpY2VzXCIpKTtcblxuICAgICAgICAvLyBUT0RPOiBkZXZpY2UgZGVoeWRyYXRpb24gYW5kIHdoYXRoYXZleW91XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBJbXBsZW1lbnRhdGlvbiBvZiB7QGxpbmsgSU1hdHJpeENsaWVudFBlZy5zdGFydH0uXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIHN0YXJ0KGFzc2lnbk9wdHM/OiBNYXRyaXhDbGllbnRQZWdBc3NpZ25PcHRzKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IG9wdHMgPSBhd2FpdCB0aGlzLmFzc2lnbihhc3NpZ25PcHRzKTtcblxuICAgICAgICBsb2dnZXIubG9nKGBNYXRyaXhDbGllbnRQZWc6IHJlYWxseSBzdGFydGluZyBNYXRyaXhDbGllbnRgKTtcbiAgICAgICAgYXdhaXQgdGhpcy5tYXRyaXhDbGllbnQhLnN0YXJ0Q2xpZW50KG9wdHMpO1xuICAgICAgICBsb2dnZXIubG9nKGBNYXRyaXhDbGllbnRQZWc6IE1hdHJpeENsaWVudCBzdGFydGVkYCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBuYW1lc1RvUm9vbU5hbWUobmFtZXM6IHN0cmluZ1tdLCBjb3VudDogbnVtYmVyKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICAgICAgY29uc3QgY291bnRXaXRob3V0TWUgPSBjb3VudCAtIDE7XG4gICAgICAgIGlmICghbmFtZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gX3QoXCJlbXB0eV9yb29tXCIpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChuYW1lcy5sZW5ndGggPT09IDEgJiYgY291bnRXaXRob3V0TWUgPD0gMSkge1xuICAgICAgICAgICAgcmV0dXJuIG5hbWVzWzBdO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBtZW1iZXJOYW1lc1RvUm9vbU5hbWUobmFtZXM6IHN0cmluZ1tdLCBjb3VudDogbnVtYmVyKTogc3RyaW5nIHtcbiAgICAgICAgY29uc3QgbmFtZSA9IHRoaXMubmFtZXNUb1Jvb21OYW1lKG5hbWVzLCBjb3VudCk7XG4gICAgICAgIGlmIChuYW1lKSByZXR1cm4gbmFtZTtcblxuICAgICAgICBpZiAobmFtZXMubGVuZ3RoID09PSAyICYmIGNvdW50ID09PSAyKSB7XG4gICAgICAgICAgICByZXR1cm4gZm9ybWF0TGlzdChuYW1lcyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZvcm1hdExpc3QobmFtZXMsIDEpO1xuICAgIH1cblxuICAgIHByaXZhdGUgaW52aXRlZU5hbWVzVG9Sb29tTmFtZShuYW1lczogc3RyaW5nW10sIGNvdW50OiBudW1iZXIpOiBzdHJpbmcge1xuICAgICAgICBjb25zdCBuYW1lID0gdGhpcy5uYW1lc1RvUm9vbU5hbWUobmFtZXMsIGNvdW50KTtcbiAgICAgICAgaWYgKG5hbWUpIHJldHVybiBuYW1lO1xuXG4gICAgICAgIGlmIChuYW1lcy5sZW5ndGggPT09IDIgJiYgY291bnQgPT09IDIpIHtcbiAgICAgICAgICAgIHJldHVybiBfdChcImludml0aW5nX3VzZXIxX2FuZF91c2VyMlwiLCB7XG4gICAgICAgICAgICAgICAgdXNlcjE6IG5hbWVzWzBdLFxuICAgICAgICAgICAgICAgIHVzZXIyOiBuYW1lc1sxXSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBfdChcImludml0aW5nX3VzZXJfYW5kX25fb3RoZXJzXCIsIHtcbiAgICAgICAgICAgIHVzZXI6IG5hbWVzWzBdLFxuICAgICAgICAgICAgY291bnQ6IGNvdW50IC0gMSxcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBjcmVhdGVDbGllbnQoY3JlZHM6IElNYXRyaXhDbGllbnRDcmVkcywgdG9rZW5SZWZyZXNoRnVuY3Rpb24/OiBUb2tlblJlZnJlc2hGdW5jdGlvbik6IHZvaWQge1xuICAgICAgICBjb25zdCBvcHRzOiBJQ3JlYXRlQ2xpZW50T3B0cyA9IHtcbiAgICAgICAgICAgIGJhc2VVcmw6IGNyZWRzLmhvbWVzZXJ2ZXJVcmwsXG4gICAgICAgICAgICBpZEJhc2VVcmw6IGNyZWRzLmlkZW50aXR5U2VydmVyVXJsLFxuICAgICAgICAgICAgYWNjZXNzVG9rZW46IGNyZWRzLmFjY2Vzc1Rva2VuLFxuICAgICAgICAgICAgcmVmcmVzaFRva2VuOiBjcmVkcy5yZWZyZXNoVG9rZW4sXG4gICAgICAgICAgICB0b2tlblJlZnJlc2hGdW5jdGlvbixcbiAgICAgICAgICAgIHVzZXJJZDogY3JlZHMudXNlcklkLFxuICAgICAgICAgICAgZGV2aWNlSWQ6IGNyZWRzLmRldmljZUlkLFxuICAgICAgICAgICAgcGlja2xlS2V5OiBjcmVkcy5waWNrbGVLZXksXG4gICAgICAgICAgICB0aW1lbGluZVN1cHBvcnQ6IHRydWUsXG4gICAgICAgICAgICBmb3JjZVRVUk46ICFTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwid2ViUnRjQWxsb3dQZWVyVG9QZWVyXCIpLFxuICAgICAgICAgICAgZmFsbGJhY2tJQ0VTZXJ2ZXJBbGxvd2VkOiAhIVNldHRpbmdzU3RvcmUuZ2V0VmFsdWUoXCJmYWxsYmFja0lDRVNlcnZlckFsbG93ZWRcIiksXG4gICAgICAgICAgICAvLyBHYXRoZXIgdXAgdG8gMjAgSUNFIGNhbmRpZGF0ZXMgd2hlbiBhIGNhbGwgYXJyaXZlczogdGhpcyBzaG91bGQgYmUgbW9yZSB0aGFuIHdlJ2RcbiAgICAgICAgICAgIC8vIGV2ZXIgbm9ybWFsbHkgbmVlZCwgc28gZWZmZWN0aXZlbHkgdGhpcyBzaG91bGQgbWFrZSBhbGwgdGhlIGdhdGhlcmluZyBoYXBwZW4gd2hlblxuICAgICAgICAgICAgLy8gdGhlIGNhbGwgYXJyaXZlcy5cbiAgICAgICAgICAgIGljZUNhbmRpZGF0ZVBvb2xTaXplOiAyMCxcbiAgICAgICAgICAgIHZlcmlmaWNhdGlvbk1ldGhvZHM6IFtcbiAgICAgICAgICAgICAgICBWZXJpZmljYXRpb25NZXRob2QuU2FzLFxuICAgICAgICAgICAgICAgIFZlcmlmaWNhdGlvbk1ldGhvZC5TaG93UXJDb2RlLFxuICAgICAgICAgICAgICAgIFZlcmlmaWNhdGlvbk1ldGhvZC5SZWNpcHJvY2F0ZSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBpZGVudGl0eVNlcnZlcjogbmV3IElkZW50aXR5QXV0aENsaWVudCgpLFxuICAgICAgICAgICAgLy8gVGhlc2UgYXJlIGFsd2F5cyBpbnN0YWxsZWQgcmVnYXJkbGVzcyBvZiB0aGUgbGFicyBmbGFnIHNvIHRoYXQgY3Jvc3Mtc2lnbmluZyBmZWF0dXJlc1xuICAgICAgICAgICAgLy8gY2FuIHRvZ2dsZSBvbiB3aXRob3V0IHJlbG9hZGluZyBhbmQgYWxzbyBiZSBhY2Nlc3NlZCBpbW1lZGlhdGVseSBhZnRlciBsb2dpbi5cbiAgICAgICAgICAgIGNyeXB0b0NhbGxiYWNrczogeyAuLi5jcm9zc1NpZ25pbmdDYWxsYmFja3MgfSxcbiAgICAgICAgICAgIHJvb21OYW1lR2VuZXJhdG9yOiAoXzogc3RyaW5nLCBzdGF0ZTogUm9vbU5hbWVTdGF0ZSkgPT4ge1xuICAgICAgICAgICAgICAgIHN3aXRjaCAoc3RhdGUudHlwZSkge1xuICAgICAgICAgICAgICAgICAgICBjYXNlIFJvb21OYW1lVHlwZS5HZW5lcmF0ZWQ6XG4gICAgICAgICAgICAgICAgICAgICAgICBzd2l0Y2ggKHN0YXRlLnN1YnR5cGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIFwiSW52aXRpbmdcIjpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuaW52aXRlZU5hbWVzVG9Sb29tTmFtZShzdGF0ZS5uYW1lcywgc3RhdGUuY291bnQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLm1lbWJlck5hbWVzVG9Sb29tTmFtZShzdGF0ZS5uYW1lcywgc3RhdGUuY291bnQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBjYXNlIFJvb21OYW1lVHlwZS5FbXB0eVJvb206XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoc3RhdGUub2xkTmFtZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBfdChcImVtcHR5X3Jvb21fd2FzX25hbWVcIiwge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGROYW1lOiBzdGF0ZS5vbGROYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gX3QoXCJlbXB0eV9yb29tXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLm1hdHJpeENsaWVudCA9IGNyZWF0ZU1hdHJpeENsaWVudChvcHRzKTtcbiAgICAgICAgdGhpcy5tYXRyaXhDbGllbnQuc2V0R3Vlc3QoQm9vbGVhbihjcmVkcy5ndWVzdCkpO1xuXG4gICAgICAgIGNvbnN0IG5vdGlmVGltZWxpbmVTZXQgPSBuZXcgRXZlbnRUaW1lbGluZVNldCh1bmRlZmluZWQsIHtcbiAgICAgICAgICAgIHRpbWVsaW5lU3VwcG9ydDogdHJ1ZSxcbiAgICAgICAgICAgIHBlbmRpbmdFdmVudHM6IGZhbHNlLFxuICAgICAgICB9KTtcbiAgICAgICAgLy8gWFhYOiB3aGF0IGlzIG91ciBpbml0aWFsIHBhZ2luYXRpb24gdG9rZW4/ISBpdCBzb21laG93IG5lZWRzIHRvIGJlIHN5bmNocm9uaXNlZCB3aXRoIC9zeW5jLlxuICAgICAgICBub3RpZlRpbWVsaW5lU2V0LmdldExpdmVUaW1lbGluZSgpLnNldFBhZ2luYXRpb25Ub2tlbihcIlwiLCBFdmVudFRpbWVsaW5lLkJBQ0tXQVJEUyk7XG4gICAgICAgIHRoaXMubWF0cml4Q2xpZW50LnNldE5vdGlmVGltZWxpbmVTZXQobm90aWZUaW1lbGluZVNldCk7XG4gICAgfVxufVxuXG4vKipcbiAqIE5vdGU6IFlvdSBzaG91bGQgYmUgdXNpbmcgYSBSZWFjdCBjb250ZXh0IHdpdGggYWNjZXNzIHRvIGEgY2xpZW50IHJhdGhlciB0aGFuXG4gKiB1c2luZyB0aGlzLCBhcyBpbiBhIG11bHRpLWFjY291bnQgd29ybGQgdGhpcyB3aWxsIG5vdCBleGlzdCFcbiAqL1xuZXhwb3J0IGNvbnN0IE1hdHJpeENsaWVudFBlZzogSU1hdHJpeENsaWVudFBlZyA9IG5ldyBNYXRyaXhDbGllbnRQZWdDbGFzcygpO1xuXG5pZiAoIXdpbmRvdy5teE1hdHJpeENsaWVudFBlZykge1xuICAgIHdpbmRvdy5teE1hdHJpeENsaWVudFBlZyA9IE1hdHJpeENsaWVudFBlZztcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFXQSxJQUFBQSxPQUFBLEdBQUFDLE9BQUE7QUFZQSxJQUFBQyxNQUFBLEdBQUFELE9BQUE7QUFDQSxJQUFBRSxLQUFBLEdBQUFDLHVCQUFBLENBQUFILE9BQUE7QUFDQSxJQUFBSSxPQUFBLEdBQUFKLE9BQUE7QUFFQSxJQUFBSyxtQkFBQSxHQUFBQyxzQkFBQSxDQUFBTixPQUFBO0FBQ0EsSUFBQU8sY0FBQSxHQUFBRCxzQkFBQSxDQUFBTixPQUFBO0FBQ0EsSUFBQVEscUJBQUEsR0FBQUYsc0JBQUEsQ0FBQU4sT0FBQTtBQUNBLElBQUFTLE1BQUEsR0FBQUgsc0JBQUEsQ0FBQU4sT0FBQTtBQUNBLElBQUFVLGtDQUFBLEdBQUFKLHNCQUFBLENBQUFOLE9BQUE7QUFDQSxJQUFBVyxjQUFBLEdBQUFSLHVCQUFBLENBQUFILE9BQUE7QUFDQSxJQUFBWSxtQkFBQSxHQUFBTixzQkFBQSxDQUFBTixPQUFBO0FBQ0EsSUFBQWEsZ0JBQUEsR0FBQWIsT0FBQTtBQUNBLElBQUFjLG1CQUFBLEdBQUFkLE9BQUE7QUFDQSxJQUFBZSxnQkFBQSxHQUFBZixPQUFBO0FBQ0EsSUFBQWdCLGFBQUEsR0FBQWhCLE9BQUE7QUFDQSxJQUFBaUIsNkJBQUEsR0FBQVgsc0JBQUEsQ0FBQU4sT0FBQTtBQUNBLElBQUFrQixZQUFBLEdBQUFaLHNCQUFBLENBQUFOLE9BQUE7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