matrix-react-sdk
Version:
SDK for matrix.org using React
397 lines (365 loc) • 48 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.UpdateCheckStatus = exports.SSO_ID_SERVER_URL_KEY = exports.SSO_IDP_ID_KEY = exports.SSO_HOMESERVER_URL_KEY = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _matrix = require("matrix-js-sdk/src/matrix");
var _logger = require("matrix-js-sdk/src/logger");
var _dispatcher = _interopRequireDefault(require("./dispatcher/dispatcher"));
var _actions = require("./dispatcher/actions");
var _UpdateToast = require("./toasts/UpdateToast");
var _MatrixClientPeg = require("./MatrixClientPeg");
var _StorageAccess = require("./utils/StorageAccess");
var _SdkConfig = _interopRequireDefault(require("./SdkConfig"));
var _pickling = require("./utils/tokens/pickling");
/*
Copyright 2024 New Vector Ltd.
Copyright 2020 The Matrix.org Foundation C.I.C.
Copyright 2018 New Vector Ltd
Copyright 2016 Aviral Dasgupta
Copyright 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.
*/
const SSO_HOMESERVER_URL_KEY = exports.SSO_HOMESERVER_URL_KEY = "mx_sso_hs_url";
const SSO_ID_SERVER_URL_KEY = exports.SSO_ID_SERVER_URL_KEY = "mx_sso_is_url";
const SSO_IDP_ID_KEY = exports.SSO_IDP_ID_KEY = "mx_sso_idp_id";
let UpdateCheckStatus = exports.UpdateCheckStatus = /*#__PURE__*/function (UpdateCheckStatus) {
UpdateCheckStatus["Checking"] = "CHECKING";
UpdateCheckStatus["Error"] = "ERROR";
UpdateCheckStatus["NotAvailable"] = "NOTAVAILABLE";
UpdateCheckStatus["Downloading"] = "DOWNLOADING";
UpdateCheckStatus["Ready"] = "READY";
return UpdateCheckStatus;
}({});
const UPDATE_DEFER_KEY = "mx_defer_update";
/**
* Base class for classes that provide platform-specific functionality
* eg. Setting an application badge or displaying notifications
*
* Instances of this class are provided by the application.
*/
class BasePlatform {
constructor() {
(0, _defineProperty2.default)(this, "notificationCount", 0);
(0, _defineProperty2.default)(this, "errorDidOccur", false);
(0, _defineProperty2.default)(this, "onAction", payload => {
switch (payload.action) {
case "on_client_not_viable":
case _actions.Action.OnLoggedOut:
this.setNotificationCount(0);
break;
}
});
_dispatcher.default.register(this.onAction);
this.startUpdateCheck = this.startUpdateCheck.bind(this);
}
// Used primarily for Analytics
setNotificationCount(count) {
this.notificationCount = count;
}
setErrorStatus(errorDidOccur) {
this.errorDidOccur = errorDidOccur;
}
/**
* Whether we can call checkForUpdate on this platform build
*/
async canSelfUpdate() {
return false;
}
startUpdateCheck() {
(0, _UpdateToast.hideToast)();
localStorage.removeItem(UPDATE_DEFER_KEY);
_dispatcher.default.dispatch({
action: _actions.Action.CheckUpdates,
status: UpdateCheckStatus.Checking
});
}
/**
* Update the currently running app to the latest available version
* and replace this instance of the app with the new version.
*/
installUpdate() {}
/**
* Check if the version update has been deferred and that deferment is still in effect
* @param newVersion the version string to check
*/
shouldShowUpdate(newVersion) {
// If the user registered on this client in the last 24 hours then do not show them the update toast
if (_MatrixClientPeg.MatrixClientPeg.userRegisteredWithinLastHours(24)) return false;
try {
const [version, deferUntil] = JSON.parse(localStorage.getItem(UPDATE_DEFER_KEY));
return newVersion !== version || Date.now() > deferUntil;
} catch (e) {
return true;
}
}
/**
* Ignore the pending update and don't prompt about this version
* until the next morning (8am).
*/
deferUpdate(newVersion) {
const date = new Date(Date.now() + 24 * 60 * 60 * 1000);
date.setHours(8, 0, 0, 0); // set to next 8am
localStorage.setItem(UPDATE_DEFER_KEY, JSON.stringify([newVersion, date.getTime()]));
(0, _UpdateToast.hideToast)();
}
/**
* Return true if platform supports multi-language
* spell-checking, otherwise false.
*/
supportsSpellCheckSettings() {
return false;
}
/**
* Returns true if platform allows overriding native context menus
*/
allowOverridingNativeContextMenus() {
return false;
}
/**
* Returns true if the platform supports displaying
* notifications, otherwise false.
* @returns {boolean} whether the platform supports displaying notifications
*/
supportsNotifications() {
return false;
}
/**
* Returns true if the application currently has permission
* to display notifications. Otherwise false.
* @returns {boolean} whether the application has permission to display notifications
*/
maySendNotifications() {
return false;
}
/**
* Requests permission to send notifications. Returns
* a promise that is resolved when the user has responded
* to the request. The promise has a single string argument
* that is 'granted' if the user allowed the request or
* 'denied' otherwise.
*/
displayNotification(title, msg, avatarUrl, room, ev) {
const notifBody = {
body: msg,
silent: true // we play our own sounds
};
if (avatarUrl) notifBody["icon"] = avatarUrl;
const notification = new window.Notification(title, notifBody);
notification.onclick = () => {
const payload = {
action: _actions.Action.ViewRoom,
room_id: room.roomId,
metricsTrigger: "Notification"
};
if (ev?.getThread()) {
payload.event_id = ev.getId();
}
_dispatcher.default.dispatch(payload);
window.focus();
};
return notification;
}
loudNotification(ev, room) {}
clearNotification(notif) {
// Some browsers don't support this, e.g Safari on iOS
// https://developer.mozilla.org/en-US/docs/Web/API/Notification/close
if (notif.close) {
notif.close();
}
}
/**
* Returns true if the platform requires URL previews in tooltips, otherwise false.
* @returns {boolean} whether the platform requires URL previews in tooltips
*/
needsUrlTooltips() {
return false;
}
/**
* Returns a promise that resolves to a string representing the current version of the application.
*/
/**
* Restarts the application, without necessarily reloading
* any application code
*/
supportsSetting(settingName) {
return false;
}
async getSettingValue(settingName) {
return undefined;
}
setSettingValue(settingName, value) {
throw new Error("Unimplemented");
}
/**
* Get our platform specific EventIndexManager.
*
* @return {BaseEventIndexManager} The EventIndex manager for our platform,
* can be null if the platform doesn't support event indexing.
*/
getEventIndexingManager() {
return null;
}
setLanguage(preferredLangs) {}
setSpellCheckEnabled(enabled) {}
async getSpellCheckEnabled() {
return false;
}
setSpellCheckLanguages(preferredLangs) {}
getSpellCheckLanguages() {
return null;
}
async getDesktopCapturerSources(options) {
return [];
}
supportsDesktopCapturer() {
return false;
}
supportsJitsiScreensharing() {
return true;
}
overrideBrowserShortcuts() {
return false;
}
navigateForwardBack(back) {}
getAvailableSpellCheckLanguages() {
return null;
}
/**
* The URL to return to after a successful SSO authentication
* @param fragmentAfterLogin optional fragment for specific view to return to
*/
getSSOCallbackUrl(fragmentAfterLogin = "") {
const url = new URL(window.location.href);
url.hash = fragmentAfterLogin;
return url;
}
/**
* Begin Single Sign On flows.
* @param {MatrixClient} mxClient the matrix client using which we should start the flow
* @param {"sso"|"cas"} loginType the type of SSO it is, CAS/SSO.
* @param {string} fragmentAfterLogin the hash to pass to the app during sso callback.
* @param {SSOAction} action the SSO flow to indicate to the IdP, optional.
* @param {string} idpId The ID of the Identity Provider being targeted, optional.
*/
startSingleSignOn(mxClient, loginType, fragmentAfterLogin, idpId, action) {
// persist hs url and is url for when the user is returned to the app with the login token
localStorage.setItem(SSO_HOMESERVER_URL_KEY, mxClient.getHomeserverUrl());
if (mxClient.getIdentityServerUrl()) {
localStorage.setItem(SSO_ID_SERVER_URL_KEY, mxClient.getIdentityServerUrl());
}
if (idpId) {
localStorage.setItem(SSO_IDP_ID_KEY, idpId);
}
const callbackUrl = this.getSSOCallbackUrl(fragmentAfterLogin);
window.location.href = mxClient.getSsoLoginUrl(callbackUrl.toString(), loginType, idpId, action); // redirect to SSO
}
/**
* Get a previously stored pickle key. The pickle key is used for
* encrypting libolm objects and react-sdk-crypto data.
* @param {string} userId the user ID for the user that the pickle key is for.
* @param {string} deviceId the device ID that the pickle key is for.
* @returns {string|null} the previously stored pickle key, or null if no
* pickle key has been stored.
*/
async getPickleKey(userId, deviceId) {
let data;
try {
data = await (0, _StorageAccess.idbLoad)("pickleKey", [userId, deviceId]);
} catch (e) {
_logger.logger.error("idbLoad for pickleKey failed", e);
}
return (await (0, _pickling.buildAndEncodePickleKey)(data, userId, deviceId)) ?? null;
}
/**
* Create and store a pickle key for encrypting libolm objects.
* @param {string} userId the user ID for the user that the pickle key is for.
* @param {string} deviceId the device ID that the pickle key is for.
* @returns {string|null} the pickle key, or null if the platform does not
* support storing pickle keys.
*/
async createPickleKey(userId, deviceId) {
const randomArray = new Uint8Array(32);
crypto.getRandomValues(randomArray);
const data = await (0, _pickling.encryptPickleKey)(randomArray, userId, deviceId);
if (data === undefined) {
// no crypto support
return null;
}
try {
await (0, _StorageAccess.idbSave)("pickleKey", [userId, deviceId], data);
} catch (e) {
return null;
}
return (0, _matrix.encodeUnpaddedBase64)(randomArray);
}
/**
* Delete a previously stored pickle key from storage.
* @param {string} userId the user ID for the user that the pickle key is for.
* @param {string} deviceId the device ID that the pickle key is for.
*/
async destroyPickleKey(userId, deviceId) {
try {
await (0, _StorageAccess.idbDelete)("pickleKey", [userId, deviceId]);
} catch (e) {
_logger.logger.error("idbDelete failed in destroyPickleKey", e);
}
}
/**
* Clear app storage, called when logging out to perform data clean up.
*/
async clearStorage() {
window.sessionStorage.clear();
window.localStorage.clear();
}
/**
* Base URL to use when generating external links for this client, for platforms e.g. Desktop this will be a different instance
*/
get baseUrl() {
return window.location.origin + window.location.pathname;
}
/**
* Fallback Client URI to use for OIDC client registration for if one is not specified in config.json
*/
get defaultOidcClientUri() {
return window.location.origin;
}
/**
* Metadata to use for dynamic OIDC client registrations
*/
async getOidcClientMetadata() {
const config = _SdkConfig.default.get();
return {
clientName: config.brand,
clientUri: config.oidc_metadata?.client_uri ?? this.defaultOidcClientUri,
redirectUris: [this.getOidcCallbackUrl().href],
logoUri: config.oidc_metadata?.logo_uri ?? new URL("vector-icons/1024.png", this.baseUrl).href,
applicationType: "web",
contacts: config.oidc_metadata?.contacts,
tosUri: config.oidc_metadata?.tos_uri ?? config.terms_and_conditions_links?.[0]?.url,
policyUri: config.oidc_metadata?.policy_uri ?? config.privacy_policy_url
};
}
/**
* Suffix to append to the `state` parameter of OIDC /auth calls. Will be round-tripped to the callback URI.
* Currently only required for ElectronPlatform for passing element-desktop-ssoid.
*/
getOidcClientState() {
return "";
}
/**
* The URL to return to after a successful OIDC authentication
*/
getOidcCallbackUrl() {
const url = new URL(window.location.href);
// The redirect URL has to exactly match that registered at the OIDC server, so
// ensure that the fragment part of the URL is empty.
url.hash = "";
return url;
}
}
exports.default = BasePlatform;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbWF0cml4IiwicmVxdWlyZSIsIl9sb2dnZXIiLCJfZGlzcGF0Y2hlciIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJfYWN0aW9ucyIsIl9VcGRhdGVUb2FzdCIsIl9NYXRyaXhDbGllbnRQZWciLCJfU3RvcmFnZUFjY2VzcyIsIl9TZGtDb25maWciLCJfcGlja2xpbmciLCJTU09fSE9NRVNFUlZFUl9VUkxfS0VZIiwiZXhwb3J0cyIsIlNTT19JRF9TRVJWRVJfVVJMX0tFWSIsIlNTT19JRFBfSURfS0VZIiwiVXBkYXRlQ2hlY2tTdGF0dXMiLCJVUERBVEVfREVGRVJfS0VZIiwiQmFzZVBsYXRmb3JtIiwiY29uc3RydWN0b3IiLCJfZGVmaW5lUHJvcGVydHkyIiwiZGVmYXVsdCIsInBheWxvYWQiLCJhY3Rpb24iLCJBY3Rpb24iLCJPbkxvZ2dlZE91dCIsInNldE5vdGlmaWNhdGlvbkNvdW50IiwiZGlzIiwicmVnaXN0ZXIiLCJvbkFjdGlvbiIsInN0YXJ0VXBkYXRlQ2hlY2siLCJiaW5kIiwiY291bnQiLCJub3RpZmljYXRpb25Db3VudCIsInNldEVycm9yU3RhdHVzIiwiZXJyb3JEaWRPY2N1ciIsImNhblNlbGZVcGRhdGUiLCJoaWRlVXBkYXRlVG9hc3QiLCJsb2NhbFN0b3JhZ2UiLCJyZW1vdmVJdGVtIiwiZGlzcGF0Y2giLCJDaGVja1VwZGF0ZXMiLCJzdGF0dXMiLCJDaGVja2luZyIsImluc3RhbGxVcGRhdGUiLCJzaG91bGRTaG93VXBkYXRlIiwibmV3VmVyc2lvbiIsIk1hdHJpeENsaWVudFBlZyIsInVzZXJSZWdpc3RlcmVkV2l0aGluTGFzdEhvdXJzIiwidmVyc2lvbiIsImRlZmVyVW50aWwiLCJKU09OIiwicGFyc2UiLCJnZXRJdGVtIiwiRGF0ZSIsIm5vdyIsImUiLCJkZWZlclVwZGF0ZSIsImRhdGUiLCJzZXRIb3VycyIsInNldEl0ZW0iLCJzdHJpbmdpZnkiLCJnZXRUaW1lIiwic3VwcG9ydHNTcGVsbENoZWNrU2V0dGluZ3MiLCJhbGxvd092ZXJyaWRpbmdOYXRpdmVDb250ZXh0TWVudXMiLCJzdXBwb3J0c05vdGlmaWNhdGlvbnMiLCJtYXlTZW5kTm90aWZpY2F0aW9ucyIsImRpc3BsYXlOb3RpZmljYXRpb24iLCJ0aXRsZSIsIm1zZyIsImF2YXRhclVybCIsInJvb20iLCJldiIsIm5vdGlmQm9keSIsImJvZHkiLCJzaWxlbnQiLCJub3RpZmljYXRpb24iLCJ3aW5kb3ciLCJOb3RpZmljYXRpb24iLCJvbmNsaWNrIiwiVmlld1Jvb20iLCJyb29tX2lkIiwicm9vbUlkIiwibWV0cmljc1RyaWdnZXIiLCJnZXRUaHJlYWQiLCJldmVudF9pZCIsImdldElkIiwiZm9jdXMiLCJsb3VkTm90aWZpY2F0aW9uIiwiY2xlYXJOb3RpZmljYXRpb24iLCJub3RpZiIsImNsb3NlIiwibmVlZHNVcmxUb29sdGlwcyIsInN1cHBvcnRzU2V0dGluZyIsInNldHRpbmdOYW1lIiwiZ2V0U2V0dGluZ1ZhbHVlIiwidW5kZWZpbmVkIiwic2V0U2V0dGluZ1ZhbHVlIiwidmFsdWUiLCJFcnJvciIsImdldEV2ZW50SW5kZXhpbmdNYW5hZ2VyIiwic2V0TGFuZ3VhZ2UiLCJwcmVmZXJyZWRMYW5ncyIsInNldFNwZWxsQ2hlY2tFbmFibGVkIiwiZW5hYmxlZCIsImdldFNwZWxsQ2hlY2tFbmFibGVkIiwic2V0U3BlbGxDaGVja0xhbmd1YWdlcyIsImdldFNwZWxsQ2hlY2tMYW5ndWFnZXMiLCJnZXREZXNrdG9wQ2FwdHVyZXJTb3VyY2VzIiwib3B0aW9ucyIsInN1cHBvcnRzRGVza3RvcENhcHR1cmVyIiwic3VwcG9ydHNKaXRzaVNjcmVlbnNoYXJpbmciLCJvdmVycmlkZUJyb3dzZXJTaG9ydGN1dHMiLCJuYXZpZ2F0ZUZvcndhcmRCYWNrIiwiYmFjayIsImdldEF2YWlsYWJsZVNwZWxsQ2hlY2tMYW5ndWFnZXMiLCJnZXRTU09DYWxsYmFja1VybCIsImZyYWdtZW50QWZ0ZXJMb2dpbiIsInVybCIsIlVSTCIsImxvY2F0aW9uIiwiaHJlZiIsImhhc2giLCJzdGFydFNpbmdsZVNpZ25PbiIsIm14Q2xpZW50IiwibG9naW5UeXBlIiwiaWRwSWQiLCJnZXRIb21lc2VydmVyVXJsIiwiZ2V0SWRlbnRpdHlTZXJ2ZXJVcmwiLCJjYWxsYmFja1VybCIsImdldFNzb0xvZ2luVXJsIiwidG9TdHJpbmciLCJnZXRQaWNrbGVLZXkiLCJ1c2VySWQiLCJkZXZpY2VJZCIsImRhdGEiLCJpZGJMb2FkIiwibG9nZ2VyIiwiZXJyb3IiLCJidWlsZEFuZEVuY29kZVBpY2tsZUtleSIsImNyZWF0ZVBpY2tsZUtleSIsInJhbmRvbUFycmF5IiwiVWludDhBcnJheSIsImNyeXB0byIsImdldFJhbmRvbVZhbHVlcyIsImVuY3J5cHRQaWNrbGVLZXkiLCJpZGJTYXZlIiwiZW5jb2RlVW5wYWRkZWRCYXNlNjQiLCJkZXN0cm95UGlja2xlS2V5IiwiaWRiRGVsZXRlIiwiY2xlYXJTdG9yYWdlIiwic2Vzc2lvblN0b3JhZ2UiLCJjbGVhciIsImJhc2VVcmwiLCJvcmlnaW4iLCJwYXRobmFtZSIsImRlZmF1bHRPaWRjQ2xpZW50VXJpIiwiZ2V0T2lkY0NsaWVudE1ldGFkYXRhIiwiY29uZmlnIiwiU2RrQ29uZmlnIiwiZ2V0IiwiY2xpZW50TmFtZSIsImJyYW5kIiwiY2xpZW50VXJpIiwib2lkY19tZXRhZGF0YSIsImNsaWVudF91cmkiLCJyZWRpcmVjdFVyaXMiLCJnZXRPaWRjQ2FsbGJhY2tVcmwiLCJsb2dvVXJpIiwibG9nb191cmkiLCJhcHBsaWNhdGlvblR5cGUiLCJjb250YWN0cyIsInRvc1VyaSIsInRvc191cmkiLCJ0ZXJtc19hbmRfY29uZGl0aW9uc19saW5rcyIsInBvbGljeVVyaSIsInBvbGljeV91cmkiLCJwcml2YWN5X3BvbGljeV91cmwiLCJnZXRPaWRjQ2xpZW50U3RhdGUiXSwic291cmNlcyI6WyIuLi9zcmMvQmFzZVBsYXRmb3JtLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAyNCBOZXcgVmVjdG9yIEx0ZC5cbkNvcHlyaWdodCAyMDIwIFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5Db3B5cmlnaHQgMjAxOCBOZXcgVmVjdG9yIEx0ZFxuQ29weXJpZ2h0IDIwMTYgQXZpcmFsIERhc2d1cHRhXG5Db3B5cmlnaHQgMjAxNiBPcGVuTWFya2V0IEx0ZFxuXG5TUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQUdQTC0zLjAtb25seSBPUiBHUEwtMy4wLW9ubHlcblBsZWFzZSBzZWUgTElDRU5TRSBmaWxlcyBpbiB0aGUgcmVwb3NpdG9yeSByb290IGZvciBmdWxsIGRldGFpbHMuXG4qL1xuXG5pbXBvcnQge1xuICAgIE1hdHJpeENsaWVudCxcbiAgICBNYXRyaXhFdmVudCxcbiAgICBSb29tLFxuICAgIFNTT0FjdGlvbixcbiAgICBlbmNvZGVVbnBhZGRlZEJhc2U2NCxcbiAgICBPaWRjUmVnaXN0cmF0aW9uQ2xpZW50TWV0YWRhdGEsXG59IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tYXRyaXhcIjtcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9sb2dnZXJcIjtcblxuaW1wb3J0IGRpcyBmcm9tIFwiLi9kaXNwYXRjaGVyL2Rpc3BhdGNoZXJcIjtcbmltcG9ydCBCYXNlRXZlbnRJbmRleE1hbmFnZXIgZnJvbSBcIi4vaW5kZXhpbmcvQmFzZUV2ZW50SW5kZXhNYW5hZ2VyXCI7XG5pbXBvcnQgeyBBY3Rpb25QYXlsb2FkIH0gZnJvbSBcIi4vZGlzcGF0Y2hlci9wYXlsb2Fkc1wiO1xuaW1wb3J0IHsgQ2hlY2tVcGRhdGVzUGF5bG9hZCB9IGZyb20gXCIuL2Rpc3BhdGNoZXIvcGF5bG9hZHMvQ2hlY2tVcGRhdGVzUGF5bG9hZFwiO1xuaW1wb3J0IHsgQWN0aW9uIH0gZnJvbSBcIi4vZGlzcGF0Y2hlci9hY3Rpb25zXCI7XG5pbXBvcnQgeyBoaWRlVG9hc3QgYXMgaGlkZVVwZGF0ZVRvYXN0IH0gZnJvbSBcIi4vdG9hc3RzL1VwZGF0ZVRvYXN0XCI7XG5pbXBvcnQgeyBNYXRyaXhDbGllbnRQZWcgfSBmcm9tIFwiLi9NYXRyaXhDbGllbnRQZWdcIjtcbmltcG9ydCB7IGlkYkxvYWQsIGlkYlNhdmUsIGlkYkRlbGV0ZSB9IGZyb20gXCIuL3V0aWxzL1N0b3JhZ2VBY2Nlc3NcIjtcbmltcG9ydCB7IFZpZXdSb29tUGF5bG9hZCB9IGZyb20gXCIuL2Rpc3BhdGNoZXIvcGF5bG9hZHMvVmlld1Jvb21QYXlsb2FkXCI7XG5pbXBvcnQgeyBJQ29uZmlnT3B0aW9ucyB9IGZyb20gXCIuL0lDb25maWdPcHRpb25zXCI7XG5pbXBvcnQgU2RrQ29uZmlnIGZyb20gXCIuL1Nka0NvbmZpZ1wiO1xuaW1wb3J0IHsgYnVpbGRBbmRFbmNvZGVQaWNrbGVLZXksIGVuY3J5cHRQaWNrbGVLZXkgfSBmcm9tIFwiLi91dGlscy90b2tlbnMvcGlja2xpbmdcIjtcblxuZXhwb3J0IGNvbnN0IFNTT19IT01FU0VSVkVSX1VSTF9LRVkgPSBcIm14X3Nzb19oc191cmxcIjtcbmV4cG9ydCBjb25zdCBTU09fSURfU0VSVkVSX1VSTF9LRVkgPSBcIm14X3Nzb19pc191cmxcIjtcbmV4cG9ydCBjb25zdCBTU09fSURQX0lEX0tFWSA9IFwibXhfc3NvX2lkcF9pZFwiO1xuXG5leHBvcnQgZW51bSBVcGRhdGVDaGVja1N0YXR1cyB7XG4gICAgQ2hlY2tpbmcgPSBcIkNIRUNLSU5HXCIsXG4gICAgRXJyb3IgPSBcIkVSUk9SXCIsXG4gICAgTm90QXZhaWxhYmxlID0gXCJOT1RBVkFJTEFCTEVcIixcbiAgICBEb3dubG9hZGluZyA9IFwiRE9XTkxPQURJTkdcIixcbiAgICBSZWFkeSA9IFwiUkVBRFlcIixcbn1cblxuZXhwb3J0IGludGVyZmFjZSBVcGRhdGVTdGF0dXMge1xuICAgIC8qKlxuICAgICAqIFRoZSBjdXJyZW50IHBoYXNlIG9mIHRoZSBtYW51YWwgdXBkYXRlIGNoZWNrLlxuICAgICAqL1xuICAgIHN0YXR1czogVXBkYXRlQ2hlY2tTdGF0dXM7XG4gICAgLyoqXG4gICAgICogRGV0YWlsIHN0cmluZyByZWxhdGluZyB0byB0aGUgY3VycmVudCBzdGF0dXMsIHR5cGljYWxseSBmb3IgZXJyb3IgZGV0YWlscy5cbiAgICAgKi9cbiAgICBkZXRhaWw/OiBzdHJpbmc7XG59XG5cbmNvbnN0IFVQREFURV9ERUZFUl9LRVkgPSBcIm14X2RlZmVyX3VwZGF0ZVwiO1xuXG4vKipcbiAqIEJhc2UgY2xhc3MgZm9yIGNsYXNzZXMgdGhhdCBwcm92aWRlIHBsYXRmb3JtLXNwZWNpZmljIGZ1bmN0aW9uYWxpdHlcbiAqIGVnLiBTZXR0aW5nIGFuIGFwcGxpY2F0aW9uIGJhZGdlIG9yIGRpc3BsYXlpbmcgbm90aWZpY2F0aW9uc1xuICpcbiAqIEluc3RhbmNlcyBvZiB0aGlzIGNsYXNzIGFyZSBwcm92aWRlZCBieSB0aGUgYXBwbGljYXRpb24uXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGFic3RyYWN0IGNsYXNzIEJhc2VQbGF0Zm9ybSB7XG4gICAgcHJvdGVjdGVkIG5vdGlmaWNhdGlvbkNvdW50ID0gMDtcbiAgICBwcm90ZWN0ZWQgZXJyb3JEaWRPY2N1ciA9IGZhbHNlO1xuXG4gICAgcHJvdGVjdGVkIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBkaXMucmVnaXN0ZXIodGhpcy5vbkFjdGlvbik7XG4gICAgICAgIHRoaXMuc3RhcnRVcGRhdGVDaGVjayA9IHRoaXMuc3RhcnRVcGRhdGVDaGVjay5iaW5kKHRoaXMpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhYnN0cmFjdCBnZXRDb25maWcoKTogUHJvbWlzZTxJQ29uZmlnT3B0aW9ucyB8IHVuZGVmaW5lZD47XG5cbiAgICBwdWJsaWMgYWJzdHJhY3QgZ2V0RGVmYXVsdERldmljZURpc3BsYXlOYW1lKCk6IHN0cmluZztcblxuICAgIHByb3RlY3RlZCBvbkFjdGlvbiA9IChwYXlsb2FkOiBBY3Rpb25QYXlsb2FkKTogdm9pZCA9PiB7XG4gICAgICAgIHN3aXRjaCAocGF5bG9hZC5hY3Rpb24pIHtcbiAgICAgICAgICAgIGNhc2UgXCJvbl9jbGllbnRfbm90X3ZpYWJsZVwiOlxuICAgICAgICAgICAgY2FzZSBBY3Rpb24uT25Mb2dnZWRPdXQ6XG4gICAgICAgICAgICAgICAgdGhpcy5zZXROb3RpZmljYXRpb25Db3VudCgwKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvLyBVc2VkIHByaW1hcmlseSBmb3IgQW5hbHl0aWNzXG4gICAgcHVibGljIGFic3RyYWN0IGdldEh1bWFuUmVhZGFibGVOYW1lKCk6IHN0cmluZztcblxuICAgIHB1YmxpYyBzZXROb3RpZmljYXRpb25Db3VudChjb3VudDogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIHRoaXMubm90aWZpY2F0aW9uQ291bnQgPSBjb3VudDtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2V0RXJyb3JTdGF0dXMoZXJyb3JEaWRPY2N1cjogYm9vbGVhbik6IHZvaWQge1xuICAgICAgICB0aGlzLmVycm9yRGlkT2NjdXIgPSBlcnJvckRpZE9jY3VyO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFdoZXRoZXIgd2UgY2FuIGNhbGwgY2hlY2tGb3JVcGRhdGUgb24gdGhpcyBwbGF0Zm9ybSBidWlsZFxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBjYW5TZWxmVXBkYXRlKCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXJ0VXBkYXRlQ2hlY2soKTogdm9pZCB7XG4gICAgICAgIGhpZGVVcGRhdGVUb2FzdCgpO1xuICAgICAgICBsb2NhbFN0b3JhZ2UucmVtb3ZlSXRlbShVUERBVEVfREVGRVJfS0VZKTtcbiAgICAgICAgZGlzLmRpc3BhdGNoPENoZWNrVXBkYXRlc1BheWxvYWQ+KHtcbiAgICAgICAgICAgIGFjdGlvbjogQWN0aW9uLkNoZWNrVXBkYXRlcyxcbiAgICAgICAgICAgIHN0YXR1czogVXBkYXRlQ2hlY2tTdGF0dXMuQ2hlY2tpbmcsXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFVwZGF0ZSB0aGUgY3VycmVudGx5IHJ1bm5pbmcgYXBwIHRvIHRoZSBsYXRlc3QgYXZhaWxhYmxlIHZlcnNpb25cbiAgICAgKiBhbmQgcmVwbGFjZSB0aGlzIGluc3RhbmNlIG9mIHRoZSBhcHAgd2l0aCB0aGUgbmV3IHZlcnNpb24uXG4gICAgICovXG4gICAgcHVibGljIGluc3RhbGxVcGRhdGUoKTogdm9pZCB7fVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2sgaWYgdGhlIHZlcnNpb24gdXBkYXRlIGhhcyBiZWVuIGRlZmVycmVkIGFuZCB0aGF0IGRlZmVybWVudCBpcyBzdGlsbCBpbiBlZmZlY3RcbiAgICAgKiBAcGFyYW0gbmV3VmVyc2lvbiB0aGUgdmVyc2lvbiBzdHJpbmcgdG8gY2hlY2tcbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgc2hvdWxkU2hvd1VwZGF0ZShuZXdWZXJzaW9uOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgICAgLy8gSWYgdGhlIHVzZXIgcmVnaXN0ZXJlZCBvbiB0aGlzIGNsaWVudCBpbiB0aGUgbGFzdCAyNCBob3VycyB0aGVuIGRvIG5vdCBzaG93IHRoZW0gdGhlIHVwZGF0ZSB0b2FzdFxuICAgICAgICBpZiAoTWF0cml4Q2xpZW50UGVnLnVzZXJSZWdpc3RlcmVkV2l0aGluTGFzdEhvdXJzKDI0KSkgcmV0dXJuIGZhbHNlO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBbdmVyc2lvbiwgZGVmZXJVbnRpbF0gPSBKU09OLnBhcnNlKGxvY2FsU3RvcmFnZS5nZXRJdGVtKFVQREFURV9ERUZFUl9LRVkpISk7XG4gICAgICAgICAgICByZXR1cm4gbmV3VmVyc2lvbiAhPT0gdmVyc2lvbiB8fCBEYXRlLm5vdygpID4gZGVmZXJVbnRpbDtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBJZ25vcmUgdGhlIHBlbmRpbmcgdXBkYXRlIGFuZCBkb24ndCBwcm9tcHQgYWJvdXQgdGhpcyB2ZXJzaW9uXG4gICAgICogdW50aWwgdGhlIG5leHQgbW9ybmluZyAoOGFtKS5cbiAgICAgKi9cbiAgICBwdWJsaWMgZGVmZXJVcGRhdGUobmV3VmVyc2lvbjogc3RyaW5nKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZShEYXRlLm5vdygpICsgMjQgKiA2MCAqIDYwICogMTAwMCk7XG4gICAgICAgIGRhdGUuc2V0SG91cnMoOCwgMCwgMCwgMCk7IC8vIHNldCB0byBuZXh0IDhhbVxuICAgICAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbShVUERBVEVfREVGRVJfS0VZLCBKU09OLnN0cmluZ2lmeShbbmV3VmVyc2lvbiwgZGF0ZS5nZXRUaW1lKCldKSk7XG4gICAgICAgIGhpZGVVcGRhdGVUb2FzdCgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybiB0cnVlIGlmIHBsYXRmb3JtIHN1cHBvcnRzIG11bHRpLWxhbmd1YWdlXG4gICAgICogc3BlbGwtY2hlY2tpbmcsIG90aGVyd2lzZSBmYWxzZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgc3VwcG9ydHNTcGVsbENoZWNrU2V0dGluZ3MoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRydWUgaWYgcGxhdGZvcm0gYWxsb3dzIG92ZXJyaWRpbmcgbmF0aXZlIGNvbnRleHQgbWVudXNcbiAgICAgKi9cbiAgICBwdWJsaWMgYWxsb3dPdmVycmlkaW5nTmF0aXZlQ29udGV4dE1lbnVzKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0cnVlIGlmIHRoZSBwbGF0Zm9ybSBzdXBwb3J0cyBkaXNwbGF5aW5nXG4gICAgICogbm90aWZpY2F0aW9ucywgb3RoZXJ3aXNlIGZhbHNlLlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSB3aGV0aGVyIHRoZSBwbGF0Zm9ybSBzdXBwb3J0cyBkaXNwbGF5aW5nIG5vdGlmaWNhdGlvbnNcbiAgICAgKi9cbiAgICBwdWJsaWMgc3VwcG9ydHNOb3RpZmljYXRpb25zKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0cnVlIGlmIHRoZSBhcHBsaWNhdGlvbiBjdXJyZW50bHkgaGFzIHBlcm1pc3Npb25cbiAgICAgKiB0byBkaXNwbGF5IG5vdGlmaWNhdGlvbnMuIE90aGVyd2lzZSBmYWxzZS5cbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gd2hldGhlciB0aGUgYXBwbGljYXRpb24gaGFzIHBlcm1pc3Npb24gdG8gZGlzcGxheSBub3RpZmljYXRpb25zXG4gICAgICovXG4gICAgcHVibGljIG1heVNlbmROb3RpZmljYXRpb25zKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVxdWVzdHMgcGVybWlzc2lvbiB0byBzZW5kIG5vdGlmaWNhdGlvbnMuIFJldHVybnNcbiAgICAgKiBhIHByb21pc2UgdGhhdCBpcyByZXNvbHZlZCB3aGVuIHRoZSB1c2VyIGhhcyByZXNwb25kZWRcbiAgICAgKiB0byB0aGUgcmVxdWVzdC4gVGhlIHByb21pc2UgaGFzIGEgc2luZ2xlIHN0cmluZyBhcmd1bWVudFxuICAgICAqIHRoYXQgaXMgJ2dyYW50ZWQnIGlmIHRoZSB1c2VyIGFsbG93ZWQgdGhlIHJlcXVlc3Qgb3JcbiAgICAgKiAnZGVuaWVkJyBvdGhlcndpc2UuXG4gICAgICovXG4gICAgcHVibGljIGFic3RyYWN0IHJlcXVlc3ROb3RpZmljYXRpb25QZXJtaXNzaW9uKCk6IFByb21pc2U8c3RyaW5nPjtcblxuICAgIHB1YmxpYyBkaXNwbGF5Tm90aWZpY2F0aW9uKFxuICAgICAgICB0aXRsZTogc3RyaW5nLFxuICAgICAgICBtc2c6IHN0cmluZyxcbiAgICAgICAgYXZhdGFyVXJsOiBzdHJpbmcgfCBudWxsLFxuICAgICAgICByb29tOiBSb29tLFxuICAgICAgICBldj86IE1hdHJpeEV2ZW50LFxuICAgICk6IE5vdGlmaWNhdGlvbiB7XG4gICAgICAgIGNvbnN0IG5vdGlmQm9keTogTm90aWZpY2F0aW9uT3B0aW9ucyA9IHtcbiAgICAgICAgICAgIGJvZHk6IG1zZyxcbiAgICAgICAgICAgIHNpbGVudDogdHJ1ZSwgLy8gd2UgcGxheSBvdXIgb3duIHNvdW5kc1xuICAgICAgICB9O1xuICAgICAgICBpZiAoYXZhdGFyVXJsKSBub3RpZkJvZHlbXCJpY29uXCJdID0gYXZhdGFyVXJsO1xuICAgICAgICBjb25zdCBub3RpZmljYXRpb24gPSBuZXcgd2luZG93Lk5vdGlmaWNhdGlvbih0aXRsZSwgbm90aWZCb2R5KTtcblxuICAgICAgICBub3RpZmljYXRpb24ub25jbGljayA9ICgpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHBheWxvYWQ6IFZpZXdSb29tUGF5bG9hZCA9IHtcbiAgICAgICAgICAgICAgICBhY3Rpb246IEFjdGlvbi5WaWV3Um9vbSxcbiAgICAgICAgICAgICAgICByb29tX2lkOiByb29tLnJvb21JZCxcbiAgICAgICAgICAgICAgICBtZXRyaWNzVHJpZ2dlcjogXCJOb3RpZmljYXRpb25cIixcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIGlmIChldj8uZ2V0VGhyZWFkKCkpIHtcbiAgICAgICAgICAgICAgICBwYXlsb2FkLmV2ZW50X2lkID0gZXYuZ2V0SWQoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZGlzLmRpc3BhdGNoKHBheWxvYWQpO1xuICAgICAgICAgICAgd2luZG93LmZvY3VzKCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIG5vdGlmaWNhdGlvbjtcbiAgICB9XG5cbiAgICBwdWJsaWMgbG91ZE5vdGlmaWNhdGlvbihldjogTWF0cml4RXZlbnQsIHJvb206IFJvb20pOiB2b2lkIHt9XG5cbiAgICBwdWJsaWMgY2xlYXJOb3RpZmljYXRpb24obm90aWY6IE5vdGlmaWNhdGlvbik6IHZvaWQge1xuICAgICAgICAvLyBTb21lIGJyb3dzZXJzIGRvbid0IHN1cHBvcnQgdGhpcywgZS5nIFNhZmFyaSBvbiBpT1NcbiAgICAgICAgLy8gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL05vdGlmaWNhdGlvbi9jbG9zZVxuICAgICAgICBpZiAobm90aWYuY2xvc2UpIHtcbiAgICAgICAgICAgIG5vdGlmLmNsb3NlKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRydWUgaWYgdGhlIHBsYXRmb3JtIHJlcXVpcmVzIFVSTCBwcmV2aWV3cyBpbiB0b29sdGlwcywgb3RoZXJ3aXNlIGZhbHNlLlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSB3aGV0aGVyIHRoZSBwbGF0Zm9ybSByZXF1aXJlcyBVUkwgcHJldmlld3MgaW4gdG9vbHRpcHNcbiAgICAgKi9cbiAgICBwdWJsaWMgbmVlZHNVcmxUb29sdGlwcygpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgYSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBjdXJyZW50IHZlcnNpb24gb2YgdGhlIGFwcGxpY2F0aW9uLlxuICAgICAqL1xuICAgIHB1YmxpYyBhYnN0cmFjdCBnZXRBcHBWZXJzaW9uKCk6IFByb21pc2U8c3RyaW5nPjtcblxuICAgIC8qKlxuICAgICAqIFJlc3RhcnRzIHRoZSBhcHBsaWNhdGlvbiwgd2l0aG91dCBuZWNlc3NhcmlseSByZWxvYWRpbmdcbiAgICAgKiBhbnkgYXBwbGljYXRpb24gY29kZVxuICAgICAqL1xuICAgIHB1YmxpYyBhYnN0cmFjdCByZWxvYWQoKTogdm9pZDtcblxuICAgIHB1YmxpYyBzdXBwb3J0c1NldHRpbmcoc2V0dGluZ05hbWU/OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBnZXRTZXR0aW5nVmFsdWUoc2V0dGluZ05hbWU6IHN0cmluZyk6IFByb21pc2U8YW55PiB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgcHVibGljIHNldFNldHRpbmdWYWx1ZShzZXR0aW5nTmFtZTogc3RyaW5nLCB2YWx1ZTogYW55KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIlVuaW1wbGVtZW50ZWRcIik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IG91ciBwbGF0Zm9ybSBzcGVjaWZpYyBFdmVudEluZGV4TWFuYWdlci5cbiAgICAgKlxuICAgICAqIEByZXR1cm4ge0Jhc2VFdmVudEluZGV4TWFuYWdlcn0gVGhlIEV2ZW50SW5kZXggbWFuYWdlciBmb3Igb3VyIHBsYXRmb3JtLFxuICAgICAqIGNhbiBiZSBudWxsIGlmIHRoZSBwbGF0Zm9ybSBkb2Vzbid0IHN1cHBvcnQgZXZlbnQgaW5kZXhpbmcuXG4gICAgICovXG4gICAgcHVibGljIGdldEV2ZW50SW5kZXhpbmdNYW5hZ2VyKCk6IEJhc2VFdmVudEluZGV4TWFuYWdlciB8IG51bGwge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2V0TGFuZ3VhZ2UocHJlZmVycmVkTGFuZ3M6IHN0cmluZ1tdKTogdm9pZCB7fVxuXG4gICAgcHVibGljIHNldFNwZWxsQ2hlY2tFbmFibGVkKGVuYWJsZWQ6IGJvb2xlYW4pOiB2b2lkIHt9XG5cbiAgICBwdWJsaWMgYXN5bmMgZ2V0U3BlbGxDaGVja0VuYWJsZWQoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2V0U3BlbGxDaGVja0xhbmd1YWdlcyhwcmVmZXJyZWRMYW5nczogc3RyaW5nW10pOiB2b2lkIHt9XG5cbiAgICBwdWJsaWMgZ2V0U3BlbGxDaGVja0xhbmd1YWdlcygpOiBQcm9taXNlPHN0cmluZ1tdPiB8IG51bGwge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZ2V0RGVza3RvcENhcHR1cmVyU291cmNlcyhvcHRpb25zOiBHZXRTb3VyY2VzT3B0aW9ucyk6IFByb21pc2U8QXJyYXk8RGVza3RvcENhcHR1cmVyU291cmNlPj4ge1xuICAgICAgICByZXR1cm4gW107XG4gICAgfVxuXG4gICAgcHVibGljIHN1cHBvcnRzRGVza3RvcENhcHR1cmVyKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgcHVibGljIHN1cHBvcnRzSml0c2lTY3JlZW5zaGFyaW5nKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICBwdWJsaWMgb3ZlcnJpZGVCcm93c2VyU2hvcnRjdXRzKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgcHVibGljIG5hdmlnYXRlRm9yd2FyZEJhY2soYmFjazogYm9vbGVhbik6IHZvaWQge31cblxuICAgIHB1YmxpYyBnZXRBdmFpbGFibGVTcGVsbENoZWNrTGFuZ3VhZ2VzKCk6IFByb21pc2U8c3RyaW5nW10+IHwgbnVsbCB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBVUkwgdG8gcmV0dXJuIHRvIGFmdGVyIGEgc3VjY2Vzc2Z1bCBTU08gYXV0aGVudGljYXRpb25cbiAgICAgKiBAcGFyYW0gZnJhZ21lbnRBZnRlckxvZ2luIG9wdGlvbmFsIGZyYWdtZW50IGZvciBzcGVjaWZpYyB2aWV3IHRvIHJldHVybiB0b1xuICAgICAqL1xuICAgIHB1YmxpYyBnZXRTU09DYWxsYmFja1VybChmcmFnbWVudEFmdGVyTG9naW4gPSBcIlwiKTogVVJMIHtcbiAgICAgICAgY29uc3QgdXJsID0gbmV3IFVSTCh3aW5kb3cubG9jYXRpb24uaHJlZik7XG4gICAgICAgIHVybC5oYXNoID0gZnJhZ21lbnRBZnRlckxvZ2luO1xuICAgICAgICByZXR1cm4gdXJsO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEJlZ2luIFNpbmdsZSBTaWduIE9uIGZsb3dzLlxuICAgICAqIEBwYXJhbSB7TWF0cml4Q2xpZW50fSBteENsaWVudCB0aGUgbWF0cml4IGNsaWVudCB1c2luZyB3aGljaCB3ZSBzaG91bGQgc3RhcnQgdGhlIGZsb3dcbiAgICAgKiBAcGFyYW0ge1wic3NvXCJ8XCJjYXNcIn0gbG9naW5UeXBlIHRoZSB0eXBlIG9mIFNTTyBpdCBpcywgQ0FTL1NTTy5cbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gZnJhZ21lbnRBZnRlckxvZ2luIHRoZSBoYXNoIHRvIHBhc3MgdG8gdGhlIGFwcCBkdXJpbmcgc3NvIGNhbGxiYWNrLlxuICAgICAqIEBwYXJhbSB7U1NPQWN0aW9ufSBhY3Rpb24gdGhlIFNTTyBmbG93IHRvIGluZGljYXRlIHRvIHRoZSBJZFAsIG9wdGlvbmFsLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBpZHBJZCBUaGUgSUQgb2YgdGhlIElkZW50aXR5IFByb3ZpZGVyIGJlaW5nIHRhcmdldGVkLCBvcHRpb25hbC5cbiAgICAgKi9cbiAgICBwdWJsaWMgc3RhcnRTaW5nbGVTaWduT24oXG4gICAgICAgIG14Q2xpZW50OiBNYXRyaXhDbGllbnQsXG4gICAgICAgIGxvZ2luVHlwZTogXCJzc29cIiB8IFwiY2FzXCIsXG4gICAgICAgIGZyYWdtZW50QWZ0ZXJMb2dpbj86IHN0cmluZyxcbiAgICAgICAgaWRwSWQ/OiBzdHJpbmcsXG4gICAgICAgIGFjdGlvbj86IFNTT0FjdGlvbixcbiAgICApOiB2b2lkIHtcbiAgICAgICAgLy8gcGVyc2lzdCBocyB1cmwgYW5kIGlzIHVybCBmb3Igd2hlbiB0aGUgdXNlciBpcyByZXR1cm5lZCB0byB0aGUgYXBwIHdpdGggdGhlIGxvZ2luIHRva2VuXG4gICAgICAgIGxvY2FsU3RvcmFnZS5zZXRJdGVtKFNTT19IT01FU0VSVkVSX1VSTF9LRVksIG14Q2xpZW50LmdldEhvbWVzZXJ2ZXJVcmwoKSk7XG4gICAgICAgIGlmIChteENsaWVudC5nZXRJZGVudGl0eVNlcnZlclVybCgpKSB7XG4gICAgICAgICAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbShTU09fSURfU0VSVkVSX1VSTF9LRVksIG14Q2xpZW50LmdldElkZW50aXR5U2VydmVyVXJsKCkhKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaWRwSWQpIHtcbiAgICAgICAgICAgIGxvY2FsU3RvcmFnZS5zZXRJdGVtKFNTT19JRFBfSURfS0VZLCBpZHBJZCk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgY2FsbGJhY2tVcmwgPSB0aGlzLmdldFNTT0NhbGxiYWNrVXJsKGZyYWdtZW50QWZ0ZXJMb2dpbik7XG4gICAgICAgIHdpbmRvdy5sb2NhdGlvbi5ocmVmID0gbXhDbGllbnQuZ2V0U3NvTG9naW5VcmwoY2FsbGJhY2tVcmwudG9TdHJpbmcoKSwgbG9naW5UeXBlLCBpZHBJZCwgYWN0aW9uKTsgLy8gcmVkaXJlY3QgdG8gU1NPXG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGEgcHJldmlvdXNseSBzdG9yZWQgcGlja2xlIGtleS4gIFRoZSBwaWNrbGUga2V5IGlzIHVzZWQgZm9yXG4gICAgICogZW5jcnlwdGluZyBsaWJvbG0gb2JqZWN0cyBhbmQgcmVhY3Qtc2RrLWNyeXB0byBkYXRhLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSB1c2VySWQgdGhlIHVzZXIgSUQgZm9yIHRoZSB1c2VyIHRoYXQgdGhlIHBpY2tsZSBrZXkgaXMgZm9yLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBkZXZpY2VJZCB0aGUgZGV2aWNlIElEIHRoYXQgdGhlIHBpY2tsZSBrZXkgaXMgZm9yLlxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd8bnVsbH0gdGhlIHByZXZpb3VzbHkgc3RvcmVkIHBpY2tsZSBrZXksIG9yIG51bGwgaWYgbm9cbiAgICAgKiAgICAgcGlja2xlIGtleSBoYXMgYmVlbiBzdG9yZWQuXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIGdldFBpY2tsZUtleSh1c2VySWQ6IHN0cmluZywgZGV2aWNlSWQ6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nIHwgbnVsbD4ge1xuICAgICAgICBsZXQgZGF0YTogeyBlbmNyeXB0ZWQ/OiBCdWZmZXJTb3VyY2U7IGl2PzogQnVmZmVyU291cmNlOyBjcnlwdG9LZXk/OiBDcnlwdG9LZXkgfSB8IHVuZGVmaW5lZDtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGRhdGEgPSBhd2FpdCBpZGJMb2FkKFwicGlja2xlS2V5XCIsIFt1c2VySWQsIGRldmljZUlkXSk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGxvZ2dlci5lcnJvcihcImlkYkxvYWQgZm9yIHBpY2tsZUtleSBmYWlsZWRcIiwgZSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gKGF3YWl0IGJ1aWxkQW5kRW5jb2RlUGlja2xlS2V5KGRhdGEsIHVzZXJJZCwgZGV2aWNlSWQpKSA/PyBudWxsO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgc3RvcmUgYSBwaWNrbGUga2V5IGZvciBlbmNyeXB0aW5nIGxpYm9sbSBvYmplY3RzLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSB1c2VySWQgdGhlIHVzZXIgSUQgZm9yIHRoZSB1c2VyIHRoYXQgdGhlIHBpY2tsZSBrZXkgaXMgZm9yLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBkZXZpY2VJZCB0aGUgZGV2aWNlIElEIHRoYXQgdGhlIHBpY2tsZSBrZXkgaXMgZm9yLlxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd8bnVsbH0gdGhlIHBpY2tsZSBrZXksIG9yIG51bGwgaWYgdGhlIHBsYXRmb3JtIGRvZXMgbm90XG4gICAgICogICAgIHN1cHBvcnQgc3RvcmluZyBwaWNrbGUga2V5cy5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgY3JlYXRlUGlja2xlS2V5KHVzZXJJZDogc3RyaW5nLCBkZXZpY2VJZDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmcgfCBudWxsPiB7XG4gICAgICAgIGNvbnN0IHJhbmRvbUFycmF5ID0gbmV3IFVpbnQ4QXJyYXkoMzIpO1xuICAgICAgICBjcnlwdG8uZ2V0UmFuZG9tVmFsdWVzKHJhbmRvbUFycmF5KTtcbiAgICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IGVuY3J5cHRQaWNrbGVLZXkocmFuZG9tQXJyYXksIHVzZXJJZCwgZGV2aWNlSWQpO1xuICAgICAgICBpZiAoZGF0YSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAvLyBubyBjcnlwdG8gc3VwcG9ydFxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgaWRiU2F2ZShcInBpY2tsZUtleVwiLCBbdXNlcklkLCBkZXZpY2VJZF0sIGRhdGEpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZW5jb2RlVW5wYWRkZWRCYXNlNjQocmFuZG9tQXJyYXkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIERlbGV0ZSBhIHByZXZpb3VzbHkgc3RvcmVkIHBpY2tsZSBrZXkgZnJvbSBzdG9yYWdlLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSB1c2VySWQgdGhlIHVzZXIgSUQgZm9yIHRoZSB1c2VyIHRoYXQgdGhlIHBpY2tsZSBrZXkgaXMgZm9yLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBkZXZpY2VJZCB0aGUgZGV2aWNlIElEIHRoYXQgdGhlIHBpY2tsZSBrZXkgaXMgZm9yLlxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBkZXN0cm95UGlja2xlS2V5KHVzZXJJZDogc3RyaW5nLCBkZXZpY2VJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBpZGJEZWxldGUoXCJwaWNrbGVLZXlcIiwgW3VzZXJJZCwgZGV2aWNlSWRdKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgbG9nZ2VyLmVycm9yKFwiaWRiRGVsZXRlIGZhaWxlZCBpbiBkZXN0cm95UGlja2xlS2V5XCIsIGUpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2xlYXIgYXBwIHN0b3JhZ2UsIGNhbGxlZCB3aGVuIGxvZ2dpbmcgb3V0IHRvIHBlcmZvcm0gZGF0YSBjbGVhbiB1cC5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgY2xlYXJTdG9yYWdlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB3aW5kb3cuc2Vzc2lvblN0b3JhZ2UuY2xlYXIoKTtcbiAgICAgICAgd2luZG93LmxvY2FsU3RvcmFnZS5jbGVhcigpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEJhc2UgVVJMIHRvIHVzZSB3aGVuIGdlbmVyYXRpbmcgZXh0ZXJuYWwgbGlua3MgZm9yIHRoaXMgY2xpZW50LCBmb3IgcGxhdGZvcm1zIGUuZy4gRGVza3RvcCB0aGlzIHdpbGwgYmUgYSBkaWZmZXJlbnQgaW5zdGFuY2VcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IGJhc2VVcmwoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHdpbmRvdy5sb2NhdGlvbi5vcmlnaW4gKyB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRmFsbGJhY2sgQ2xpZW50IFVSSSB0byB1c2UgZm9yIE9JREMgY2xpZW50IHJlZ2lzdHJhdGlvbiBmb3IgaWYgb25lIGlzIG5vdCBzcGVjaWZpZWQgaW4gY29uZmlnLmpzb25cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IGRlZmF1bHRPaWRjQ2xpZW50VXJpKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiB3aW5kb3cubG9jYXRpb24ub3JpZ2luO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIE1ldGFkYXRhIHRvIHVzZSBmb3IgZHluYW1pYyBPSURDIGNsaWVudCByZWdpc3RyYXRpb25zXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIGdldE9pZGNDbGllbnRNZXRhZGF0YSgpOiBQcm9taXNlPE9pZGNSZWdpc3RyYXRpb25DbGllbnRNZXRhZGF0YT4ge1xuICAgICAgICBjb25zdCBjb25maWcgPSBTZGtDb25maWcuZ2V0KCk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBjbGllbnROYW1lOiBjb25maWcuYnJhbmQsXG4gICAgICAgICAgICBjbGllbnRVcmk6IGNvbmZpZy5vaWRjX21ldGFkYXRhPy5jbGllbnRfdXJpID8/IHRoaXMuZGVmYXVsdE9pZGNDbGllbnRVcmksXG4gICAgICAgICAgICByZWRpcmVjdFVyaXM6IFt0aGlzLmdldE9pZGNDYWxsYmFja1VybCgpLmhyZWZdLFxuICAgICAgICAgICAgbG9nb1VyaTogY29uZmlnLm9pZGNfbWV0YWRhdGE/LmxvZ29fdXJpID8/IG5ldyBVUkwoXCJ2ZWN0b3ItaWNvbnMvMTAyNC5wbmdcIiwgdGhpcy5iYXNlVXJsKS5ocmVmLFxuICAgICAgICAgICAgYXBwbGljYXRpb25UeXBlOiBcIndlYlwiLFxuICAgICAgICAgICAgY29udGFjdHM6IGNvbmZpZy5vaWRjX21ldGFkYXRhPy5jb250YWN0cyxcbiAgICAgICAgICAgIHRvc1VyaTogY29uZmlnLm9pZGNfbWV0YWRhdGE/LnRvc191cmkgPz8gY29uZmlnLnRlcm1zX2FuZF9jb25kaXRpb25zX2xpbmtzPy5bMF0/LnVybCxcbiAgICAgICAgICAgIHBvbGljeVVyaTogY29uZmlnLm9pZGNfbWV0YWRhdGE/LnBvbGljeV91cmkgPz8gY29uZmlnLnByaXZhY3lfcG9saWN5X3VybCxcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTdWZmaXggdG8gYXBwZW5kIHRvIHRoZSBgc3RhdGVgIHBhcmFtZXRlciBvZiBPSURDIC9hdXRoIGNhbGxzLiBXaWxsIGJlIHJvdW5kLXRyaXBwZWQgdG8gdGhlIGNhbGxiYWNrIFVSSS5cbiAgICAgKiBDdXJyZW50bHkgb25seSByZXF1aXJlZCBmb3IgRWxlY3Ryb25QbGF0Zm9ybSBmb3IgcGFzc2luZyBlbGVtZW50LWRlc2t0b3Atc3NvaWQuXG4gICAgICovXG4gICAgcHVibGljIGdldE9pZGNDbGllbnRTdGF0ZSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gXCJcIjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgVVJMIHRvIHJldHVybiB0byBhZnRlciBhIHN1Y2Nlc3NmdWwgT0lEQyBhdXRoZW50aWNhdGlvblxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRPaWRjQ2FsbGJhY2tVcmwoKTogVVJMIHtcbiAgICAgICAgY29uc3QgdXJsID0gbmV3IFVSTCh3aW5kb3cubG9jYXRpb24uaHJlZik7XG4gICAgICAgIC8vIFRoZSByZWRpcmVjdCBVUkwgaGFzIHRvIGV4YWN0bHkgbWF0Y2ggdGhhdCByZWdpc3RlcmVkIGF0IHRoZSBPSURDIHNlcnZlciwgc29cbiAgICAgICAgLy8gZW5zdXJlIHRoYXQgdGhlIGZyYWdtZW50IHBhcnQgb2YgdGhlIFVSTCBpcyBlbXB0eS5cbiAgICAgICAgdXJsLmhhc2ggPSBcIlwiO1xuICAgICAgICByZXR1cm4gdXJsO1xuICAgIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFXQSxJQUFBQSxPQUFBLEdBQUFDLE9BQUE7QUFRQSxJQUFBQyxPQUFBLEdBQUFELE9BQUE7QUFFQSxJQUFBRSxXQUFBLEdBQUFDLHNCQUFBLENBQUFILE9BQUE7QUFJQSxJQUFBSSxRQUFBLEdBQUFKLE9BQUE7QUFDQSxJQUFBSyxZQUFBLEdBQUFMLE9BQUE7QUFDQSxJQUFBTSxnQkFBQSxHQUFBTixPQUFBO0FBQ0EsSUFBQU8sY0FBQSxHQUFBUCxPQUFBO0FBR0EsSUFBQVEsVUFBQSxHQUFBTCxzQkFBQSxDQUFBSCxPQUFBO0FBQ0EsSUFBQVMsU0FBQSxHQUFBVCxPQUFB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