matrix-react-sdk
Version:
SDK for matrix.org using React
329 lines (317 loc) • 58.6 kB
JavaScript
"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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