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