UNPKG

matrix-react-sdk

Version:
451 lines (435 loc) 67 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.canEncryptToAllUsers = canEncryptToAllUsers; exports.checkUserIsAllowedToChangeEncryption = checkUserIsAllowedToChangeEncryption; exports.default = createRoom; exports.ensureDMExists = ensureDMExists; exports.ensureVirtualRoomExists = ensureVirtualRoomExists; 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 _Modal = _interopRequireDefault(require("./Modal")); var _languageHandler = require("./languageHandler"); var _dispatcher = _interopRequireDefault(require("./dispatcher/dispatcher")); var Rooms = _interopRequireWildcard(require("./Rooms")); var _UserAddress = require("./UserAddress"); var _callTypes = require("./call-types"); var _SpaceStore = _interopRequireDefault(require("./stores/spaces/SpaceStore")); var _space = require("./utils/space"); var _Call = require("./models/Call"); var _actions = require("./dispatcher/actions"); var _ErrorDialog = _interopRequireDefault(require("./components/views/dialogs/ErrorDialog")); var _Spinner = _interopRequireDefault(require("./components/views/elements/Spinner")); var _findDMForUser = require("./utils/dm/findDMForUser"); var _rooms = require("./utils/rooms"); var _shouldForceDisableEncryption = require("./utils/crypto/shouldForceDisableEncryption"); var _membership = require("./utils/membership"); var _PreferredRoomVersions = require("./utils/PreferredRoomVersions"); var _SettingsStore = _interopRequireDefault(require("./settings/SettingsStore")); var _crypto = require("./utils/crypto"); 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, 2020 The Matrix.org Foundation C.I.C. 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. */ // we define a number of interfaces which take their names from the js-sdk /* eslint-disable camelcase */ const DEFAULT_EVENT_POWER_LEVELS = { [_matrix.EventType.RoomName]: 50, [_matrix.EventType.RoomAvatar]: 50, [_matrix.EventType.RoomPowerLevels]: 100, [_matrix.EventType.RoomHistoryVisibility]: 100, [_matrix.EventType.RoomCanonicalAlias]: 50, [_matrix.EventType.RoomTombstone]: 100, [_matrix.EventType.RoomServerAcl]: 100, [_matrix.EventType.RoomEncryption]: 100 }; /** * Create a new room, and switch to it. * * @param client The Matrix Client instance to create the room with * @param {object=} opts parameters for creating the room * @param {string=} opts.dmUserId If specified, make this a DM room for this user and invite them * @param {object=} opts.createOpts set of options to pass to createRoom call. * @param {bool=} opts.spinner True to show a modal spinner while the room is created. * Default: True * @param {bool=} opts.guestAccess Whether to enable guest access. * Default: True * @param {bool=} opts.encryption Whether to enable encryption. * Default: False * @param {bool=} opts.inlineErrors True to raise errors off the promise instead of resolving to null. * Default: False * @param {bool=} opts.andView True to dispatch an action to view the room once it has been created. * * @returns {Promise} which resolves to the room id, or null if the * action was aborted or failed. */ async function createRoom(client, opts) { opts = opts || {}; if (opts.spinner === undefined) opts.spinner = true; if (opts.guestAccess === undefined) opts.guestAccess = true; if (opts.encryption === undefined) opts.encryption = false; if (client.isGuest()) { _dispatcher.default.dispatch({ action: "require_registration" }); return null; } const defaultPreset = opts.dmUserId ? _matrix.Preset.TrustedPrivateChat : _matrix.Preset.PrivateChat; // set some defaults for the creation const createOpts = opts.createOpts || {}; createOpts.preset = createOpts.preset || defaultPreset; createOpts.visibility = createOpts.visibility || _matrix.Visibility.Private; // We allow UX of DMing ourselves as a form of creating a personal room but the server throws // an error when a user tries to invite themselves so we filter it out if (opts.dmUserId && opts.dmUserId !== client.getUserId() && createOpts.invite === undefined) { switch ((0, _UserAddress.getAddressType)(opts.dmUserId)) { case "mx-user-id": createOpts.invite = [opts.dmUserId]; break; case "email": { const isUrl = client.getIdentityServerUrl(true); if (!isUrl) { throw new _languageHandler.UserFriendlyError("cannot_invite_without_identity_server"); } createOpts.invite_3pid = [{ id_server: isUrl, medium: "email", address: opts.dmUserId }]; break; } } } if (opts.dmUserId && createOpts.is_direct === undefined) { createOpts.is_direct = true; } if (opts.roomType) { createOpts.creation_content = _objectSpread(_objectSpread({}, createOpts.creation_content), {}, { [_matrix.RoomCreateTypeField]: opts.roomType }); // Video rooms require custom power levels if (opts.roomType === _matrix.RoomType.ElementVideo) { createOpts.power_level_content_override = { events: _objectSpread(_objectSpread({}, DEFAULT_EVENT_POWER_LEVELS), {}, { // Allow all users to send call membership updates [_Call.JitsiCall.MEMBER_EVENT_TYPE]: 0, // Make widgets immutable, even to admins "im.vector.modular.widgets": 200 }), users: { // Temporarily give ourselves the power to set up a widget [client.getSafeUserId()]: 200 } }; } else if (opts.roomType === _matrix.RoomType.UnstableCall) { createOpts.power_level_content_override = { events: _objectSpread(_objectSpread({}, DEFAULT_EVENT_POWER_LEVELS), {}, { // Allow all users to send call membership updates [_Call.ElementCall.MEMBER_EVENT_TYPE.name]: 0, // Make calls immutable, even to admins [_Call.ElementCall.CALL_EVENT_TYPE.name]: 200 }), users: { // Temporarily give ourselves the power to set up a call [client.getSafeUserId()]: 200 } }; } } else if (_SettingsStore.default.getValue("feature_group_calls")) { createOpts.power_level_content_override = { events: _objectSpread(_objectSpread({}, DEFAULT_EVENT_POWER_LEVELS), {}, { // It should always (including non video rooms) be possible to join a group call. [_Call.ElementCall.MEMBER_EVENT_TYPE.name]: 0, // Make sure only admins can enable it (DEPRECATED) [_Call.ElementCall.CALL_EVENT_TYPE.name]: 100 }) }; } // By default, view the room after creating it if (opts.andView === undefined) { opts.andView = true; } createOpts.initial_state = createOpts.initial_state || []; // Allow guests by default since the room is private and they'd // need an invite. This means clicking on a 3pid invite email can // actually drop you right in to a chat. if (opts.guestAccess) { createOpts.initial_state.push({ type: "m.room.guest_access", state_key: "", content: { guest_access: "can_join" } }); } if (opts.encryption) { createOpts.initial_state.push({ type: "m.room.encryption", state_key: "", content: { algorithm: _crypto.MEGOLM_ENCRYPTION_ALGORITHM } }); } if (opts.joinRule === _matrix.JoinRule.Knock) { createOpts.room_version = _PreferredRoomVersions.PreferredRoomVersions.KnockRooms; } if (opts.parentSpace) { createOpts.initial_state.push((0, _space.makeSpaceParentEvent)(opts.parentSpace, true)); if (!opts.historyVisibility) { opts.historyVisibility = createOpts.preset === _matrix.Preset.PublicChat ? _matrix.HistoryVisibility.WorldReadable : _matrix.HistoryVisibility.Invited; } if (opts.joinRule === _matrix.JoinRule.Restricted) { createOpts.room_version = _PreferredRoomVersions.PreferredRoomVersions.RestrictedRooms; createOpts.initial_state.push({ type: _matrix.EventType.RoomJoinRules, content: { join_rule: _matrix.JoinRule.Restricted, allow: [{ type: _matrix.RestrictedAllowType.RoomMembership, room_id: opts.parentSpace.roomId }] } }); } } // we handle the restricted join rule in the parentSpace handling block above if (opts.joinRule && opts.joinRule !== _matrix.JoinRule.Restricted) { createOpts.initial_state.push({ type: _matrix.EventType.RoomJoinRules, content: { join_rule: opts.joinRule } }); } if (opts.avatar) { let url = opts.avatar; if (opts.avatar instanceof File) { ({ content_uri: url } = await client.uploadContent(opts.avatar)); } createOpts.initial_state.push({ type: _matrix.EventType.RoomAvatar, content: { url } }); } if (opts.historyVisibility) { createOpts.initial_state.push({ type: _matrix.EventType.RoomHistoryVisibility, content: { history_visibility: opts.historyVisibility } }); } let modal; if (opts.spinner) modal = _Modal.default.createDialog(_Spinner.default, undefined, "mx_Dialog_spinner"); let roomId; let room; return client.createRoom(createOpts).catch(function (err) { // NB This checks for the Synapse-specific error condition of a room creation // having been denied because the requesting user wanted to publish the room, // but the server denies them that permission (via room_list_publication_rules). // The check below responds by retrying without publishing the room. if (err.httpStatus === 403 && err.errcode === "M_UNKNOWN" && err.data.error === "Not allowed to publish room") { _logger.logger.warn("Failed to publish room, try again without publishing it"); createOpts.visibility = _matrix.Visibility.Private; return client.createRoom(createOpts); } else { return Promise.reject(err); } }).finally(function () { if (modal) modal.close(); }).then(async res => { roomId = res.room_id; room = new Promise(resolve => { const storedRoom = client.getRoom(roomId); if (storedRoom) { resolve(storedRoom); } else { // The room hasn't arrived down sync yet const onRoom = emittedRoom => { if (emittedRoom.roomId === roomId) { resolve(emittedRoom); client.off(_matrix.ClientEvent.Room, onRoom); } }; client.on(_matrix.ClientEvent.Room, onRoom); } }); if (opts.dmUserId) await Rooms.setDMRoom(client, roomId, opts.dmUserId); }).then(() => { if (opts.parentSpace) { return _SpaceStore.default.instance.addRoomToSpace(opts.parentSpace, roomId, [client.getDomain()], opts.suggested); } }).then(async () => { if (opts.roomType === _matrix.RoomType.ElementVideo) { // Set up this video room with a Jitsi call await _Call.JitsiCall.create(await room); // Reset our power level back to admin so that the widget becomes immutable await client.setPowerLevel(roomId, client.getUserId(), 100); } else if (opts.roomType === _matrix.RoomType.UnstableCall) { // Set up this video room with an Element call await _Call.ElementCall.create(await room); // Reset our power level back to admin so that the call becomes immutable await client.setPowerLevel(roomId, client.getUserId(), 100); } }).then(function () { // NB we haven't necessarily blocked on the room promise, so we race // here with the client knowing that the room exists, causing things // like https://github.com/vector-im/vector-web/issues/1813 // Even if we were to block on the echo, servers tend to split the room // state over multiple syncs so we can't atomically know when we have the // entire thing. if (opts.andView) { _dispatcher.default.dispatch({ action: _actions.Action.ViewRoom, room_id: roomId, should_peek: false, // Creating a room will have joined us to the room, // so we are expecting the room to come down the sync // stream, if it hasn't already. joining: true, justCreatedOpts: opts, metricsTrigger: "Created" }); } return roomId; }, function (err) { // Raise the error if the caller requested that we do so. if (opts.inlineErrors) throw err; // We also failed to join the room (this sets joining to false in RoomViewStore) _dispatcher.default.dispatch({ action: _actions.Action.JoinRoomError, roomId }); _logger.logger.error("Failed to create room " + roomId + " " + err); let description = (0, _languageHandler._t)("create_room|generic_error"); if (err.errcode === "M_UNSUPPORTED_ROOM_VERSION") { // Technically not possible with the UI as of April 2019 because there's no // options for the user to change this. However, it's not a bad thing to report // the error to the user for if/when the UI is available. description = (0, _languageHandler._t)("create_room|unsupported_version"); } _Modal.default.createDialog(_ErrorDialog.default, { title: (0, _languageHandler._t)("create_room|error_title"), description }); return null; }); } /* * Ensure that for every user in a room, there is at least one device that we * can encrypt to. */ async function canEncryptToAllUsers(client, userIds) { try { const usersDeviceMap = await client.getCrypto()?.getUserDeviceInfo(userIds, true); if (!usersDeviceMap) { return false; } for (const devices of usersDeviceMap.values()) { if (devices.size === 0) { // This user does not have any encryption-capable devices. return false; } } } catch (e) { _logger.logger.error("Error determining if it's possible to encrypt to all users: ", e); return false; // assume not } return true; } // Similar to ensureDMExists but also adds creation content // without polluting ensureDMExists with unrelated stuff (also // they're never encrypted). async function ensureVirtualRoomExists(client, userId, nativeRoomId) { const existingDMRoom = (0, _findDMForUser.findDMForUser)(client, userId); let roomId; if (existingDMRoom) { roomId = existingDMRoom.roomId; } else { roomId = await createRoom(client, { dmUserId: userId, spinner: false, andView: false, createOpts: { creation_content: { // This allows us to recognise that the room is a virtual room // when it comes down our sync stream (we also put the ID of the // respective native room in there because why not?) [_callTypes.VIRTUAL_ROOM_EVENT_TYPE]: nativeRoomId } } }); } return roomId; } async function ensureDMExists(client, userId) { const existingDMRoom = (0, _findDMForUser.findDMForUser)(client, userId); let roomId; if (existingDMRoom) { roomId = existingDMRoom.roomId; } else { let encryption; if ((0, _rooms.privateShouldBeEncrypted)(client)) { encryption = await canEncryptToAllUsers(client, [userId]); } roomId = await createRoom(client, { encryption, dmUserId: userId, spinner: false, andView: false }); if (!roomId) return null; await (0, _membership.waitForMember)(client, roomId, userId); } return roomId; } /** * Check if server configuration supports the user changing encryption for a room * First check if server features force enable encryption for the given room type * If not, check if server .well-known forces encryption to disabled * If either are forced, then do not allow the user to change room's encryption * @param client * @param chatPreset chat type * @returns Promise<boolean> */ async function checkUserIsAllowedToChangeEncryption(client, chatPreset) { const doesServerForceEncryptionForPreset = await client.doesServerForceEncryptionForPreset(chatPreset); const doesWellKnownForceDisableEncryption = (0, _shouldForceDisableEncryption.shouldForceDisableEncryption)(client); // server is forcing encryption to ENABLED // while .well-known config is forcing it to DISABLED // server version config overrides wk config if (doesServerForceEncryptionForPreset && doesWellKnownForceDisableEncryption) { console.warn(`Conflicting e2ee settings: server config and .well-known configuration disagree. Using server forced encryption setting for chat type ${chatPreset}`); } if (doesServerForceEncryptionForPreset) { return { allowChange: false, forcedValue: true }; } if (doesWellKnownForceDisableEncryption) { return { allowChange: false, forcedValue: false }; } return { allowChange: true }; } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbWF0cml4IiwicmVxdWlyZSIsIl9sb2dnZXIiLCJfTW9kYWwiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwiX2xhbmd1YWdlSGFuZGxlciIsIl9kaXNwYXRjaGVyIiwiUm9vbXMiLCJfaW50ZXJvcFJlcXVpcmVXaWxkY2FyZCIsIl9Vc2VyQWRkcmVzcyIsIl9jYWxsVHlwZXMiLCJfU3BhY2VTdG9yZSIsIl9zcGFjZSIsIl9DYWxsIiwiX2FjdGlvbnMiLCJfRXJyb3JEaWFsb2ciLCJfU3Bpbm5lciIsIl9maW5kRE1Gb3JVc2VyIiwiX3Jvb21zIiwiX3Nob3VsZEZvcmNlRGlzYWJsZUVuY3J5cHRpb24iLCJfbWVtYmVyc2hpcCIsIl9QcmVmZXJyZWRSb29tVmVyc2lvbnMiLCJfU2V0dGluZ3NTdG9yZSIsIl9jcnlwdG8iLCJfZ2V0UmVxdWlyZVdpbGRjYXJkQ2FjaGUiLCJlIiwiV2Vha01hcCIsInIiLCJ0IiwiX19lc01vZHVsZSIsImRlZmF1bHQiLCJoYXMiLCJnZXQiLCJuIiwiX19wcm90b19fIiwiYSIsIk9iamVjdCIsImRlZmluZVByb3BlcnR5IiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yIiwidSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsImkiLCJzZXQiLCJvd25LZXlzIiwia2V5cyIsImdldE93blByb3BlcnR5U3ltYm9scyIsIm8iLCJmaWx0ZXIiLCJlbnVtZXJhYmxlIiwicHVzaCIsImFwcGx5IiwiX29iamVjdFNwcmVhZCIsImFyZ3VtZW50cyIsImxlbmd0aCIsImZvckVhY2giLCJfZGVmaW5lUHJvcGVydHkyIiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9ycyIsImRlZmluZVByb3BlcnRpZXMiLCJERUZBVUxUX0VWRU5UX1BPV0VSX0xFVkVMUyIsIkV2ZW50VHlwZSIsIlJvb21OYW1lIiwiUm9vbUF2YXRhciIsIlJvb21Qb3dlckxldmVscyIsIlJvb21IaXN0b3J5VmlzaWJpbGl0eSIsIlJvb21DYW5vbmljYWxBbGlhcyIsIlJvb21Ub21ic3RvbmUiLCJSb29tU2VydmVyQWNsIiwiUm9vbUVuY3J5cHRpb24iLCJjcmVhdGVSb29tIiwiY2xpZW50Iiwib3B0cyIsInNwaW5uZXIiLCJ1bmRlZmluZWQiLCJndWVzdEFjY2VzcyIsImVuY3J5cHRpb24iLCJpc0d1ZXN0IiwiZGlzIiwiZGlzcGF0Y2giLCJhY3Rpb24iLCJkZWZhdWx0UHJlc2V0IiwiZG1Vc2VySWQiLCJQcmVzZXQiLCJUcnVzdGVkUHJpdmF0ZUNoYXQiLCJQcml2YXRlQ2hhdCIsImNyZWF0ZU9wdHMiLCJwcmVzZXQiLCJ2aXNpYmlsaXR5IiwiVmlzaWJpbGl0eSIsIlByaXZhdGUiLCJnZXRVc2VySWQiLCJpbnZpdGUiLCJnZXRBZGRyZXNzVHlwZSIsImlzVXJsIiwiZ2V0SWRlbnRpdHlTZXJ2ZXJVcmwiLCJVc2VyRnJpZW5kbHlFcnJvciIsImludml0ZV8zcGlkIiwiaWRfc2VydmVyIiwibWVkaXVtIiwiYWRkcmVzcyIsImlzX2RpcmVjdCIsInJvb21UeXBlIiwiY3JlYXRpb25fY29udGVudCIsIlJvb21DcmVhdGVUeXBlRmllbGQiLCJSb29tVHlwZSIsIkVsZW1lbnRWaWRlbyIsInBvd2VyX2xldmVsX2NvbnRlbnRfb3ZlcnJpZGUiLCJldmVudHMiLCJKaXRzaUNhbGwiLCJNRU1CRVJfRVZFTlRfVFlQRSIsInVzZXJzIiwiZ2V0U2FmZVVzZXJJZCIsIlVuc3RhYmxlQ2FsbCIsIkVsZW1lbnRDYWxsIiwibmFtZSIsIkNBTExfRVZFTlRfVFlQRSIsIlNldHRpbmdzU3RvcmUiLCJnZXRWYWx1ZSIsImFuZFZpZXciLCJpbml0aWFsX3N0YXRlIiwidHlwZSIsInN0YXRlX2tleSIsImNvbnRlbnQiLCJndWVzdF9hY2Nlc3MiLCJhbGdvcml0aG0iLCJNRUdPTE1fRU5DUllQVElPTl9BTEdPUklUSE0iLCJqb2luUnVsZSIsIkpvaW5SdWxlIiwiS25vY2siLCJyb29tX3ZlcnNpb24iLCJQcmVmZXJyZWRSb29tVmVyc2lvbnMiLCJLbm9ja1Jvb21zIiwicGFyZW50U3BhY2UiLCJtYWtlU3BhY2VQYXJlbnRFdmVudCIsImhpc3RvcnlWaXNpYmlsaXR5IiwiUHVibGljQ2hhdCIsIkhpc3RvcnlWaXNpYmlsaXR5IiwiV29ybGRSZWFkYWJsZSIsIkludml0ZWQiLCJSZXN0cmljdGVkIiwiUmVzdHJpY3RlZFJvb21zIiwiUm9vbUpvaW5SdWxlcyIsImpvaW5fcnVsZSIsImFsbG93IiwiUmVzdHJpY3RlZEFsbG93VHlwZSIsIlJvb21NZW1iZXJzaGlwIiwicm9vbV9pZCIsInJvb21JZCIsImF2YXRhciIsInVybCIsIkZpbGUiLCJjb250ZW50X3VyaSIsInVwbG9hZENvbnRlbnQiLCJoaXN0b3J5X3Zpc2liaWxpdHkiLCJtb2RhbCIsIk1vZGFsIiwiY3JlYXRlRGlhbG9nIiwiU3Bpbm5lciIsInJvb20iLCJjYXRjaCIsImVyciIsImh0dHBTdGF0dXMiLCJlcnJjb2RlIiwiZGF0YSIsImVycm9yIiwibG9nZ2VyIiwid2FybiIsIlByb21pc2UiLCJyZWplY3QiLCJmaW5hbGx5IiwiY2xvc2UiLCJ0aGVuIiwicmVzIiwicmVzb2x2ZSIsInN0b3JlZFJvb20iLCJnZXRSb29tIiwib25Sb29tIiwiZW1pdHRlZFJvb20iLCJvZmYiLCJDbGllbnRFdmVudCIsIlJvb20iLCJvbiIsInNldERNUm9vbSIsIlNwYWNlU3RvcmUiLCJpbnN0YW5jZSIsImFkZFJvb21Ub1NwYWNlIiwiZ2V0RG9tYWluIiwic3VnZ2VzdGVkIiwiY3JlYXRlIiwic2V0UG93ZXJMZXZlbCIsIkFjdGlvbiIsIlZpZXdSb29tIiwic2hvdWxkX3BlZWsiLCJqb2luaW5nIiwianVzdENyZWF0ZWRPcHRzIiwibWV0cmljc1RyaWdnZXIiLCJpbmxpbmVFcnJvcnMiLCJKb2luUm9vbUVycm9yIiwiZGVzY3JpcHRpb24iLCJfdCIsIkVycm9yRGlhbG9nIiwidGl0bGUiLCJjYW5FbmNyeXB0VG9BbGxVc2VycyIsInVzZXJJZHMiLCJ1c2Vyc0RldmljZU1hcCIsImdldENyeXB0byIsImdldFVzZXJEZXZpY2VJbmZvIiwiZGV2aWNlcyIsInZhbHVlcyIsInNpemUiLCJlbnN1cmVWaXJ0dWFsUm9vbUV4aXN0cyIsInVzZXJJZCIsIm5hdGl2ZVJvb21JZCIsImV4aXN0aW5nRE1Sb29tIiwiZmluZERNRm9yVXNlciIsIlZJUlRVQUxfUk9PTV9FVkVOVF9UWVBFIiwiZW5zdXJlRE1FeGlzdHMiLCJwcml2YXRlU2hvdWxkQmVFbmNyeXB0ZWQiLCJ3YWl0Rm9yTWVtYmVyIiwiY2hlY2tVc2VySXNBbGxvd2VkVG9DaGFuZ2VFbmNyeXB0aW9uIiwiY2hhdFByZXNldCIsImRvZXNTZXJ2ZXJGb3JjZUVuY3J5cHRpb25Gb3JQcmVzZXQiLCJkb2VzV2VsbEtub3duRm9yY2VEaXNhYmxlRW5jcnlwdGlvbiIsInNob3VsZEZvcmNlRGlzYWJsZUVuY3J5cHRpb24iLCJjb25zb2xlIiwiYWxsb3dDaGFuZ2UiLCJmb3JjZWRWYWx1ZSJdLCJzb3VyY2VzIjpbIi4uL3NyYy9jcmVhdGVSb29tLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAyNCBOZXcgVmVjdG9yIEx0ZC5cbkNvcHlyaWdodCAyMDE5LCAyMDIwIFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5Db3B5cmlnaHQgMjAxNSwgMjAxNiBPcGVuTWFya2V0IEx0ZFxuXG5TUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQUdQTC0zLjAtb25seSBPUiBHUEwtMy4wLW9ubHlcblBsZWFzZSBzZWUgTElDRU5TRSBmaWxlcyBpbiB0aGUgcmVwb3NpdG9yeSByb290IGZvciBmdWxsIGRldGFpbHMuXG4qL1xuXG5pbXBvcnQge1xuICAgIE1hdHJpeENsaWVudCxcbiAgICBDbGllbnRFdmVudCxcbiAgICBSb29tLFxuICAgIEV2ZW50VHlwZSxcbiAgICBSb29tQ3JlYXRlVHlwZUZpZWxkLFxuICAgIFJvb21UeXBlLFxuICAgIElDcmVhdGVSb29tT3B0cyxcbiAgICBIaXN0b3J5VmlzaWJpbGl0eSxcbiAgICBKb2luUnVsZSxcbiAgICBQcmVzZXQsXG4gICAgUmVzdHJpY3RlZEFsbG93VHlwZSxcbiAgICBWaXNpYmlsaXR5LFxufSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbWF0cml4XCI7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbG9nZ2VyXCI7XG5cbmltcG9ydCBNb2RhbCwgeyBJSGFuZGxlIH0gZnJvbSBcIi4vTW9kYWxcIjtcbmltcG9ydCB7IF90LCBVc2VyRnJpZW5kbHlFcnJvciB9IGZyb20gXCIuL2xhbmd1YWdlSGFuZGxlclwiO1xuaW1wb3J0IGRpcyBmcm9tIFwiLi9kaXNwYXRjaGVyL2Rpc3BhdGNoZXJcIjtcbmltcG9ydCAqIGFzIFJvb21zIGZyb20gXCIuL1Jvb21zXCI7XG5pbXBvcnQgeyBnZXRBZGRyZXNzVHlwZSB9IGZyb20gXCIuL1VzZXJBZGRyZXNzXCI7XG5pbXBvcnQgeyBWSVJUVUFMX1JPT01fRVZFTlRfVFlQRSB9IGZyb20gXCIuL2NhbGwtdHlwZXNcIjtcbmltcG9ydCBTcGFjZVN0b3JlIGZyb20gXCIuL3N0b3Jlcy9zcGFjZXMvU3BhY2VTdG9yZVwiO1xuaW1wb3J0IHsgbWFrZVNwYWNlUGFyZW50RXZlbnQgfSBmcm9tIFwiLi91dGlscy9zcGFjZVwiO1xuaW1wb3J0IHsgSml0c2lDYWxsLCBFbGVtZW50Q2FsbCB9IGZyb20gXCIuL21vZGVscy9DYWxsXCI7XG5pbXBvcnQgeyBBY3Rpb24gfSBmcm9tIFwiLi9kaXNwYXRjaGVyL2FjdGlvbnNcIjtcbmltcG9ydCBFcnJvckRpYWxvZyBmcm9tIFwiLi9jb21wb25lbnRzL3ZpZXdzL2RpYWxvZ3MvRXJyb3JEaWFsb2dcIjtcbmltcG9ydCBTcGlubmVyIGZyb20gXCIuL2NvbXBvbmVudHMvdmlld3MvZWxlbWVudHMvU3Bpbm5lclwiO1xuaW1wb3J0IHsgVmlld1Jvb21QYXlsb2FkIH0gZnJvbSBcIi4vZGlzcGF0Y2hlci9wYXlsb2Fkcy9WaWV3Um9vbVBheWxvYWRcIjtcbmltcG9ydCB7IGZpbmRETUZvclVzZXIgfSBmcm9tIFwiLi91dGlscy9kbS9maW5kRE1Gb3JVc2VyXCI7XG5pbXBvcnQgeyBwcml2YXRlU2hvdWxkQmVFbmNyeXB0ZWQgfSBmcm9tIFwiLi91dGlscy9yb29tc1wiO1xuaW1wb3J0IHsgc2hvdWxkRm9yY2VEaXNhYmxlRW5jcnlwdGlvbiB9IGZyb20gXCIuL3V0aWxzL2NyeXB0by9zaG91bGRGb3JjZURpc2FibGVFbmNyeXB0aW9uXCI7XG5pbXBvcnQgeyB3YWl0Rm9yTWVtYmVyIH0gZnJvbSBcIi4vdXRpbHMvbWVtYmVyc2hpcFwiO1xuaW1wb3J0IHsgUHJlZmVycmVkUm9vbVZlcnNpb25zIH0gZnJvbSBcIi4vdXRpbHMvUHJlZmVycmVkUm9vbVZlcnNpb25zXCI7XG5pbXBvcnQgU2V0dGluZ3NTdG9yZSBmcm9tIFwiLi9zZXR0aW5ncy9TZXR0aW5nc1N0b3JlXCI7XG5pbXBvcnQgeyBNRUdPTE1fRU5DUllQVElPTl9BTEdPUklUSE0gfSBmcm9tIFwiLi91dGlscy9jcnlwdG9cIjtcblxuLy8gd2UgZGVmaW5lIGEgbnVtYmVyIG9mIGludGVyZmFjZXMgd2hpY2ggdGFrZSB0aGVpciBuYW1lcyBmcm9tIHRoZSBqcy1zZGtcbi8qIGVzbGludC1kaXNhYmxlIGNhbWVsY2FzZSAqL1xuXG5leHBvcnQgaW50ZXJmYWNlIElPcHRzIHtcbiAgICBkbVVzZXJJZD86IHN0cmluZztcbiAgICBjcmVhdGVPcHRzPzogSUNyZWF0ZVJvb21PcHRzO1xuICAgIHNwaW5uZXI/OiBib29sZWFuO1xuICAgIGd1ZXN0QWNjZXNzPzogYm9vbGVhbjtcbiAgICBlbmNyeXB0aW9uPzogYm9vbGVhbjtcbiAgICBpbmxpbmVFcnJvcnM/OiBib29sZWFuO1xuICAgIGFuZFZpZXc/OiBib29sZWFuO1xuICAgIGF2YXRhcj86IEZpbGUgfCBzdHJpbmc7IC8vIHdpbGwgdXBsb2FkIGlmIGdpdmVuIGZpbGUsIGVsc2UgbXhjVXJsIGlzIG5lZWRlZFxuICAgIHJvb21UeXBlPzogUm9vbVR5cGUgfCBzdHJpbmc7XG4gICAgaGlzdG9yeVZpc2liaWxpdHk/OiBIaXN0b3J5VmlzaWJpbGl0eTtcbiAgICBwYXJlbnRTcGFjZT86IFJvb207XG4gICAgLy8gY29udGV4dHVhbGx5IG9ubHkgbWFrZXMgc2Vuc2UgaWYgcGFyZW50U3BhY2UgaXMgc3BlY2lmaWVkLCBpZiB0cnVlIHRoZW4gd2lsbCBiZSBhZGRlZCB0byBwYXJlbnRTcGFjZSBhcyBzdWdnZXN0ZWRcbiAgICBzdWdnZXN0ZWQ/OiBib29sZWFuO1xuICAgIGpvaW5SdWxlPzogSm9pblJ1bGU7XG59XG5cbmNvbnN0IERFRkFVTFRfRVZFTlRfUE9XRVJfTEVWRUxTID0ge1xuICAgIFtFdmVudFR5cGUuUm9vbU5hbWVdOiA1MCxcbiAgICBbRXZlbnRUeXBlLlJvb21BdmF0YXJdOiA1MCxcbiAgICBbRXZlbnRUeXBlLlJvb21Qb3dlckxldmVsc106IDEwMCxcbiAgICBbRXZlbnRUeXBlLlJvb21IaXN0b3J5VmlzaWJpbGl0eV06IDEwMCxcbiAgICBbRXZlbnRUeXBlLlJvb21DYW5vbmljYWxBbGlhc106IDUwLFxuICAgIFtFdmVudFR5cGUuUm9vbVRvbWJzdG9uZV06IDEwMCxcbiAgICBbRXZlbnRUeXBlLlJvb21TZXJ2ZXJBY2xdOiAxMDAsXG4gICAgW0V2ZW50VHlwZS5Sb29tRW5jcnlwdGlvbl06IDEwMCxcbn07XG5cbi8qKlxuICogQ3JlYXRlIGEgbmV3IHJvb20sIGFuZCBzd2l0Y2ggdG8gaXQuXG4gKlxuICogQHBhcmFtIGNsaWVudCBUaGUgTWF0cml4IENsaWVudCBpbnN0YW5jZSB0byBjcmVhdGUgdGhlIHJvb20gd2l0aFxuICogQHBhcmFtIHtvYmplY3Q9fSBvcHRzIHBhcmFtZXRlcnMgZm9yIGNyZWF0aW5nIHRoZSByb29tXG4gKiBAcGFyYW0ge3N0cmluZz19IG9wdHMuZG1Vc2VySWQgSWYgc3BlY2lmaWVkLCBtYWtlIHRoaXMgYSBETSByb29tIGZvciB0aGlzIHVzZXIgYW5kIGludml0ZSB0aGVtXG4gKiBAcGFyYW0ge29iamVjdD19IG9wdHMuY3JlYXRlT3B0cyBzZXQgb2Ygb3B0aW9ucyB0byBwYXNzIHRvIGNyZWF0ZVJvb20gY2FsbC5cbiAqIEBwYXJhbSB7Ym9vbD19IG9wdHMuc3Bpbm5lciBUcnVlIHRvIHNob3cgYSBtb2RhbCBzcGlubmVyIHdoaWxlIHRoZSByb29tIGlzIGNyZWF0ZWQuXG4gKiAgICAgRGVmYXVsdDogVHJ1ZVxuICogQHBhcmFtIHtib29sPX0gb3B0cy5ndWVzdEFjY2VzcyBXaGV0aGVyIHRvIGVuYWJsZSBndWVzdCBhY2Nlc3MuXG4gKiAgICAgRGVmYXVsdDogVHJ1ZVxuICogQHBhcmFtIHtib29sPX0gb3B0cy5lbmNyeXB0aW9uIFdoZXRoZXIgdG8gZW5hYmxlIGVuY3J5cHRpb24uXG4gKiAgICAgRGVmYXVsdDogRmFsc2VcbiAqIEBwYXJhbSB7Ym9vbD19IG9wdHMuaW5saW5lRXJyb3JzIFRydWUgdG8gcmFpc2UgZXJyb3JzIG9mZiB0aGUgcHJvbWlzZSBpbnN0ZWFkIG9mIHJlc29sdmluZyB0byBudWxsLlxuICogICAgIERlZmF1bHQ6IEZhbHNlXG4gKiBAcGFyYW0ge2Jvb2w9fSBvcHRzLmFuZFZpZXcgVHJ1ZSB0byBkaXNwYXRjaCBhbiBhY3Rpb24gdG8gdmlldyB0aGUgcm9vbSBvbmNlIGl0IGhhcyBiZWVuIGNyZWF0ZWQuXG4gKlxuICogQHJldHVybnMge1Byb21pc2V9IHdoaWNoIHJlc29sdmVzIHRvIHRoZSByb29tIGlkLCBvciBudWxsIGlmIHRoZVxuICogYWN0aW9uIHdhcyBhYm9ydGVkIG9yIGZhaWxlZC5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlUm9vbShjbGllbnQ6IE1hdHJpeENsaWVudCwgb3B0czogSU9wdHMpOiBQcm9taXNlPHN0cmluZyB8IG51bGw+IHtcbiAgICBvcHRzID0gb3B0cyB8fCB7fTtcbiAgICBpZiAob3B0cy5zcGlubmVyID09PSB1bmRlZmluZWQpIG9wdHMuc3Bpbm5lciA9IHRydWU7XG4gICAgaWYgKG9wdHMuZ3Vlc3RBY2Nlc3MgPT09IHVuZGVmaW5lZCkgb3B0cy5ndWVzdEFjY2VzcyA9IHRydWU7XG4gICAgaWYgKG9wdHMuZW5jcnlwdGlvbiA9PT0gdW5kZWZpbmVkKSBvcHRzLmVuY3J5cHRpb24gPSBmYWxzZTtcblxuICAgIGlmIChjbGllbnQuaXNHdWVzdCgpKSB7XG4gICAgICAgIGRpcy5kaXNwYXRjaCh7IGFjdGlvbjogXCJyZXF1aXJlX3JlZ2lzdHJhdGlvblwiIH0pO1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBjb25zdCBkZWZhdWx0UHJlc2V0ID0gb3B0cy5kbVVzZXJJZCA/IFByZXNldC5UcnVzdGVkUHJpdmF0ZUNoYXQgOiBQcmVzZXQuUHJpdmF0ZUNoYXQ7XG5cbiAgICAvLyBzZXQgc29tZSBkZWZhdWx0cyBmb3IgdGhlIGNyZWF0aW9uXG4gICAgY29uc3QgY3JlYXRlT3B0czogSUNyZWF0ZVJvb21PcHRzID0gb3B0cy5jcmVhdGVPcHRzIHx8IHt9O1xuICAgIGNyZWF0ZU9wdHMucHJlc2V0ID0gY3JlYXRlT3B0cy5wcmVzZXQgfHwgZGVmYXVsdFByZXNldDtcbiAgICBjcmVhdGVPcHRzLnZpc2liaWxpdHkgPSBjcmVhdGVPcHRzLnZpc2liaWxpdHkgfHwgVmlzaWJpbGl0eS5Qcml2YXRlO1xuXG4gICAgLy8gV2UgYWxsb3cgVVggb2YgRE1pbmcgb3Vyc2VsdmVzIGFzIGEgZm9ybSBvZiBjcmVhdGluZyBhIHBlcnNvbmFsIHJvb20gYnV0IHRoZSBzZXJ2ZXIgdGhyb3dzXG4gICAgLy8gYW4gZXJyb3Igd2hlbiBhIHVzZXIgdHJpZXMgdG8gaW52aXRlIHRoZW1zZWx2ZXMgc28gd2UgZmlsdGVyIGl0IG91dFxuICAgIGlmIChvcHRzLmRtVXNlcklkICYmIG9wdHMuZG1Vc2VySWQgIT09IGNsaWVudC5nZXRVc2VySWQoKSAmJiBjcmVhdGVPcHRzLmludml0ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHN3aXRjaCAoZ2V0QWRkcmVzc1R5cGUob3B0cy5kbVVzZXJJZCkpIHtcbiAgICAgICAgICAgIGNhc2UgXCJteC11c2VyLWlkXCI6XG4gICAgICAgICAgICAgICAgY3JlYXRlT3B0cy5pbnZpdGUgPSBbb3B0cy5kbVVzZXJJZF07XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwiZW1haWxcIjoge1xuICAgICAgICAgICAgICAgIGNvbnN0IGlzVXJsID0gY2xpZW50LmdldElkZW50aXR5U2VydmVyVXJsKHRydWUpO1xuICAgICAgICAgICAgICAgIGlmICghaXNVcmwpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IFVzZXJGcmllbmRseUVycm9yKFwiY2Fubm90X2ludml0ZV93aXRob3V0X2lkZW50aXR5X3NlcnZlclwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY3JlYXRlT3B0cy5pbnZpdGVfM3BpZCA9IFtcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWRfc2VydmVyOiBpc1VybCxcbiAgICAgICAgICAgICAgICAgICAgICAgIG1lZGl1bTogXCJlbWFpbFwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgYWRkcmVzczogb3B0cy5kbVVzZXJJZCxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBdO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIGlmIChvcHRzLmRtVXNlcklkICYmIGNyZWF0ZU9wdHMuaXNfZGlyZWN0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgY3JlYXRlT3B0cy5pc19kaXJlY3QgPSB0cnVlO1xuICAgIH1cblxuICAgIGlmIChvcHRzLnJvb21UeXBlKSB7XG4gICAgICAgIGNyZWF0ZU9wdHMuY3JlYXRpb25fY29udGVudCA9IHtcbiAgICAgICAgICAgIC4uLmNyZWF0ZU9wdHMuY3JlYXRpb25fY29udGVudCxcbiAgICAgICAgICAgIFtSb29tQ3JlYXRlVHlwZUZpZWxkXTogb3B0cy5yb29tVHlwZSxcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBWaWRlbyByb29tcyByZXF1aXJlIGN1c3RvbSBwb3dlciBsZXZlbHNcbiAgICAgICAgaWYgKG9wdHMucm9vbVR5cGUgPT09IFJvb21UeXBlLkVsZW1lbnRWaWRlbykge1xuICAgICAgICAgICAgY3JlYXRlT3B0cy5wb3dlcl9sZXZlbF9jb250ZW50X292ZXJyaWRlID0ge1xuICAgICAgICAgICAgICAgIGV2ZW50czoge1xuICAgICAgICAgICAgICAgICAgICAuLi5ERUZBVUxUX0VWRU5UX1BPV0VSX0xFVkVMUyxcbiAgICAgICAgICAgICAgICAgICAgLy8gQWxsb3cgYWxsIHVzZXJzIHRvIHNlbmQgY2FsbCBtZW1iZXJzaGlwIHVwZGF0ZXNcbiAgICAgICAgICAgICAgICAgICAgW0ppdHNpQ2FsbC5NRU1CRVJfRVZFTlRfVFlQRV06IDAsXG4gICAgICAgICAgICAgICAgICAgIC8vIE1ha2Ugd2lkZ2V0cyBpbW11dGFibGUsIGV2ZW4gdG8gYWRtaW5zXG4gICAgICAgICAgICAgICAgICAgIFwiaW0udmVjdG9yLm1vZHVsYXIud2lkZ2V0c1wiOiAyMDAsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB1c2Vyczoge1xuICAgICAgICAgICAgICAgICAgICAvLyBUZW1wb3JhcmlseSBnaXZlIG91cnNlbHZlcyB0aGUgcG93ZXIgdG8gc2V0IHVwIGEgd2lkZ2V0XG4gICAgICAgICAgICAgICAgICAgIFtjbGllbnQuZ2V0U2FmZVVzZXJJZCgpXTogMjAwLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9O1xuICAgICAgICB9IGVsc2UgaWYgKG9wdHMucm9vbVR5cGUgPT09IFJvb21UeXBlLlVuc3RhYmxlQ2FsbCkge1xuICAgICAgICAgICAgY3JlYXRlT3B0cy5wb3dlcl9sZXZlbF9jb250ZW50X292ZXJyaWRlID0ge1xuICAgICAgICAgICAgICAgIGV2ZW50czoge1xuICAgICAgICAgICAgICAgICAgICAuLi5ERUZBVUxUX0VWRU5UX1BPV0VSX0xFVkVMUyxcbiAgICAgICAgICAgICAgICAgICAgLy8gQWxsb3cgYWxsIHVzZXJzIHRvIHNlbmQgY2FsbCBtZW1iZXJzaGlwIHVwZGF0ZXNcbiAgICAgICAgICAgICAgICAgICAgW0VsZW1lbnRDYWxsLk1FTUJFUl9FVkVOVF9UWVBFLm5hbWVdOiAwLFxuICAgICAgICAgICAgICAgICAgICAvLyBNYWtlIGNhbGxzIGltbXV0YWJsZSwgZXZlbiB0byBhZG1pbnNcbiAgICAgICAgICAgICAgICAgICAgW0VsZW1lbnRDYWxsLkNBTExfRVZFTlRfVFlQRS5uYW1lXTogMjAwLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgdXNlcnM6IHtcbiAgICAgICAgICAgICAgICAgICAgLy8gVGVtcG9yYXJpbHkgZ2l2ZSBvdXJzZWx2ZXMgdGhlIHBvd2VyIHRvIHNldCB1cCBhIGNhbGxcbiAgICAgICAgICAgICAgICAgICAgW2NsaWVudC5nZXRTYWZlVXNlcklkKCldOiAyMDAsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICB9IGVsc2UgaWYgKFNldHRpbmdzU3RvcmUuZ2V0VmFsdWUoXCJmZWF0dXJlX2dyb3VwX2NhbGxzXCIpKSB7XG4gICAgICAgIGNyZWF0ZU9wdHMucG93ZXJfbGV2ZWxfY29udGVudF9vdmVycmlkZSA9IHtcbiAgICAgICAgICAgIGV2ZW50czoge1xuICAgICAgICAgICAgICAgIC4uLkRFRkFVTFRfRVZFTlRfUE9XRVJfTEVWRUxTLFxuICAgICAgICAgICAgICAgIC8vIEl0IHNob3VsZCBhbHdheXMgKGluY2x1ZGluZyBub24gdmlkZW8gcm9vbXMpIGJlIHBvc3NpYmxlIHRvIGpvaW4gYSBncm91cCBjYWxsLlxuICAgICAgICAgICAgICAgIFtFbGVtZW50Q2FsbC5NRU1CRVJfRVZFTlRfVFlQRS5uYW1lXTogMCxcbiAgICAgICAgICAgICAgICAvLyBNYWtlIHN1cmUgb25seSBhZG1pbnMgY2FuIGVuYWJsZSBpdCAoREVQUkVDQVRFRClcbiAgICAgICAgICAgICAgICBbRWxlbWVudENhbGwuQ0FMTF9FVkVOVF9UWVBFLm5hbWVdOiAxMDAsXG4gICAgICAgICAgICB9LFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIC8vIEJ5IGRlZmF1bHQsIHZpZXcgdGhlIHJvb20gYWZ0ZXIgY3JlYXRpbmcgaXRcbiAgICBpZiAob3B0cy5hbmRWaWV3ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgb3B0cy5hbmRWaWV3ID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBjcmVhdGVPcHRzLmluaXRpYWxfc3RhdGUgPSBjcmVhdGVPcHRzLmluaXRpYWxfc3RhdGUgfHwgW107XG5cbiAgICAvLyBBbGxvdyBndWVzdHMgYnkgZGVmYXVsdCBzaW5jZSB0aGUgcm9vbSBpcyBwcml2YXRlIGFuZCB0aGV5J2RcbiAgICAvLyBuZWVkIGFuIGludml0ZS4gVGhpcyBtZWFucyBjbGlja2luZyBvbiBhIDNwaWQgaW52aXRlIGVtYWlsIGNhblxuICAgIC8vIGFjdHVhbGx5IGRyb3AgeW91IHJpZ2h0IGluIHRvIGEgY2hhdC5cbiAgICBpZiAob3B0cy5ndWVzdEFjY2Vzcykge1xuICAgICAgICBjcmVhdGVPcHRzLmluaXRpYWxfc3RhdGUucHVzaCh7XG4gICAgICAgICAgICB0eXBlOiBcIm0ucm9vbS5ndWVzdF9hY2Nlc3NcIixcbiAgICAgICAgICAgIHN0YXRlX2tleTogXCJcIixcbiAgICAgICAgICAgIGNvbnRlbnQ6IHtcbiAgICAgICAgICAgICAgICBndWVzdF9hY2Nlc3M6IFwiY2FuX2pvaW5cIixcbiAgICAgICAgICAgIH0sXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChvcHRzLmVuY3J5cHRpb24pIHtcbiAgICAgICAgY3JlYXRlT3B0cy5pbml0aWFsX3N0YXRlLnB1c2goe1xuICAgICAgICAgICAgdHlwZTogXCJtLnJvb20uZW5jcnlwdGlvblwiLFxuICAgICAgICAgICAgc3RhdGVfa2V5OiBcIlwiLFxuICAgICAgICAgICAgY29udGVudDoge1xuICAgICAgICAgICAgICAgIGFsZ29yaXRobTogTUVHT0xNX0VOQ1JZUFRJT05fQUxHT1JJVEhNLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKG9wdHMuam9pblJ1bGUgPT09IEpvaW5SdWxlLktub2NrKSB7XG4gICAgICAgIGNyZWF0ZU9wdHMucm9vbV92ZXJzaW9uID0gUHJlZmVycmVkUm9vbVZlcnNpb25zLktub2NrUm9vbXM7XG4gICAgfVxuXG4gICAgaWYgKG9wdHMucGFyZW50U3BhY2UpIHtcbiAgICAgICAgY3JlYXRlT3B0cy5pbml0aWFsX3N0YXRlLnB1c2gobWFrZVNwYWNlUGFyZW50RXZlbnQob3B0cy5wYXJlbnRTcGFjZSwgdHJ1ZSkpO1xuICAgICAgICBpZiAoIW9wdHMuaGlzdG9yeVZpc2liaWxpdHkpIHtcbiAgICAgICAgICAgIG9wdHMuaGlzdG9yeVZpc2liaWxpdHkgPVxuICAgICAgICAgICAgICAgIGNyZWF0ZU9wdHMucHJlc2V0ID09PSBQcmVzZXQuUHVibGljQ2hhdCA/IEhpc3RvcnlWaXNpYmlsaXR5LldvcmxkUmVhZGFibGUgOiBIaXN0b3J5VmlzaWJpbGl0eS5JbnZpdGVkO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKG9wdHMuam9pblJ1bGUgPT09IEpvaW5SdWxlLlJlc3RyaWN0ZWQpIHtcbiAgICAgICAgICAgIGNyZWF0ZU9wdHMucm9vbV92ZXJzaW9uID0gUHJlZmVycmVkUm9vbVZlcnNpb25zLlJlc3RyaWN0ZWRSb29tcztcblxuICAgICAgICAgICAgY3JlYXRlT3B0cy5pbml0aWFsX3N0YXRlLnB1c2goe1xuICAgICAgICAgICAgICAgIHR5cGU6IEV2ZW50VHlwZS5Sb29tSm9pblJ1bGVzLFxuICAgICAgICAgICAgICAgIGNvbnRlbnQ6IHtcbiAgICAgICAgICAgICAgICAgICAgam9pbl9ydWxlOiBKb2luUnVsZS5SZXN0cmljdGVkLFxuICAgICAgICAgICAgICAgICAgICBhbGxvdzogW1xuICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6IFJlc3RyaWN0ZWRBbGxvd1R5cGUuUm9vbU1lbWJlcnNoaXAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcm9vbV9pZDogb3B0cy5wYXJlbnRTcGFjZS5yb29tSWQsXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIHdlIGhhbmRsZSB0aGUgcmVzdHJpY3RlZCBqb2luIHJ1bGUgaW4gdGhlIHBhcmVudFNwYWNlIGhhbmRsaW5nIGJsb2NrIGFib3ZlXG4gICAgaWYgKG9wdHMuam9pblJ1bGUgJiYgb3B0cy5qb2luUnVsZSAhPT0gSm9pblJ1bGUuUmVzdHJpY3RlZCkge1xuICAgICAgICBjcmVhdGVPcHRzLmluaXRpYWxfc3RhdGUucHVzaCh7XG4gICAgICAgICAgICB0eXBlOiBFdmVudFR5cGUuUm9vbUpvaW5SdWxlcyxcbiAgICAgICAgICAgIGNvbnRlbnQ6IHsgam9pbl9ydWxlOiBvcHRzLmpvaW5SdWxlIH0sXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChvcHRzLmF2YXRhcikge1xuICAgICAgICBsZXQgdXJsID0gb3B0cy5hdmF0YXI7XG4gICAgICAgIGlmIChvcHRzLmF2YXRhciBpbnN0YW5jZW9mIEZpbGUpIHtcbiAgICAgICAgICAgICh7IGNvbnRlbnRfdXJpOiB1cmwgfSA9IGF3YWl0IGNsaWVudC51cGxvYWRDb250ZW50KG9wdHMuYXZhdGFyKSk7XG4gICAgICAgIH1cblxuICAgICAgICBjcmVhdGVPcHRzLmluaXRpYWxfc3RhdGUucHVzaCh7XG4gICAgICAgICAgICB0eXBlOiBFdmVudFR5cGUuUm9vbUF2YXRhcixcbiAgICAgICAgICAgIGNvbnRlbnQ6IHsgdXJsIH0sXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChvcHRzLmhpc3RvcnlWaXNpYmlsaXR5KSB7XG4gICAgICAgIGNyZWF0ZU9wdHMuaW5pdGlhbF9zdGF0ZS5wdXNoKHtcbiAgICAgICAgICAgIHR5cGU6IEV2ZW50VHlwZS5Sb29tSGlzdG9yeVZpc2liaWxpdHksXG4gICAgICAgICAgICBjb250ZW50OiB7XG4gICAgICAgICAgICAgICAgaGlzdG9yeV92aXNpYmlsaXR5OiBvcHRzLmhpc3RvcnlWaXNpYmlsaXR5LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgbGV0IG1vZGFsOiBJSGFuZGxlPGFueT4gfCB1bmRlZmluZWQ7XG4gICAgaWYgKG9wdHMuc3Bpbm5lcikgbW9kYWwgPSBNb2RhbC5jcmVhdGVEaWFsb2coU3Bpbm5lciwgdW5kZWZpbmVkLCBcIm14X0RpYWxvZ19zcGlubmVyXCIpO1xuXG4gICAgbGV0IHJvb21JZDogc3RyaW5nO1xuICAgIGxldCByb29tOiBQcm9taXNlPFJvb20+O1xuICAgIHJldHVybiBjbGllbnRcbiAgICAgICAgLmNyZWF0ZVJvb20oY3JlYXRlT3B0cylcbiAgICAgICAgLmNhdGNoKGZ1bmN0aW9uIChlcnIpIHtcbiAgICAgICAgICAgIC8vIE5CIFRoaXMgY2hlY2tzIGZvciB0aGUgU3luYXBzZS1zcGVjaWZpYyBlcnJvciBjb25kaXRpb24gb2YgYSByb29tIGNyZWF0aW9uXG4gICAgICAgICAgICAvLyBoYXZpbmcgYmVlbiBkZW5pZWQgYmVjYXVzZSB0aGUgcmVxdWVzdGluZyB1c2VyIHdhbnRlZCB0byBwdWJsaXNoIHRoZSByb29tLFxuICAgICAgICAgICAgLy8gYnV0IHRoZSBzZXJ2ZXIgZGVuaWVzIHRoZW0gdGhhdCBwZXJtaXNzaW9uICh2aWEgcm9vbV9saXN0X3B1YmxpY2F0aW9uX3J1bGVzKS5cbiAgICAgICAgICAgIC8vIFRoZSBjaGVjayBiZWxvdyByZXNwb25kcyBieSByZXRyeWluZyB3aXRob3V0IHB1Ymxpc2hpbmcgdGhlIHJvb20uXG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgZXJyLmh0dHBTdGF0dXMgPT09IDQwMyAmJlxuICAgICAgICAgICAgICAgIGVyci5lcnJjb2RlID09PSBcIk1fVU5LTk9XTlwiICYmXG4gICAgICAgICAgICAgICAgZXJyLmRhdGEuZXJyb3IgPT09IFwiTm90IGFsbG93ZWQgdG8gcHVibGlzaCByb29tXCJcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIGxvZ2dlci53YXJuKFwiRmFpbGVkIHRvIHB1Ymxpc2ggcm9vbSwgdHJ5IGFnYWluIHdpdGhvdXQgcHVibGlzaGluZyBpdFwiKTtcbiAgICAgICAgICAgICAgICBjcmVhdGVPcHRzLnZpc2liaWxpdHkgPSBWaXNpYmlsaXR5LlByaXZhdGU7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGNsaWVudC5jcmVhdGVSb29tKGNyZWF0ZU9wdHMpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoZXJyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICAgICAgLmZpbmFsbHkoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKG1vZGFsKSBtb2RhbC5jbG9zZSgpO1xuICAgICAgICB9KVxuICAgICAgICAudGhlbihhc3luYyAocmVzKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgICAgICByb29tSWQgPSByZXMucm9vbV9pZDtcblxuICAgICAgICAgICAgcm9vbSA9IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3Qgc3RvcmVkUm9vbSA9IGNsaWVudC5nZXRSb29tKHJvb21JZCk7XG4gICAgICAgICAgICAgICAgaWYgKHN0b3JlZFJvb20pIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZShzdG9yZWRSb29tKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAvLyBUaGUgcm9vbSBoYXNuJ3QgYXJyaXZlZCBkb3duIHN5bmMgeWV0XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG9uUm9vbSA9IChlbWl0dGVkUm9vbTogUm9vbSk6IHZvaWQgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVtaXR0ZWRSb29tLnJvb21JZCA9PT0gcm9vbUlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZShlbWl0dGVkUm9vbSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xpZW50Lm9mZihDbGllbnRFdmVudC5Sb29tLCBvblJvb20pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICBjbGllbnQub24oQ2xpZW50RXZlbnQuUm9vbSwgb25Sb29tKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgaWYgKG9wdHMuZG1Vc2VySWQpIGF3YWl0IFJvb21zLnNldERNUm9vbShjbGllbnQsIHJvb21JZCwgb3B0cy5kbVVzZXJJZCk7XG4gICAgICAgIH0pXG4gICAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgICAgIGlmIChvcHRzLnBhcmVudFNwYWNlKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFNwYWNlU3RvcmUuaW5zdGFuY2UuYWRkUm9vbVRvU3BhY2UoXG4gICAgICAgICAgICAgICAgICAgIG9wdHMucGFyZW50U3BhY2UsXG4gICAgICAgICAgICAgICAgICAgIHJvb21JZCxcbiAgICAgICAgICAgICAgICAgICAgW2NsaWVudC5nZXREb21haW4oKSFdLFxuICAgICAgICAgICAgICAgICAgICBvcHRzLnN1Z2dlc3RlZCxcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KVxuICAgICAgICAudGhlbihhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgICAgICBpZiAob3B0cy5yb29tVHlwZSA9PT0gUm9vbVR5cGUuRWxlbWVudFZpZGVvKSB7XG4gICAgICAgICAgICAgICAgLy8gU2V0IHVwIHRoaXMgdmlkZW8gcm9vbSB3aXRoIGEgSml0c2kgY2FsbFxuICAgICAgICAgICAgICAgIGF3YWl0IEppdHNpQ2FsbC5jcmVhdGUoYXdhaXQgcm9vbSk7XG5cbiAgICAgICAgICAgICAgICAvLyBSZXNldCBvdXIgcG93ZXIgbGV2ZWwgYmFjayB0byBhZG1pbiBzbyB0aGF0IHRoZSB3aWRnZXQgYmVjb21lcyBpbW11dGFibGVcbiAgICAgICAgICAgICAgICBhd2FpdCBjbGllbnQuc2V0UG93ZXJMZXZlbChyb29tSWQsIGNsaWVudC5nZXRVc2VySWQoKSEsIDEwMCk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKG9wdHMucm9vbVR5cGUgPT09IFJvb21UeXBlLlVuc3RhYmxlQ2FsbCkge1xuICAgICAgICAgICAgICAgIC8vIFNldCB1cCB0aGlzIHZpZGVvIHJvb20gd2l0aCBhbiBFbGVtZW50IGNhbGxcbiAgICAgICAgICAgICAgICBhd2FpdCBFbGVtZW50Q2FsbC5jcmVhdGUoYXdhaXQgcm9vbSk7XG5cbiAgICAgICAgICAgICAgICAvLyBSZXNldCBvdXIgcG93ZXIgbGV2ZWwgYmFjayB0byBhZG1pbiBzbyB0aGF0IHRoZSBjYWxsIGJlY29tZXMgaW1tdXRhYmxlXG4gICAgICAgICAgICAgICAgYXdhaXQgY2xpZW50LnNldFBvd2VyTGV2ZWwocm9vbUlkLCBjbGllbnQuZ2V0VXNlcklkKCkhLCAxMDApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KVxuICAgICAgICAudGhlbihcbiAgICAgICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyBOQiB3ZSBoYXZlbid0IG5lY2Vzc2FyaWx5IGJsb2NrZWQgb24gdGhlIHJvb20gcHJvbWlzZSwgc28gd2UgcmFjZVxuICAgICAgICAgICAgICAgIC8vIGhlcmUgd2l0aCB0aGUgY2xpZW50IGtub3dpbmcgdGhhdCB0aGUgcm9vbSBleGlzdHMsIGNhdXNpbmcgdGhpbmdzXG4gICAgICAgICAgICAgICAgLy8gbGlrZSBodHRwczovL2dpdGh1Yi5jb20vdmVjdG9yLWltL3ZlY3Rvci13ZWIvaXNzdWVzLzE4MTNcbiAgICAgICAgICAgICAgICAvLyBFdmVuIGlmIHdlIHdlcmUgdG8gYmxvY2sgb24gdGhlIGVjaG8sIHNlcnZlcnMgdGVuZCB0byBzcGxpdCB0aGUgcm9vbVxuICAgICAgICAgICAgICAgIC8vIHN0YXRlIG92ZXIgbXVsdGlwbGUgc3luY3Mgc28gd2UgY2FuJ3QgYXRvbWljYWxseSBrbm93IHdoZW4gd2UgaGF2ZSB0aGVcbiAgICAgICAgICAgICAgICAvLyBlbnRpcmUgdGhpbmcuXG4gICAgICAgICAgICAgICAgaWYgKG9wdHMuYW5kVmlldykge1xuICAgICAgICAgICAgICAgICAgICBkaXMuZGlzcGF0Y2g8Vmlld1Jvb21QYXlsb2FkPih7XG4gICAgICAgICAgICAgICAgICAgICAgICBhY3Rpb246IEFjdGlvbi5WaWV3Um9vbSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJvb21faWQ6IHJvb21JZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNob3VsZF9wZWVrOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIENyZWF0aW5nIGEgcm9vbSB3aWxsIGhhdmUgam9pbmVkIHVzIHRvIHRoZSByb29tLFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gc28gd2UgYXJlIGV4cGVjdGluZyB0aGUgcm9vbSB0byBjb21lIGRvd24gdGhlIHN5bmNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHN0cmVhbSwgaWYgaXQgaGFzbid0IGFscmVhZHkuXG4gICAgICAgICAgICAgICAgICAgICAgICBqb2luaW5nOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICAgICAganVzdENyZWF0ZWRPcHRzOiBvcHRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgbWV0cmljc1RyaWdnZXI6IFwiQ3JlYXRlZFwiLFxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJvb21JZDtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBmdW5jdGlvbiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgLy8gUmFpc2UgdGhlIGVycm9yIGlmIHRoZSBjYWxsZXIgcmVxdWVzdGVkIHRoYXQgd2UgZG8gc28uXG4gICAgICAgICAgICAgICAgaWYgKG9wdHMuaW5saW5lRXJyb3JzKSB0aHJvdyBlcnI7XG5cbiAgICAgICAgICAgICAgICAvLyBXZSBhbHNvIGZhaWxlZCB0byBqb2luIHRoZSByb29tICh0aGlzIHNldHMgam9pbmluZyB0byBmYWxzZSBpbiBSb29tVmlld1N0b3JlKVxuICAgICAgICAgICAgICAgIGRpcy5kaXNwYXRjaCh7XG4gICAgICAgICAgICAgICAgICAgIGFjdGlvbjogQWN0aW9uLkpvaW5Sb29tRXJyb3IsXG4gICAgICAgICAgICAgICAgICAgIHJvb21JZCxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBsb2dnZXIuZXJyb3IoXCJGYWlsZWQgdG8gY3JlYXRlIHJvb20gXCIgKyByb29tSWQgKyBcIiBcIiArIGVycik7XG4gICAgICAgICAgICAgICAgbGV0IGRlc2NyaXB0aW9uID0gX3QoXCJjcmVhdGVfcm9vbXxnZW5lcmljX2Vycm9yXCIpO1xuICAgICAgICAgICAgICAgIGlmIChlcnIuZXJyY29kZSA9PT0gXCJNX1VOU1VQUE9SVEVEX1JPT01fVkVSU0lPTlwiKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFRlY2huaWNhbGx5IG5vdCBwb3NzaWJsZSB3aXRoIHRoZSBVSSBhcyBvZiBBcHJpbCAyMDE5IGJlY2F1c2UgdGhlcmUncyBub1xuICAgICAgICAgICAgICAgICAgICAvLyBvcHRpb25zIGZvciB0aGUgdXNlciB0byBjaGFuZ2UgdGhpcy4gSG93ZXZlciwgaXQncyBub3QgYSBiYWQgdGhpbmcgdG8gcmVwb3J0XG4gICAgICAgICAgICAgICAgICAgIC8vIHRoZSBlcnJvciB0byB0aGUgdXNlciBmb3IgaWYvd2hlbiB0aGUgVUkgaXMgYXZhaWxhYmxlLlxuICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbiA9IF90KFwiY3JlYXRlX3Jvb218dW5zdXBwb3J0ZWRfdmVyc2lvblwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgTW9kYWwuY3JlYXRlRGlhbG9nKEVycm9yRGlhbG9nLCB7XG4gICAgICAgICAgICAgICAgICAgIHRpdGxlOiBfdChcImNyZWF0ZV9yb29tfGVycm9yX3RpdGxlXCIpLFxuICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbixcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICk7XG59XG5cbi8qXG4gKiBFbnN1cmUgdGhhdCBmb3IgZXZlcnkgdXNlciBpbiBhIHJvb20sIHRoZXJlIGlzIGF0IGxlYXN0IG9uZSBkZXZpY2UgdGhhdCB3ZVxuICogY2FuIGVuY3J5cHQgdG8uXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjYW5FbmNyeXB0VG9BbGxVc2VycyhjbGllbnQ6IE1hdHJpeENsaWVudCwgdXNlcklkczogc3RyaW5nW10pOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICB0cnkge1xuICAgICAgICBjb25zdCB1c2Vyc0RldmljZU1hcCA9IGF3YWl0IGNsaWVudC5nZXRDcnlwdG8oKT8uZ2V0VXNlckRldmljZUluZm8odXNlcklkcywgdHJ1ZSk7XG4gICAgICAgIGlmICghdXNlcnNEZXZpY2VNYXApIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZvciAoY29uc3QgZGV2aWNlcyBvZiB1c2Vyc0RldmljZU1hcC52YWx1ZXMoKSkge1xuICAgICAgICAgICAgaWYgKGRldmljZXMuc2l6ZSA9PT0gMCkge1xuICAgICAgICAgICAgICAgIC8vIFRoaXMgdXNlciBkb2VzIG5vdCBoYXZlIGFueSBlbmNyeXB0aW9uLWNhcGFibGUgZGV2aWNlcy5cbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGxvZ2dlci5lcnJvcihcIkVycm9yIGRldGVybWluaW5nIGlmIGl0J3MgcG9zc2libGUgdG8gZW5jcnlwdCB0byBhbGwgdXNlcnM6IFwiLCBlKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlOyAvLyBhc3N1bWUgbm90XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG59XG5cbi8vIFNpbWlsYXIgdG8gZW5zdXJlRE1FeGlzdHMgYnV0IGFsc28gYWRkcyBjcmVhdGlvbiBjb250ZW50XG4vLyB3aXRob3V0IHBvbGx1dGluZyBlbnN1cmVETUV4aXN0cyB3aXRoIHVucmVsYXRlZCBzdHVmZiAoYWxzb1xuLy8gdGhleSdyZSBuZXZlciBlbmNyeXB0ZWQpLlxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGVuc3VyZVZpcnR1YWxSb29tRXhpc3RzKFxuICAgIGNsaWVudDogTWF0cml4Q2xpZW50LFxuICAgIHVzZXJJZDogc3RyaW5nLFxuICAgIG5hdGl2ZVJvb21JZDogc3RyaW5nLFxuKTogUHJvbWlzZTxzdHJpbmcgfCBudWxsPiB7XG4gICAgY29uc3QgZXhpc3RpbmdETVJvb20gPSBmaW5kRE1Gb3JVc2VyKGNsaWVudCwgdXNlcklkKTtcbiAgICBsZXQgcm9vbUlkOiBzdHJpbmcgfCBudWxsO1xuICAgIGlmIChleGlzdGluZ0RNUm9vbSkge1xuICAgICAgICByb29tSWQgPSBleGlzdGluZ0RNUm9vbS5yb29tSWQ7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgcm9vbUlkID0gYXdhaXQgY3JlYXRlUm9vbShjbGllbnQsIHtcbiAgICAgICAgICAgIGRtVXNlcklkOiB1c2VySWQsXG4gICAgICAgICAgICBzcGlubmVyOiBmYWxzZSxcbiAgICAgICAgICAgIGFuZFZpZXc6IGZhbHNlLFxuICAgICAgICAgICAgY3JlYXRlT3B0czoge1xuICAgICAgICAgICAgICAgIGNyZWF0aW9uX2NvbnRlbnQ6IHtcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhpcyBhbGxvd3MgdXMgdG8gcmVjb2duaXNlIHRoYXQgdGhlIHJvb20gaXMgYSB2aXJ0dWFsIHJvb21cbiAgICAgICAgICAgICAgICAgICAgLy8gd2hlbiBpdCBjb21lcyBkb3duIG91ciBzeW5jIHN0cmVhbSAod2UgYWxzbyBwdXQgdGhlIElEIG9mIHRoZVxuICAgICAgICAgICAgICAgICAgICAvLyByZXNwZWN0aXZlIG5hdGl2ZSByb29tIGluIHRoZXJlIGJlY2F1c2Ugd2h5IG5vdD8pXG4gICAgICAgICAgICAgICAgICAgIFtWSVJUVUFMX1JPT01fRVZFTlRfVFlQRV06IG5hdGl2ZVJvb21JZCxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIHJldHVybiByb29tSWQ7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBlbnN1cmVETUV4aXN0cyhjbGllbnQ6IE1hdHJpeENsaWVudCwgdXNlcklkOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZyB8IG51bGw+IHtcbiAgICBjb25zdCBleGlzdGluZ0RNUm9vbSA9IGZpbmRETUZvclVzZXIoY2xpZW50LCB1c2VySWQpO1xuICAgIGxldCByb29tSWQ6IHN0cmluZyB8IG51bGw7XG4gICAgaWYgKGV4aXN0aW5nRE1Sb29tKSB7XG4gICAgICAgIHJvb21JZCA9IGV4aXN0aW5nRE1Sb29tLnJvb21JZDtcbiAgICB9IGVsc2Uge1xuICAgICAgICBsZXQgZW5jcnlwdGlvbjogYm9vbGVhbiB8IHVuZGVmaW5lZDtcbiAgICAgICAgaWYgKHByaXZhdGVTaG91bGRCZUVuY3J5cHRlZChjbGllbnQpKSB7XG4gICAgICAgICAgICBlbmNyeXB0aW9uID0gYXdhaXQgY2FuRW5jcnlwdFRvQWxsVXNlcnMoY2xpZW50LCBbdXNlcklkXSk7XG4gICAgICAgIH1cblxuICAgICAgICByb29tSWQgPSBhd2FpdCBjcmVhdGVSb29tKGNsaWVudCwgeyBlbmNyeXB0aW9uLCBkbVVzZXJJZDogdXNlcklkLCBzcGlubmVyOiBmYWxzZSwgYW5kVmlldzogZmFsc2UgfSk7XG4gICAgICAgIGlmICghcm9vbUlkKSByZXR1cm4gbnVsbDtcbiAgICAgICAgYXdhaXQgd2FpdEZvck1lbWJlcihjbGllbnQsIHJvb21JZCwgdXNlcklkKTtcbiAgICB9XG4gICAgcmV0dXJuIHJvb21JZDtcbn1cblxuaW50ZXJmYWNlIEFsbG93ZWRFbmNyeXB0aW9uU2V0dGluZyB7XG4gICAgLyoqXG4gICAgICogVHJ1ZSB3aGVuIHRoZSB1c2VyIGlzIGFsbG93ZWQgdG8gY2hvb3NlIHdoZXRoZXIgZW5jcnlwdGlvbiBpcyBlbmFibGVkXG4gICAgICovXG4gICAgYWxsb3dDaGFuZ2U6IGJvb2xlYW47XG4gICAgLyoqXG4gICAgICogU2V0IHdoZW4gdXNlciBpcyBub3QgYWxsb3dlZCB0byBjaG9vc2UgZW5jcnlwdGlvbiBzZXR0aW5nXG4gICAgICogVHJ1ZSB3aGVuIGVuY3J5cHRpb24gaXMgZm9yY2VkIHRvIGVuYWJsZWRcbiAgICAgKi9cbiAgICBmb3JjZWRWYWx1ZT86IGJvb2xlYW47XG59XG4vKipcbiAqIENoZWNrIGlmIHNlcnZlciBjb25maWd1cmF0aW9uIHN1cHBvcnRzIHRoZSB1c2VyIGNoYW5naW5nIGVuY3J5cHRpb24gZm9yIGEgcm9vbVxuICogRmlyc3QgY2hlY2sgaWYgc2VydmVyIGZlYXR1cmVzIGZvcmNlIGVuYWJsZSBlbmNyeXB0aW9uIGZvciB0aGUgZ2l2ZW4gcm9vbSB0eXBlXG4gKiBJZiBub3QsIGNoZWNrIGlmIHNlcnZlciAud2VsbC1rbm93biBmb3JjZXMgZW5jcnlwdGlvbiB0byBkaXNhYmxlZFxuICogSWYgZWl0aGVyIGFyZSBmb3JjZWQsIHRoZW4gZG8gbm90IGFsbG93IHRoZSB1c2VyIHRvIGNoYW5nZSByb29tJ3MgZW5jcnlwdGlvblxuICogQHBhcmFtIGNsaWVudFxuICogQHBhcmFtIGNoYXRQcmVzZXQgY2hhdCB0eXBlXG4gKiBAcmV0dXJucyBQcm9taXNlPGJvb2xlYW4+XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjaGVja1VzZXJJc0FsbG93ZWRUb0NoYW5nZUVuY3J5cHRpb24oXG4gICAgY2xpZW50OiBNYXRyaXhDbGllbnQsXG4gICAgY2hhdFByZXNldDogUHJlc2V0LFxuKTogUHJvbWlzZTxBbGxvd2VkRW5jcnlwdGlvblNldHRpbmc+IHtcbiAgICBjb25zdCBkb2VzU2VydmVyRm9yY2VFbmNyeXB0aW9uRm9yUHJlc2V0ID0gYXdhaXQgY2xpZW50LmRvZXNTZXJ2ZXJGb3JjZUVuY3J5cHRpb25Gb3JQcmVzZXQoY2hhdFByZXNldCk7XG4gICAgY29uc3QgZG9lc1dlbGxLbm93bkZvcmNlRGlzYWJsZUVuY3J5cHRpb24gPSBzaG91bGRGb3JjZURpc2FibGVFbmNyeXB0aW9uKGNsaWVudCk7XG5cbiAgICAvLyBzZXJ2ZXIgaXMgZm9yY2luZyBlbmNyeXB0aW9uIHRvIEVOQUJMRURcbiAgICAvLyB3aGlsZSAud2VsbC1rbm93biBjb25maWcgaXMgZm9yY2luZyBpdCB0byBESVNBQkxFRFxuICAgIC8vIHNlcnZlciB2ZXJzaW9uIGNvbmZpZyBvdmVycmlkZXMgd2sgY29uZmlnXG4gICAgaWYgKGRvZXNTZXJ2ZXJGb3JjZUVuY3J5cHRpb25Gb3JQcmVzZXQgJiYgZG9lc1dlbGxLbm93bkZvcmNlRGlzYWJsZUVuY3J5cHRpb24pIHtcbiAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgICAgYENvbmZsaWN0aW5nIGUyZWUgc2V0dGluZ3M6IHNlcnZlciBjb25maWcgYW5kIC53ZWxsLWtub3duIGNvbmZpZ3VyYXRpb24gZGlzYWdyZWUuIFVzaW5nIHNlcnZlciBmb3JjZWQgZW5jcnlwdGlvbiBzZXR0aW5nIGZvciBjaGF0IHR5cGUgJHtjaGF0UHJlc2V0fWAsXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKGRvZXNTZXJ2ZXJGb3JjZUVuY3J5cHRpb25Gb3JQcmVzZXQpIHtcbiAgICAgICAgcmV0dXJuIHsgYWxsb3dDaGFuZ2U6IGZhbHNlLCBmb