UNPKG

@jsprismarine/prismarine

Version:

Dedicated Minecraft Bedrock Edition server written in TypeScript

494 lines (493 loc) • 74.4 kB
"use strict"; Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } }); const require_runtime = require("../_virtual/_rolldown/runtime.cjs.cjs"); const require_item_Item = require("../item/Item.cjs.cjs"); const require_world_chunk_Chunk = require("../world/chunk/Chunk.cjs.cjs"); const require_world_BlockPosition = require("../world/BlockPosition.cjs.cjs"); const require_network_packet_RemoveActorPacket = require("./packet/RemoveActorPacket.cjs.cjs"); const require_network_type_TextType = require("./type/TextType.cjs.cjs"); const require_utils_UUID = require("../utils/UUID.cjs.cjs"); const require_network_packet_AddPlayerPacket = require("./packet/AddPlayerPacket.cjs.cjs"); const require_network_packet_AvailableCommandsPacket = require("./packet/AvailableCommandsPacket.cjs.cjs"); const require_network_packet_BatchPacket = require("./packet/BatchPacket.cjs.cjs"); const require_network_packet_ChunkRadiusUpdatedPacket = require("./packet/ChunkRadiusUpdatedPacket.cjs.cjs"); const require_network_packet_CreativeContentPacket = require("./packet/CreativeContentPacket.cjs.cjs"); const require_network_packet_DisconnectPacket = require("./packet/DisconnectPacket.cjs.cjs"); const require_network_packet_InventoryContentPacket = require("./packet/InventoryContentPacket.cjs.cjs"); const require_network_packet_LevelChunkPacket = require("./packet/LevelChunkPacket.cjs.cjs"); const require_network_packet_MobEquipmentPacket = require("./packet/MobEquipmentPacket.cjs.cjs"); const require_network_type_MovementType = require("./type/MovementType.cjs.cjs"); const require_network_packet_MovePlayerPacket = require("./packet/MovePlayerPacket.cjs.cjs"); const require_network_packet_NetworkChunkPublisherUpdatePacket = require("./packet/NetworkChunkPublisherUpdatePacket.cjs.cjs"); const require_network_packet_PlayStatusPacket = require("./packet/PlayStatusPacket.cjs.cjs"); const require_network_packet_PlayerListPacket = require("./packet/PlayerListPacket.cjs.cjs"); const require_network_packet_SetActorDataPacket = require("./packet/SetActorDataPacket.cjs.cjs"); const require_network_packet_SetPlayerGametypePacket = require("./packet/SetPlayerGametypePacket.cjs.cjs"); const require_network_packet_SetTimePacket = require("./packet/SetTimePacket.cjs.cjs"); const require_network_packet_TextPacket = require("./packet/TextPacket.cjs.cjs"); const require_network_packet_UpdateAdventureSettingsPacket = require("./packet/UpdateAdventureSettingsPacket.cjs.cjs"); const require_network_packet_UpdateAttributesPacket = require("./packet/UpdateAttributesPacket.cjs.cjs"); const require_network_type_CommandParameter = require("./type/CommandParameter.cjs.cjs"); const require_network_type_CommandEnum = require("./type/CommandEnum.cjs.cjs"); const require_command_CommandArguments = require("../command/CommandArguments.cjs.cjs"); const require_inventory_WindowIds = require("../inventory/WindowIds.cjs.cjs"); const require_world_CoordinateUtils = require("../world/CoordinateUtils.cjs.cjs"); const require_network_packet_UpdateAbilitiesPacket = require("./packet/UpdateAbilitiesPacket.cjs.cjs"); const require_network_type_CommandData = require("./type/CommandData.cjs.cjs"); const require_network_type_PermissionType = require("./type/PermissionType.cjs.cjs"); const require_network_type_PlayerPermissionType = require("./type/PlayerPermissionType.cjs.cjs"); let _jsprismarine_bedrock_data = require("@jsprismarine/bedrock-data"); let _jsprismarine_minecraft = require("@jsprismarine/minecraft"); let heap = require("heap"); heap = require_runtime.__toESM(heap, 1); //#region src/network/PlayerSession.ts var PlayerSession = class { connection; server; player; chunkSendQueue = []; loadedChunks = /* @__PURE__ */ new Set(); loadingChunks = /* @__PURE__ */ new Set(); constructor(server, connection, player) { this.server = server; this.connection = connection; this.player = player; } async update(_tick) { if (this.chunkSendQueue.length > 0) { const chunksToSend = this.chunkSendQueue.splice(0, Math.min(this.chunkSendQueue.length, 50)); const batch = new require_network_packet_BatchPacket.default(); for (const chunk of chunksToSend) { const pk = new require_network_packet_LevelChunkPacket.default(); pk.chunkX = chunk.getX(); pk.chunkZ = chunk.getZ(); pk.clientSubChunkRequestsEnabled = false; pk.subChunkCount = chunk.getTopEmpty() + 4; pk.data = chunk.networkSerialize(); batch.addPacket(pk); const hash = require_world_chunk_Chunk.default.packXZ(chunk.getX(), chunk.getZ()); this.loadedChunks.add(hash); this.loadingChunks.delete(hash); } this.connection.sendBatch(batch, false); } this.player.viewDistance && await this.needNewChunks(); } async send(packet) { this.connection.sendDataPacket(packet); } /** * Notify a client about change(s) to the adventure settings. * * @param player - The client-controlled entity */ async sendSettings(player) { const target = player ?? this.player; const packet = new require_network_packet_UpdateAdventureSettingsPacket.default(); packet.worldImmutable = target.gamemode === _jsprismarine_minecraft.Gametype.SPECTATOR; packet.noAttackingPlayers = target.gamemode === _jsprismarine_minecraft.Gametype.SPECTATOR; packet.noAttackingMobs = target.gamemode === _jsprismarine_minecraft.Gametype.SPECTATOR; packet.autoJump = true; packet.showNameTags = true; await this.connection.sendDataPacket(packet); } async sendAbilities(player) { const target = player ?? this.player; const mainLayer = new require_network_packet_UpdateAbilitiesPacket.AbilityLayer(); mainLayer.layerType = require_network_packet_UpdateAbilitiesPacket.AbilityLayerType.BASE; mainLayer.layerFlags = new Map([ [require_network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.FLY_SPEED, true], [require_network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.WALK_SPEED, true], [require_network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.MAY_FLY, target.metadata.canFly], [require_network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.FLYING, target.isFlying()], [require_network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.NO_CLIP, target.gamemode === _jsprismarine_minecraft.Gametype.SPECTATOR], [require_network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.OPERATOR_COMMANDS, target.isOp()], [require_network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.TELEPORT, target.isOp()], [require_network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.INVULNERABLE, target.gamemode === _jsprismarine_minecraft.Gametype.SPECTATOR], [require_network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.MUTED, false], [require_network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.WORLD_BUILDER, false], [require_network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.INSTABUILD, target.gamemode === _jsprismarine_minecraft.Gametype.SPECTATOR], [require_network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.LIGHTNING, false], [require_network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.BUILD, target.gamemode !== _jsprismarine_minecraft.Gametype.SPECTATOR], [require_network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.MINE, target.gamemode !== _jsprismarine_minecraft.Gametype.SPECTATOR], [require_network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.DOORS_AND_SWITCHES, target.gamemode !== _jsprismarine_minecraft.Gametype.SPECTATOR], [require_network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.OPEN_CONTAINERS, target.gamemode !== _jsprismarine_minecraft.Gametype.SPECTATOR], [require_network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.ATTACK_PLAYERS, target.gamemode !== _jsprismarine_minecraft.Gametype.SPECTATOR], [require_network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.ATTACK_MOBS, target.gamemode !== _jsprismarine_minecraft.Gametype.SPECTATOR] ]); mainLayer.flySpeed = .05; mainLayer.walkSpeed = .1; const packet = new require_network_packet_UpdateAbilitiesPacket.default(); packet.commandPermission = target.isOp() ? require_network_type_PermissionType.default.Operator : require_network_type_PermissionType.default.Normal; packet.playerPermission = target.isOp() ? require_network_type_PlayerPermissionType.default.Operator : require_network_type_PlayerPermissionType.default.Member; packet.targetActorUniqueId = target.getRuntimeId(); packet.abilityLayers = [mainLayer]; await this.send(packet); } async needNewChunks(forceResend = false, dist) { const currentXChunk = require_world_CoordinateUtils.default.fromBlockToChunk(this.player.getX()); const currentZChunk = require_world_CoordinateUtils.default.fromBlockToChunk(this.player.getZ()); const viewDistance = this.player.viewDistance || dist || 0; const chunksToSendHeap = new heap.default((a, b) => { const distXFirst = Math.abs(a[0] - currentXChunk); const distXSecond = Math.abs(b[0] - currentXChunk); const distZFirst = Math.abs(a[1] - currentZChunk); const distZSecond = Math.abs(b[1] - currentZChunk); return distXFirst + distZFirst > distXSecond + distZSecond ? 1 : -1; }); for (let sendXChunk = -viewDistance; sendXChunk <= viewDistance; sendXChunk++) for (let sendZChunk = -viewDistance; sendZChunk <= viewDistance; sendZChunk++) { if (sendXChunk * sendXChunk + sendZChunk * sendZChunk > viewDistance * viewDistance) continue; const newChunk = [currentXChunk + sendXChunk, currentZChunk + sendZChunk]; const hash = require_world_chunk_Chunk.default.packXZ(newChunk[0], newChunk[1]); if (forceResend) chunksToSendHeap.push(newChunk); else if (!this.loadedChunks.has(hash) && !this.loadingChunks.has(hash)) chunksToSendHeap.push(newChunk); } while (chunksToSendHeap.size() > 0) { const closestChunk = chunksToSendHeap.pop(); const hash = require_world_chunk_Chunk.default.packXZ(closestChunk[0], closestChunk[1]); if (forceResend) if (!this.loadedChunks.has(hash) && !this.loadingChunks.has(hash)) { this.loadingChunks.add(hash); await this.requestChunk(closestChunk[0], closestChunk[1]); } else { const loadedChunk = await this.player.getWorld().getChunk(closestChunk[0], closestChunk[1]); await this.sendChunk(loadedChunk); } else { this.loadingChunks.add(hash); await this.requestChunk(closestChunk[0], closestChunk[1]); } } let unloaded = false; for (const hash of this.loadedChunks) { const [x, z] = require_world_chunk_Chunk.default.unpackXZ(hash); if (Math.abs(x - currentXChunk) > viewDistance || Math.abs(z - currentZChunk) > viewDistance) { unloaded = true; this.loadedChunks.delete(hash); } } for (const hash of this.loadingChunks) { const [x, z] = require_world_chunk_Chunk.default.unpackXZ(hash); if (Math.abs(x - currentXChunk) > viewDistance || Math.abs(z - currentZChunk) > viewDistance) this.loadingChunks.delete(hash); } if (!unloaded && this.chunkSendQueue.length !== 0) await this.sendNetworkChunkPublisher(dist ?? viewDistance, []); } async requestChunk(x, z) { const chunk = await this.player.getWorld().getChunk(x, z); this.chunkSendQueue.push(chunk); } /** * Clear the currently loaded and loading chunks. * * @remarks * Usually used for changing dimension, world, etc. */ async clearChunks() { this.loadedChunks.clear(); this.loadingChunks.clear(); } /** * @TODO: Implement this. */ async sendInventory() { const pk = new require_network_packet_InventoryContentPacket.default(); pk.items = this.player.getInventory().getItems(true); pk.windowId = require_inventory_WindowIds.WindowIds.INVENTORY; } async sendCreativeContents(empty = false) { const pk = new require_network_packet_CreativeContentPacket.default(); if (empty) { await this.connection.sendDataPacket(pk); return; } const entries = [...this.player.getServer().getBlockManager().getBlocks(), ...this.player.getServer().getItemManager().getItems()]; _jsprismarine_bedrock_data.creativeitems.forEach((item) => { pk.items.push(...entries.filter((entry) => { return entry.meta === (item.damage ?? 0) && entry.getId() === item.id; }).map((entry) => new require_item_Item.Item({ id: entry.getId(), name: entry.getName(), meta: entry.meta }))); }); await this.connection.sendDataPacket(pk); } /** * Sets the item in the player hand. * @param {Item} item - The entity. */ async sendHandItem(item) { const pk = new require_network_packet_MobEquipmentPacket.default(); pk.runtimeEntityId = this.player.getRuntimeId(); pk.item = item; pk.inventorySlot = this.player.getInventory().getHandSlotIndex(); pk.hotbarSlot = this.player.getInventory().getHandSlotIndex(); pk.windowId = 0; await this.connection.sendDataPacket(pk); } /** * Send the current tick to a client. * @param {number} tick - The tick */ async sendTime(tick) { const pk = new require_network_packet_SetTimePacket.default(); pk.time = tick; await this.connection.sendDataPacket(pk); } /** * Send gamemode to a client. * @param {Gametype} gamemode - the numeric gamemode ID. */ async sendGamemode(gamemode) { const packet = new require_network_packet_SetPlayerGametypePacket.default(); packet.gametype = gamemode ?? this.player.gamemode; await this.connection.sendDataPacket(packet); } async sendNetworkChunkPublisher(distance, savedChunks) { const pk = new require_network_packet_NetworkChunkPublisherUpdatePacket.default(); pk.position = require_world_BlockPosition.default.fromVector3(this.player.getPosition()); pk.radius = distance << 4; pk.savedChunks = savedChunks; await this.connection.sendDataPacket(pk); } async sendAvailableCommands() { const playerEnum = new require_network_type_CommandEnum.CommandEnum(); playerEnum.soft = true; playerEnum.name = "Player"; playerEnum.values = this.player.getServer().getSessionManager().getAllPlayers().map((player) => player.getName()); const pk = new require_network_packet_AvailableCommandsPacket.default(); pk.softEnums = [playerEnum]; this.server.getCommandManager().getCommandsList().forEach((command) => { const commandClass = Array.from(this.server.getCommandManager().getCommands().values()).find((cmd) => cmd.name === command[0]); if (!commandClass) { this.player.getServer().getLogger().warn(`Can't find corresponding command class for "${command[0]}"`); return; } if (!this.player.getServer().getPermissionManager().can(this.player).execute(commandClass.permission)) return; const cmd = new require_network_type_CommandData.default(); cmd.commandName = command[0]; cmd.commandDescription = commandClass.description; if (commandClass.aliases.length > 0) { const cmdAliases = new require_network_type_CommandEnum.CommandEnum(); cmdAliases.name = `${command[0]}Aliases`; cmdAliases.values = commandClass.aliases.concat(command[0]); cmd.aliases = cmdAliases; } command[2].forEach((arg, index) => { const parameters = arg.map((parameter) => { if (!parameter || !parameter?.getParameters) return []; const parameters = parameter.getParameters(this.server); if (parameters) return Array.from(parameters.values()); if (parameter instanceof require_command_CommandArguments.CommandArgumentEntity) return [new require_network_type_CommandParameter.default({ paramName: "target", paramType: require_network_type_CommandParameter.CommandParameterType.Target })]; if (parameter instanceof require_command_CommandArguments.CommandArgumentGamemode) return [new require_network_type_CommandParameter.default({ paramName: "gamemode", paramType: require_network_type_CommandParameter.CommandParameterType.String })]; if (parameter.constructor.name === "StringArgumentType") return [new require_network_type_CommandParameter.default({ paramName: "value", paramType: require_network_type_CommandParameter.CommandParameterType.String })]; if (parameter.constructor.name === "IntegerArgumentType") return [new require_network_type_CommandParameter.default({ paramName: "number", paramType: require_network_type_CommandParameter.CommandParameterType.Int })]; this.server.getLogger().warn(`Invalid parameter ${parameter.constructor.name}`); return [new require_network_type_CommandParameter.default({ paramName: "value", paramType: require_network_type_CommandParameter.CommandParameterType.String })]; }).flat(); cmd.overloads[index] = parameters; }); pk.commandData.push(cmd); }); await this.getConnection().sendDataPacket(pk); } /** * Set the client's maximum view distance. * * @param distance - The view distance */ async setViewDistance(distance) { const packet = new require_network_packet_ChunkRadiusUpdatedPacket.default(); packet.radius = this.player.viewDistance = distance; await this.connection.sendDataPacket(packet); } async sendAttributes(attributes) { const value = attributes?.getAttributes() ?? this.player.attributes.getAttributes(); const packet = new require_network_packet_UpdateAttributesPacket.default(); packet.runtimeEntityId = this.player.getRuntimeId(); packet.attributes = value.length > 0 ? value : this.player.attributes.getDefaults(); packet.tick = BigInt(this.player.getServer().getTick()); await this.connection.sendDataPacket(packet); } async sendMetadata(metadata) { const packet = new require_network_packet_SetActorDataPacket.default(); packet.runtimeEntityId = this.player.getRuntimeId(); packet.metadata = metadata ?? this.player.metadata; packet.tick = BigInt(this.player.getServer().getTick()); await this.connection.sendDataPacket(packet); } /** * Send a chat message to the client. * @param {object} options - The options for the message. * @param {string} options.message - The message to send. * @param {string} [options.sourceName=''] - The source of the message. * @param {string} [options.xuid=''] - The XUID of the player. * @param {string} [options.platformChatId=''] - The platform chat ID. * @param {string[]} [options.parameters=[]] - The parameters for the message. * @param {boolean} [options.needsTranslation=false] - Whether the message needs translation. * @param {TextType} [options.type=TextType.Raw] - The type of the message. * @returns {Promise<void>} A promise that resolves when the message is sent. */ async sendMessage({ message, sourceName = "", xuid = "", platformChatId = "", parameters = [], needsTranslation = false, type = require_network_type_TextType.default.Raw }) { if (!message) throw new Error("A message is required"); const pk = new require_network_packet_TextPacket.default(); pk.message = message; pk.filtered = message; pk.sourceName = sourceName; pk.xuid = xuid; pk.platformChatId = platformChatId; pk.parameters = parameters; pk.needsTranslation = needsTranslation; pk.type = type; await this.connection.sendDataPacket(pk); } async sendChunk(chunk) { const hash = require_world_chunk_Chunk.default.packXZ(chunk.getX(), chunk.getZ()); const packet = new require_network_packet_LevelChunkPacket.default(); packet.chunkX = chunk.getX(); packet.chunkZ = chunk.getZ(); packet.clientSubChunkRequestsEnabled = false; packet.subChunkCount = chunk.getTopEmpty() + 4; packet.data = chunk.networkSerialize(); await this.send(packet); this.loadingChunks.delete(hash); this.loadedChunks.add(hash); } /** * Broadcast the movement to a defined player */ async broadcastMove(player, mode = require_network_type_MovementType.default.Normal) { const packet = new require_network_packet_MovePlayerPacket.default(); packet.runtimeEntityId = player.getRuntimeId(); packet.position = player.getPosition(); packet.pitch = player.pitch; packet.yaw = player.yaw; packet.headYaw = player.headYaw; packet.mode = mode; packet.onGround = player.isOnGround(); if (mode === require_network_type_MovementType.default.Teleport) { packet.teleportCause = 0; packet.teleportItemId = 0; } packet.ridingEntityRuntimeId = BigInt(0); packet.tick = BigInt(this.player.getServer().getTick()); await this.send(packet); } /** * Adds the client to the player list of every player inside * the server and also to the player itself. */ async addToPlayerList() { const entry = new require_network_packet_PlayerListPacket.PlayerListEntry({ uuid: require_utils_UUID.default.fromString(this.player.getUUID()), runtimeId: this.player.getRuntimeId(), name: this.player.getName(), xuid: this.player.xuid, platformChatId: this.player.platformChatId, buildPlatform: this.player.device?.os ?? -1, skin: this.player.skin, isTeacher: false, isHost: false }); this.server.getSessionManager().getPlayerList().set(this.player.getUUID(), entry); const packet = new require_network_packet_PlayerListPacket.default(); packet.type = require_network_packet_PlayerListPacket.PlayerListAction.TYPE_ADD; packet.entries.push(entry); await this.server.broadcastPacket(packet); } /** * Removes a player from other players list */ async removeFromPlayerList() { const entry = new require_network_packet_PlayerListPacket.PlayerListEntry({ uuid: require_utils_UUID.default.fromString(this.player.getUUID()) }); this.server.getSessionManager().getPlayerList().delete(this.player.getUUID()); const packet = new require_network_packet_PlayerListPacket.default(); packet.type = require_network_packet_PlayerListPacket.PlayerListAction.TYPE_REMOVE; packet.entries.push(entry); await this.server.broadcastPacket(packet); } /** * Sends the full player list to the player. */ async sendPlayerList() { const packet = new require_network_packet_PlayerListPacket.default(); packet.type = require_network_packet_PlayerListPacket.PlayerListAction.TYPE_ADD; packet.entries = Array.from(this.server.getSessionManager().getPlayerList().values()); await this.send(packet); } /** * Spawn the player for another player * * @param player - the player to send the AddPlayerPacket to */ async sendSpawn(player) { if (!player.getUUID()) { this.server.getLogger().error(`UUID for player ${player.getName()} is undefined`); return; } const pk = new require_network_packet_AddPlayerPacket.default(); pk.uuid = require_utils_UUID.default.fromString(this.player.getUUID()); pk.runtimeEntityId = this.player.getRuntimeId(); pk.name = this.player.getName(); pk.positionX = this.player.getX(); pk.positionY = this.player.getY(); pk.positionZ = this.player.getZ(); pk.motionX = 0; pk.motionY = 0; pk.motionZ = 0; pk.pitch = this.player.pitch; pk.yaw = this.player.yaw; pk.headYaw = this.player.headYaw; pk.gamemode = this.player.gamemode; pk.item = this.player.getInventory().getItemInHand(); pk.deviceId = this.player.device?.id ?? ""; pk.metadata = this.player.metadata; await player.getNetworkSession().send(pk); await this.sendSettings(player); } /** * Despawn the player entity from another player */ async sendDespawn(player) { const pk = new require_network_packet_RemoveActorPacket.default(); pk.uniqueEntityId = this.player.getRuntimeId(); await player.getNetworkSession().getConnection().sendDataPacket(pk); } async sendPlayStatus(status) { const pk = new require_network_packet_PlayStatusPacket.default(); pk.status = status; await this.connection.sendDataPacket(pk, true); } async kick(reason = "unknown reason") { const pk = new require_network_packet_DisconnectPacket.default(); pk.skipMessage = false; pk.message = reason; await this.connection.sendDataPacket(pk, true); } getConnection() { return this.connection; } getPlayer() { return this.player; } }; //#endregion exports.default = PlayerSession; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGxheWVyU2Vzc2lvbi5janMuY2pzIiwibmFtZXMiOltdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9uZXR3b3JrL1BsYXllclNlc3Npb24udHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgY3JlYXRpdmVpdGVtcyBhcyBDcmVhdGl2ZUl0ZW1zIH0gZnJvbSAnQGpzcHJpc21hcmluZS9iZWRyb2NrLWRhdGEnO1xuaW1wb3J0IHsgR2FtZXR5cGUgfSBmcm9tICdAanNwcmlzbWFyaW5lL21pbmVjcmFmdCc7XG5pbXBvcnQgSGVhcCBmcm9tICdoZWFwJztcbmltcG9ydCB0eXBlIFBsYXllciBmcm9tICcuLi9QbGF5ZXInO1xuaW1wb3J0IHR5cGUgU2VydmVyIGZyb20gJy4uL1NlcnZlcic7XG5pbXBvcnQgdHlwZSB7IENvbW1hbmRBcmd1bWVudCB9IGZyb20gJy4uL2NvbW1hbmQvQ29tbWFuZEFyZ3VtZW50cyc7XG5pbXBvcnQgeyBDb21tYW5kQXJndW1lbnRFbnRpdHksIENvbW1hbmRBcmd1bWVudEdhbWVtb2RlIH0gZnJvbSAnLi4vY29tbWFuZC9Db21tYW5kQXJndW1lbnRzJztcbmltcG9ydCB0eXBlIHsgQXR0cmlidXRlcyB9IGZyb20gJy4uL2VudGl0eS9BdHRyaWJ1dGUnO1xuaW1wb3J0IHR5cGUgeyBNZXRhZGF0YSB9IGZyb20gJy4uL2VudGl0eS9NZXRhZGF0YSc7XG5pbXBvcnQgeyBXaW5kb3dJZHMgfSBmcm9tICcuLi9pbnZlbnRvcnkvV2luZG93SWRzJztcbmltcG9ydCB7IEl0ZW0gfSBmcm9tICcuLi9pdGVtL0l0ZW0nO1xuaW1wb3J0IFVVSUQgZnJvbSAnLi4vdXRpbHMvVVVJRCc7XG5pbXBvcnQgQmxvY2tQb3NpdGlvbiBmcm9tICcuLi93b3JsZC9CbG9ja1Bvc2l0aW9uJztcbmltcG9ydCBDb29yZGluYXRlVXRpbHMgZnJvbSAnLi4vd29ybGQvQ29vcmRpbmF0ZVV0aWxzJztcbmltcG9ydCBDaHVuayBmcm9tICcuLi93b3JsZC9jaHVuay9DaHVuayc7XG5pbXBvcnQgdHlwZSBDbGllbnRDb25uZWN0aW9uIGZyb20gJy4vQ2xpZW50Q29ubmVjdGlvbic7XG5pbXBvcnQgdHlwZSB7IERhdGFQYWNrZXQgfSBmcm9tICcuL1BhY2tldHMnO1xuaW1wb3J0IHsgQmF0Y2hQYWNrZXQgfSBmcm9tICcuL1BhY2tldHMnO1xuaW1wb3J0IEFkZFBsYXllclBhY2tldCBmcm9tICcuL3BhY2tldC9BZGRQbGF5ZXJQYWNrZXQnO1xuaW1wb3J0IEF2YWlsYWJsZUNvbW1hbmRzUGFja2V0IGZyb20gJy4vcGFja2V0L0F2YWlsYWJsZUNvbW1hbmRzUGFja2V0JztcbmltcG9ydCBDaHVua1JhZGl1c1VwZGF0ZWRQYWNrZXQgZnJvbSAnLi9wYWNrZXQvQ2h1bmtSYWRpdXNVcGRhdGVkUGFja2V0JztcbmltcG9ydCBDcmVhdGl2ZUNvbnRlbnRQYWNrZXQgZnJvbSAnLi9wYWNrZXQvQ3JlYXRpdmVDb250ZW50UGFja2V0JztcbmltcG9ydCBEaXNjb25uZWN0UGFja2V0IGZyb20gJy4vcGFja2V0L0Rpc2Nvbm5lY3RQYWNrZXQnO1xuaW1wb3J0IEludmVudG9yeUNvbnRlbnRQYWNrZXQgZnJvbSAnLi9wYWNrZXQvSW52ZW50b3J5Q29udGVudFBhY2tldCc7XG5pbXBvcnQgTGV2ZWxDaHVua1BhY2tldCBmcm9tICcuL3BhY2tldC9MZXZlbENodW5rUGFja2V0JztcbmltcG9ydCBNb2JFcXVpcG1lbnRQYWNrZXQgZnJvbSAnLi9wYWNrZXQvTW9iRXF1aXBtZW50UGFja2V0JztcbmltcG9ydCBNb3ZlUGxheWVyUGFja2V0IGZyb20gJy4vcGFja2V0L01vdmVQbGF5ZXJQYWNrZXQnO1xuaW1wb3J0IHR5cGUgeyBDaHVua0Nvb3JkIH0gZnJvbSAnLi9wYWNrZXQvTmV0d29ya0NodW5rUHVibGlzaGVyVXBkYXRlUGFja2V0JztcbmltcG9ydCBOZXR3b3JrQ2h1bmtQdWJsaXNoZXJVcGRhdGVQYWNrZXQgZnJvbSAnLi9wYWNrZXQvTmV0d29ya0NodW5rUHVibGlzaGVyVXBkYXRlUGFja2V0JztcbmltcG9ydCBQbGF5U3RhdHVzUGFja2V0IGZyb20gJy4vcGFja2V0L1BsYXlTdGF0dXNQYWNrZXQnO1xuaW1wb3J0IFBsYXllckxpc3RQYWNrZXQsIHsgUGxheWVyTGlzdEFjdGlvbiwgUGxheWVyTGlzdEVudHJ5IH0gZnJvbSAnLi9wYWNrZXQvUGxheWVyTGlzdFBhY2tldCc7XG5pbXBvcnQgUmVtb3ZlQWN0b3JQYWNrZXQgZnJvbSAnLi9wYWNrZXQvUmVtb3ZlQWN0b3JQYWNrZXQnO1xuaW1wb3J0IFNldEFjdG9yRGF0YVBhY2tldCBmcm9tICcuL3BhY2tldC9TZXRBY3RvckRhdGFQYWNrZXQnO1xuaW1wb3J0IFNldFBsYXllckdhbWV0eXBlUGFja2V0IGZyb20gJy4vcGFja2V0L1NldFBsYXllckdhbWV0eXBlUGFja2V0JztcbmltcG9ydCBTZXRUaW1lUGFja2V0IGZyb20gJy4vcGFja2V0L1NldFRpbWVQYWNrZXQnO1xuaW1wb3J0IFRleHRQYWNrZXQgZnJvbSAnLi9wYWNrZXQvVGV4dFBhY2tldCc7XG5pbXBvcnQgVXBkYXRlQWJpbGl0aWVzUGFja2V0LCB7XG4gICAgQWJpbGl0eUxheWVyLFxuICAgIEFiaWxpdHlMYXllckZsYWcsXG4gICAgQWJpbGl0eUxheWVyVHlwZVxufSBmcm9tICcuL3BhY2tldC9VcGRhdGVBYmlsaXRpZXNQYWNrZXQnO1xuaW1wb3J0IFVwZGF0ZUFkdmVudHVyZVNldHRpbmdzUGFja2V0IGZyb20gJy4vcGFja2V0L1VwZGF0ZUFkdmVudHVyZVNldHRpbmdzUGFja2V0JztcbmltcG9ydCBVcGRhdGVBdHRyaWJ1dGVzUGFja2V0IGZyb20gJy4vcGFja2V0L1VwZGF0ZUF0dHJpYnV0ZXNQYWNrZXQnO1xuaW1wb3J0IENvbW1hbmREYXRhIGZyb20gJy4vdHlwZS9Db21tYW5kRGF0YSc7XG5pbXBvcnQgeyBDb21tYW5kRW51bSB9IGZyb20gJy4vdHlwZS9Db21tYW5kRW51bSc7XG5pbXBvcnQgQ29tbWFuZFBhcmFtZXRlciwgeyBDb21tYW5kUGFyYW1ldGVyVHlwZSB9IGZyb20gJy4vdHlwZS9Db21tYW5kUGFyYW1ldGVyJztcbmltcG9ydCBNb3ZlbWVudFR5cGUgZnJvbSAnLi90eXBlL01vdmVtZW50VHlwZSc7XG5pbXBvcnQgUGVybWlzc2lvblR5cGUgZnJvbSAnLi90eXBlL1Blcm1pc3Npb25UeXBlJztcbmltcG9ydCBQbGF5ZXJQZXJtaXNzaW9uVHlwZSBmcm9tICcuL3R5cGUvUGxheWVyUGVybWlzc2lvblR5cGUnO1xuaW1wb3J0IFRleHRUeXBlIGZyb20gJy4vdHlwZS9UZXh0VHlwZSc7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFBsYXllclNlc3Npb24ge1xuICAgIHByaXZhdGUgY29ubmVjdGlvbjogQ2xpZW50Q29ubmVjdGlvbjtcbiAgICBwcml2YXRlIHJlYWRvbmx5IHNlcnZlcjogU2VydmVyO1xuICAgIHByaXZhdGUgcGxheWVyOiBQbGF5ZXI7XG5cbiAgICBwcml2YXRlIHJlYWRvbmx5IGNodW5rU2VuZFF1ZXVlOiBDaHVua1tdID0gW107XG4gICAgcHJpdmF0ZSByZWFkb25seSBsb2FkZWRDaHVua3M6IFNldDxiaWdpbnQ+ID0gbmV3IFNldCgpO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgbG9hZGluZ0NodW5rczogU2V0PGJpZ2ludD4gPSBuZXcgU2V0KCk7XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3Ioc2VydmVyOiBTZXJ2ZXIsIGNvbm5lY3Rpb246IENsaWVudENvbm5lY3Rpb24sIHBsYXllcjogUGxheWVyKSB7XG4gICAgICAgIHRoaXMuc2VydmVyID0gc2VydmVyO1xuICAgICAgICB0aGlzLmNvbm5lY3Rpb24gPSBjb25uZWN0aW9uO1xuICAgICAgICB0aGlzLnBsYXllciA9IHBsYXllcjtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgdXBkYXRlKF90aWNrOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKHRoaXMuY2h1bmtTZW5kUXVldWUubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgY29uc3QgY2h1bmtzVG9TZW5kID0gdGhpcy5jaHVua1NlbmRRdWV1ZS5zcGxpY2UoMCwgTWF0aC5taW4odGhpcy5jaHVua1NlbmRRdWV1ZS5sZW5ndGgsIDUwKSk7XG4gICAgICAgICAgICBjb25zdCBiYXRjaCA9IG5ldyBCYXRjaFBhY2tldCgpO1xuICAgICAgICAgICAgZm9yIChjb25zdCBjaHVuayBvZiBjaHVua3NUb1NlbmQpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBwayA9IG5ldyBMZXZlbENodW5rUGFja2V0KCk7XG4gICAgICAgICAgICAgICAgcGsuY2h1bmtYID0gY2h1bmsuZ2V0WCgpO1xuICAgICAgICAgICAgICAgIHBrLmNodW5rWiA9IGNodW5rLmdldFooKTtcbiAgICAgICAgICAgICAgICBway5jbGllbnRTdWJDaHVua1JlcXVlc3RzRW5hYmxlZCA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIHBrLnN1YkNodW5rQ291bnQgPSBjaHVuay5nZXRUb3BFbXB0eSgpICsgNDtcbiAgICAgICAgICAgICAgICBway5kYXRhID0gY2h1bmsubmV0d29ya1NlcmlhbGl6ZSgpO1xuICAgICAgICAgICAgICAgIGJhdGNoLmFkZFBhY2tldChwayk7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBoYXNoID0gQ2h1bmsucGFja1haKGNodW5rLmdldFgoKSwgY2h1bmsuZ2V0WigpKTtcbiAgICAgICAgICAgICAgICB0aGlzLmxvYWRlZENodW5rcy5hZGQoaGFzaCk7XG4gICAgICAgICAgICAgICAgdGhpcy5sb2FkaW5nQ2h1bmtzLmRlbGV0ZShoYXNoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5zZW5kQmF0Y2goYmF0Y2gsIGZhbHNlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucGxheWVyLnZpZXdEaXN0YW5jZSAmJiAoYXdhaXQgdGhpcy5uZWVkTmV3Q2h1bmtzKCkpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBzZW5kKHBhY2tldDogRGF0YVBhY2tldCkge1xuICAgICAgICB0aGlzLmNvbm5lY3Rpb24uc2VuZERhdGFQYWNrZXQocGFja2V0KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBOb3RpZnkgYSBjbGllbnQgYWJvdXQgY2hhbmdlKHMpIHRvIHRoZSBhZHZlbnR1cmUgc2V0dGluZ3MuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gcGxheWVyIC0gVGhlIGNsaWVudC1jb250cm9sbGVkIGVudGl0eVxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBzZW5kU2V0dGluZ3MocGxheWVyPzogUGxheWVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IHRhcmdldCA9IHBsYXllciA/PyB0aGlzLnBsYXllcjtcblxuICAgICAgICBjb25zdCBwYWNrZXQgPSBuZXcgVXBkYXRlQWR2ZW50dXJlU2V0dGluZ3NQYWNrZXQoKTtcbiAgICAgICAgcGFja2V0LndvcmxkSW1tdXRhYmxlID0gdGFyZ2V0LmdhbWVtb2RlID09PSBHYW1ldHlwZS5TUEVDVEFUT1I7XG4gICAgICAgIHBhY2tldC5ub0F0dGFja2luZ1BsYXllcnMgPSB0YXJnZXQuZ2FtZW1vZGUgPT09IEdhbWV0eXBlLlNQRUNUQVRPUjtcbiAgICAgICAgcGFja2V0Lm5vQXR0YWNraW5nTW9icyA9IHRhcmdldC5nYW1lbW9kZSA9PT0gR2FtZXR5cGUuU1BFQ1RBVE9SO1xuICAgICAgICBwYWNrZXQuYXV0b0p1bXAgPSB0cnVlO1xuICAgICAgICBwYWNrZXQuc2hvd05hbWVUYWdzID0gdHJ1ZTtcbiAgICAgICAgYXdhaXQgdGhpcy5jb25uZWN0aW9uLnNlbmREYXRhUGFja2V0KHBhY2tldCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHNlbmRBYmlsaXRpZXMocGxheWVyPzogUGxheWVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IHRhcmdldCA9IHBsYXllciA/PyB0aGlzLnBsYXllcjtcblxuICAgICAgICBjb25zdCBtYWluTGF5ZXIgPSBuZXcgQWJpbGl0eUxheWVyKCk7XG4gICAgICAgIG1haW5MYXllci5sYXllclR5cGUgPSBBYmlsaXR5TGF5ZXJUeXBlLkJBU0U7XG4gICAgICAgIG1haW5MYXllci5sYXllckZsYWdzID0gbmV3IE1hcChbXG4gICAgICAgICAgICBbQWJpbGl0eUxheWVyRmxhZy5GTFlfU1BFRUQsIHRydWVdLFxuICAgICAgICAgICAgW0FiaWxpdHlMYXllckZsYWcuV0FMS19TUEVFRCwgdHJ1ZV0sXG4gICAgICAgICAgICBbQWJpbGl0eUxheWVyRmxhZy5NQVlfRkxZLCB0YXJnZXQubWV0YWRhdGEuY2FuRmx5XSxcbiAgICAgICAgICAgIFtBYmlsaXR5TGF5ZXJGbGFnLkZMWUlORywgdGFyZ2V0LmlzRmx5aW5nKCldLFxuICAgICAgICAgICAgW0FiaWxpdHlMYXllckZsYWcuTk9fQ0xJUCwgdGFyZ2V0LmdhbWVtb2RlID09PSBHYW1ldHlwZS5TUEVDVEFUT1JdLFxuICAgICAgICAgICAgW0FiaWxpdHlMYXllckZsYWcuT1BFUkFUT1JfQ09NTUFORFMsIHRhcmdldC5pc09wKCldLFxuICAgICAgICAgICAgW0FiaWxpdHlMYXllckZsYWcuVEVMRVBPUlQsIHRhcmdldC5pc09wKCldLFxuICAgICAgICAgICAgW0FiaWxpdHlMYXllckZsYWcuSU5WVUxORVJBQkxFLCB0YXJnZXQuZ2FtZW1vZGUgPT09IEdhbWV0eXBlLlNQRUNUQVRPUl0sXG4gICAgICAgICAgICBbQWJpbGl0eUxheWVyRmxhZy5NVVRFRCwgZmFsc2VdLFxuICAgICAgICAgICAgW0FiaWxpdHlMYXllckZsYWcuV09STERfQlVJTERFUiwgZmFsc2VdLFxuICAgICAgICAgICAgW0FiaWxpdHlMYXllckZsYWcuSU5TVEFCVUlMRCwgdGFyZ2V0LmdhbWVtb2RlID09PSBHYW1ldHlwZS5TUEVDVEFUT1JdLFxuICAgICAgICAgICAgW0FiaWxpdHlMYXllckZsYWcuTElHSFROSU5HLCBmYWxzZV0sXG4gICAgICAgICAgICBbQWJpbGl0eUxheWVyRmxhZy5CVUlMRCwgdGFyZ2V0LmdhbWVtb2RlICE9PSBHYW1ldHlwZS5TUEVDVEFUT1JdLFxuICAgICAgICAgICAgW0FiaWxpdHlMYXllckZsYWcuTUlORSwgdGFyZ2V0LmdhbWVtb2RlICE9PSBHYW1ldHlwZS5TUEVDVEFUT1JdLFxuICAgICAgICAgICAgW0FiaWxpdHlMYXllckZsYWcuRE9PUlNfQU5EX1NXSVRDSEVTLCB0YXJnZXQuZ2FtZW1vZGUgIT09IEdhbWV0eXBlLlNQRUNUQVRPUl0sXG4gICAgICAgICAgICBbQWJpbGl0eUxheWVyRmxhZy5PUEVOX0NPTlRBSU5FUlMsIHRhcmdldC5nYW1lbW9kZSAhPT0gR2FtZXR5cGUuU1BFQ1RBVE9SXSxcbiAgICAgICAgICAgIFtBYmlsaXR5TGF5ZXJGbGFnLkFUVEFDS19QTEFZRVJTLCB0YXJnZXQuZ2FtZW1vZGUgIT09IEdhbWV0eXBlLlNQRUNUQVRPUl0sXG4gICAgICAgICAgICBbQWJpbGl0eUxheWVyRmxhZy5BVFRBQ0tfTU9CUywgdGFyZ2V0LmdhbWVtb2RlICE9PSBHYW1ldHlwZS5TUEVDVEFUT1JdXG4gICAgICAgIF0pO1xuICAgICAgICBtYWluTGF5ZXIuZmx5U3BlZWQgPSAwLjA1O1xuICAgICAgICBtYWluTGF5ZXIud2Fsa1NwZWVkID0gMC4xO1xuXG4gICAgICAgIGNvbnN0IHBhY2tldCA9IG5ldyBVcGRhdGVBYmlsaXRpZXNQYWNrZXQoKTtcbiAgICAgICAgcGFja2V0LmNvbW1hbmRQZXJtaXNzaW9uID0gdGFyZ2V0LmlzT3AoKSA/IFBlcm1pc3Npb25UeXBlLk9wZXJhdG9yIDogUGVybWlzc2lvblR5cGUuTm9ybWFsO1xuICAgICAgICBwYWNrZXQucGxheWVyUGVybWlzc2lvbiA9IHRhcmdldC5pc09wKCkgPyBQbGF5ZXJQZXJtaXNzaW9uVHlwZS5PcGVyYXRvciA6IFBsYXllclBlcm1pc3Npb25UeXBlLk1lbWJlcjtcbiAgICAgICAgcGFja2V0LnRhcmdldEFjdG9yVW5pcXVlSWQgPSB0YXJnZXQuZ2V0UnVudGltZUlkKCk7XG4gICAgICAgIHBhY2tldC5hYmlsaXR5TGF5ZXJzID0gW21haW5MYXllcl07XG4gICAgICAgIGF3YWl0IHRoaXMuc2VuZChwYWNrZXQpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBuZWVkTmV3Q2h1bmtzKGZvcmNlUmVzZW5kID0gZmFsc2UsIGRpc3Q/OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgY3VycmVudFhDaHVuayA9IENvb3JkaW5hdGVVdGlscy5mcm9tQmxvY2tUb0NodW5rKHRoaXMucGxheWVyLmdldFgoKSk7XG4gICAgICAgIGNvbnN0IGN1cnJlbnRaQ2h1bmsgPSBDb29yZGluYXRlVXRpbHMuZnJvbUJsb2NrVG9DaHVuayh0aGlzLnBsYXllci5nZXRaKCkpO1xuXG4gICAgICAgIGNvbnN0IHZpZXdEaXN0YW5jZSA9IHRoaXMucGxheWVyLnZpZXdEaXN0YW5jZSB8fCBkaXN0IHx8IDA7XG5cbiAgICAgICAgY29uc3QgY2h1bmtzVG9TZW5kSGVhcCA9IG5ldyBIZWFwKChhOiBudW1iZXJbXSwgYjogbnVtYmVyW10pID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGRpc3RYRmlyc3QgPSBNYXRoLmFicyhhWzBdISAtIGN1cnJlbnRYQ2h1bmspO1xuICAgICAgICAgICAgY29uc3QgZGlzdFhTZWNvbmQgPSBNYXRoLmFicyhiWzBdISAtIGN1cnJlbnRYQ2h1bmspO1xuXG4gICAgICAgICAgICBjb25zdCBkaXN0WkZpcnN0ID0gTWF0aC5hYnMoYVsxXSEgLSBjdXJyZW50WkNodW5rKTtcbiAgICAgICAgICAgIGNvbnN0IGRpc3RaU2Vjb25kID0gTWF0aC5hYnMoYlsxXSEgLSBjdXJyZW50WkNodW5rKTtcblxuICAgICAgICAgICAgcmV0dXJuIGRpc3RYRmlyc3QgKyBkaXN0WkZpcnN0ID4gZGlzdFhTZWNvbmQgKyBkaXN0WlNlY29uZCA/IDEgOiAtMTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgZm9yIChsZXQgc2VuZFhDaHVuayA9IC12aWV3RGlzdGFuY2U7IHNlbmRYQ2h1bmsgPD0gdmlld0Rpc3RhbmNlOyBzZW5kWENodW5rKyspIHtcbiAgICAgICAgICAgIGZvciAobGV0IHNlbmRaQ2h1bmsgPSAtdmlld0Rpc3RhbmNlOyBzZW5kWkNodW5rIDw9IHZpZXdEaXN0YW5jZTsgc2VuZFpDaHVuaysrKSB7XG4gICAgICAgICAgICAgICAgaWYgKHNlbmRYQ2h1bmsgKiBzZW5kWENodW5rICsgc2VuZFpDaHVuayAqIHNlbmRaQ2h1bmsgPiB2aWV3RGlzdGFuY2UgKiB2aWV3RGlzdGFuY2UpIGNvbnRpbnVlOyAvLyBlYXJseSBleGl0IGlmIGNodW5rIGlzIG91dHNpZGUgb2YgdmlldyBkaXN0YW5jZVxuICAgICAgICAgICAgICAgIGNvbnN0IG5ld0NodW5rID0gW2N1cnJlbnRYQ2h1bmsgKyBzZW5kWENodW5rLCBjdXJyZW50WkNodW5rICsgc2VuZFpDaHVua107XG4gICAgICAgICAgICAgICAgY29uc3QgaGFzaCA9IENodW5rLnBhY2tYWihuZXdDaHVua1swXSEsIG5ld0NodW5rWzFdISk7XG5cbiAgICAgICAgICAgICAgICBpZiAoZm9yY2VSZXNlbmQpIHtcbiAgICAgICAgICAgICAgICAgICAgY2h1bmtzVG9TZW5kSGVhcC5wdXNoKG5ld0NodW5rKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCF0aGlzLmxvYWRlZENodW5rcy5oYXMoaGFzaCkgJiYgIXRoaXMubG9hZGluZ0NodW5rcy5oYXMoaGFzaCkpIHtcbiAgICAgICAgICAgICAgICAgICAgY2h1bmtzVG9TZW5kSGVhcC5wdXNoKG5ld0NodW5rKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB3aGlsZSAoY2h1bmtzVG9TZW5kSGVhcC5zaXplKCkgPiAwKSB7XG4gICAgICAgICAgICBjb25zdCBjbG9zZXN0Q2h1bmsgPSBjaHVua3NUb1NlbmRIZWFwLnBvcCgpITtcbiAgICAgICAgICAgIGNvbnN0IGhhc2ggPSBDaHVuay5wYWNrWFooY2xvc2VzdENodW5rWzBdISwgY2xvc2VzdENodW5rWzFdISk7XG4gICAgICAgICAgICBpZiAoZm9yY2VSZXNlbmQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXRoaXMubG9hZGVkQ2h1bmtzLmhhcyhoYXNoKSAmJiAhdGhpcy5sb2FkaW5nQ2h1bmtzLmhhcyhoYXNoKSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmxvYWRpbmdDaHVua3MuYWRkKGhhc2gpO1xuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnJlcXVlc3RDaHVuayhjbG9zZXN0Q2h1bmtbMF0hLCBjbG9zZXN0Q2h1bmtbMV0hKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBsb2FkZWRDaHVuayA9IGF3YWl0IHRoaXMucGxheWVyLmdldFdvcmxkKCkuZ2V0Q2h1bmsoY2xvc2VzdENodW5rWzBdISwgY2xvc2VzdENodW5rWzFdISk7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuc2VuZENodW5rKGxvYWRlZENodW5rKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMubG9hZGluZ0NodW5rcy5hZGQoaGFzaCk7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5yZXF1ZXN0Q2h1bmsoY2xvc2VzdENodW5rWzBdISwgY2xvc2VzdENodW5rWzFdISk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgdW5sb2FkZWQgPSBmYWxzZTtcblxuICAgICAgICBmb3IgKGNvbnN0IGhhc2ggb2YgdGhpcy5sb2FkZWRDaHVua3MpIHtcbiAgICAgICAgICAgIGNvbnN0IFt4LCB6XSA9IENodW5rLnVucGFja1haKGhhc2gpO1xuXG4gICAgICAgICAgICBpZiAoTWF0aC5hYnMoeCEgLSBjdXJyZW50WENodW5rKSA+IHZpZXdEaXN0YW5jZSB8fCBNYXRoLmFicyh6ISAtIGN1cnJlbnRaQ2h1bmspID4gdmlld0Rpc3RhbmNlKSB7XG4gICAgICAgICAgICAgICAgdW5sb2FkZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHRoaXMubG9hZGVkQ2h1bmtzLmRlbGV0ZShoYXNoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGZvciAoY29uc3QgaGFzaCBvZiB0aGlzLmxvYWRpbmdDaHVua3MpIHtcbiAgICAgICAgICAgIGNvbnN0IFt4LCB6XSA9IENodW5rLnVucGFja1haKGhhc2gpO1xuXG4gICAgICAgICAgICBpZiAoTWF0aC5hYnMoeCEgLSBjdXJyZW50WENodW5rKSA+IHZpZXdEaXN0YW5jZSB8fCBNYXRoLmFicyh6ISAtIGN1cnJlbnRaQ2h1bmspID4gdmlld0Rpc3RhbmNlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5sb2FkaW5nQ2h1bmtzLmRlbGV0ZShoYXNoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghdW5sb2FkZWQgJiYgdGhpcy5jaHVua1NlbmRRdWV1ZS5sZW5ndGggIT09IDApIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuc2VuZE5ldHdvcmtDaHVua1B1Ymxpc2hlcihkaXN0ID8/IHZpZXdEaXN0YW5jZSwgW10pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHJlcXVlc3RDaHVuayh4OiBudW1iZXIsIHo6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBjaHVuayA9IGF3YWl0IHRoaXMucGxheWVyLmdldFdvcmxkKCkuZ2V0Q2h1bmsoeCwgeik7XG4gICAgICAgIHRoaXMuY2h1bmtTZW5kUXVldWUucHVzaChjaHVuayk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2xlYXIgdGhlIGN1cnJlbnRseSBsb2FkZWQgYW5kIGxvYWRpbmcgY2h1bmtzLlxuICAgICAqXG4gICAgICogQHJlbWFya3NcbiAgICAgKiBVc3VhbGx5IHVzZWQgZm9yIGNoYW5naW5nIGRpbWVuc2lvbiwgd29ybGQsIGV0Yy5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgY2xlYXJDaHVua3MoKSB7XG4gICAgICAgIHRoaXMubG9hZGVkQ2h1bmtzLmNsZWFyKCk7XG4gICAgICAgIHRoaXMubG9hZGluZ0NodW5rcy5jbGVhcigpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBUT0RPOiBJbXBsZW1lbnQgdGhpcy5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgc2VuZEludmVudG9yeSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgcGsgPSBuZXcgSW52ZW50b3J5Q29udGVudFBhY2tldCgpO1xuICAgICAgICBway5pdGVtcyA9IHRoaXMucGxheWVyLmdldEludmVudG9yeSgpLmdldEl0ZW1zKHRydWUpO1xuICAgICAgICBway53aW5kb3dJZCA9IFdpbmRvd0lkcy5JTlZFTlRPUlk7IC8vIEludmVudG9yeSB3aW5kb3dcbiAgICAgICAgLy9hd2FpdCB0aGlzLmNvbm5lY3Rpb24uc2VuZERhdGFQYWNrZXQocGspO1xuICAgICAgICAvL2F3YWl0IHRoaXMuc2VuZEhhbmRJdGVtKHRoaXMucGxheWVyLmdldEludmVudG9yeSgpLmdldEl0ZW1JbkhhbmQoKSk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHNlbmRDcmVhdGl2ZUNvbnRlbnRzKGVtcHR5ID0gZmFsc2UpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgcGsgPSBuZXcgQ3JlYXRpdmVDb250ZW50UGFja2V0KCk7XG4gICAgICAgIGlmIChlbXB0eSkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5jb25uZWN0aW9uLnNlbmREYXRhUGFja2V0KHBrKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGVudHJpZXMgPSBbXG4gICAgICAgICAgICAuLi50aGlzLnBsYXllci5nZXRTZXJ2ZXIoKS5nZXRCbG9ja01hbmFnZXIoKS5nZXRCbG9ja3MoKSxcbiAgICAgICAgICAgIC4uLnRoaXMucGxheWVyLmdldFNlcnZlcigpLmdldEl0ZW1NYW5hZ2VyKCkuZ2V0SXRlbXMoKVxuICAgICAgICBdO1xuXG4gICAgICAgIC8vIFNvcnQgYmFzZWQgb24gUG1tUCBCZWRyb2NrLWRhdGFcbiAgICAgICAgQ3JlYXRpdmVJdGVtcy5mb3JFYWNoKChpdGVtOiBhbnkpID0+IHtcbiAgICAgICAgICAgIHBrLml0ZW1zLnB1c2goXG4gICAgICAgICAgICAgICAgLi4uZW50cmllc1xuICAgICAgICAgICAgICAgICAgICAuZmlsdGVyKChlbnRyeTogYW55KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZW50cnkubWV0YSA9PT0gKGl0ZW0uZGFtYWdlID8/IDApICYmIGVudHJ5LmdldElkKCkgPT09IGl0ZW0uaWQ7XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgIC5tYXAoXG4gICAgICAgICAgICAgICAgICAgICAgICAoZW50cnkpID0+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3IEl0ZW0oe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZDogZW50cnkuZ2V0SWQoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZTogZW50cnkuZ2V0TmFtZSgpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRhOiBlbnRyeS5tZXRhXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgYXdhaXQgdGhpcy5jb25uZWN0aW9uLnNlbmREYXRhUGFja2V0KHBrKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBpdGVtIGluIHRoZSBwbGF5ZXIgaGFuZC5cbiAgICAgKiBAcGFyYW0ge0l0ZW19IGl0ZW0gLSBUaGUgZW50aXR5LlxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBzZW5kSGFuZEl0ZW0oaXRlbTogSXRlbSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBwayA9IG5ldyBNb2JFcXVpcG1lbnRQYWNrZXQoKTtcbiAgICAgICAgcGsucnVudGltZUVudGl0eUlkID0gdGhpcy5wbGF5ZXIuZ2V0UnVudGltZUlkKCk7XG4gICAgICAgIHBrLml0ZW0gPSBpdGVtO1xuICAgICAgICBway5pbnZlbnRvcnlTbG90ID0gdGhpcy5wbGF5ZXIuZ2V0SW52ZW50b3J5KCkuZ2V0SGFuZFNsb3RJbmRleCgpO1xuICAgICAgICBway5ob3RiYXJTbG90ID0gdGhpcy5wbGF5ZXIuZ2V0SW52ZW50b3J5KCkuZ2V0SGFuZFNsb3RJbmRleCgpO1xuICAgICAgICBway53aW5kb3dJZCA9IDA7IC8vIEludmVudG9yeSBJRFxuICAgICAgICBhd2FpdCB0aGlzLmNvbm5lY3Rpb24uc2VuZERhdGFQYWNrZXQocGspO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNlbmQgdGhlIGN1cnJlbnQgdGljayB0byBhIGNsaWVudC5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gdGljayAtIFRoZSB0aWNrXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIHNlbmRUaW1lKHRpY2s6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBwayA9IG5ldyBTZXRUaW1lUGFja2V0KCk7XG4gICAgICAgIHBrLnRpbWUgPSB0aWNrO1xuICAgICAgICBhd2FpdCB0aGlzLmNvbm5lY3Rpb24uc2VuZERhdGFQYWNrZXQocGspO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNlbmQgZ2FtZW1vZGUgdG8gYSBjbGllbnQuXG4gICAgICogQHBhcmFtIHtHYW1ldHlwZX0gZ2FtZW1vZGUgLSB0aGUgbnVtZXJpYyBnYW1lbW9kZSBJRC5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgc2VuZEdhbWVtb2RlKGdhbWVtb2RlPzogR2FtZXR5cGUpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgcGFja2V0ID0gbmV3IFNldFBsYXllckdhbWV0eXBlUGFja2V0KCk7XG4gICAgICAgIHBhY2tldC5nYW1ldHlwZSA9IGdhbWVtb2RlID8/IHRoaXMucGxheWVyLmdhbWVtb2RlO1xuICAgICAgICBhd2FpdCB0aGlzLmNvbm5lY3Rpb24uc2VuZERhdGFQYWNrZXQocGFja2V0KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgc2VuZE5ldHdvcmtDaHVua1B1Ymxpc2hlcihkaXN0YW5jZTogbnVtYmVyLCBzYXZlZENodW5rczogQ2h1bmtDb29yZFtdKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IHBrID0gbmV3IE5ldHdvcmtDaHVua1B1Ymxpc2hlclVwZGF0ZVBhY2tldCgpO1xuICAgICAgICBway5wb3NpdGlvbiA9IEJsb2NrUG9zaXRpb24uZnJvbVZlY3RvcjModGhpcy5wbGF5ZXIuZ2V0UG9zaXRpb24oKSk7XG4gICAgICAgIHBrLnJhZGl1cyA9IGRpc3RhbmNlIDw8IDQ7XG4gICAgICAgIHBrLnNhdmVkQ2h1bmtzID0gc2F2ZWRDaHVua3M7XG4gICAgICAgIGF3YWl0IHRoaXMuY29ubmVjdGlvbi5zZW5kRGF0YVBhY2tldChwayk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHNlbmRBdmFpbGFibGVDb21tYW5kcygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgcGxheWVyRW51bSA9IG5ldyBDb21tYW5kRW51bSgpO1xuICAgICAgICBwbGF5ZXJFbnVtLnNvZnQgPSB0cnVlO1xuICAgICAgICBwbGF5ZXJFbnVtLm5hbWUgPSAnUGxheWVyJztcbiAgICAgICAgcGxheWVyRW51bS52YWx1ZXMgPSB0aGlzLnBsYXllclxuICAgICAgICAgICAgLmdldFNlcnZlcigpXG4gICAgICAgICAgICAuZ2V0U2Vzc2lvbk1hbmFnZXIoKVxuICAgICAgICAgICAgLmdldEFsbFBsYXllcnMoKVxuICAgICAgICAgICAgLm1hcCgocGxheWVyKSA9PiBwbGF5ZXIuZ2V0TmFtZSgpKTtcblxuICAgICAgICBjb25zdCBwayA9IG5ldyBBdmFpbGFibGVDb21tYW5kc1BhY2tldCgpO1xuICAgICAgICBway5zb2Z0RW51bXMgPSBbcGxheWVyRW51bV07XG4gICAgICAgIHRoaXMuc2VydmVyXG4gICAgICAgICAgICAuZ2V0Q29tbWFuZE1hbmFnZXIoKVxuICAgICAgICAgICAgLmdldENvbW1hbmRzTGlzdCgpXG4gICAgICAgICAgICAuZm9yRWFjaCgoY29tbWFuZCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IGNvbW1hbmRDbGFzcyA9IEFycmF5LmZyb20odGhpcy5zZXJ2ZXIuZ2V0Q29tbWFuZE1hbmFnZXIoKS5nZXRDb21tYW5kcygpLnZhbHVlcygpKS5maW5kKFxuICAgICAgICAgICAgICAgICAgICAoY21kKSA9PiBjbWQubmFtZSA9PT0gY29tbWFuZFswXVxuICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgICBpZiAoIWNvbW1hbmRDbGFzcykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnBsYXllclxuICAgICAgICAgICAgICAgICAgICAgICAgLmdldFNlcnZlcigpXG4gICAgICAgICAgICAgICAgICAgICAgICAuZ2V0TG9nZ2VyKClcbiAgICAgICAgICAgICAgICAgICAgICAgIC53YXJuKGBDYW4ndCBmaW5kIGNvcnJlc3BvbmRpbmcgY29tbWFuZCBjbGFzcyBmb3IgXCIke2NvbW1hbmRbMF19XCJgKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICghdGhpcy5wbGF5ZXIuZ2V0U2VydmVyKCkuZ2V0UGVybWlzc2lvbk1hbmFnZXIoKS5jYW4odGhpcy5wbGF5ZXIpLmV4ZWN1dGUoY29tbWFuZENsYXNzLnBlcm1pc3Npb24pKVxuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgICAgICAgICBjb25zdCBjbWQgPSBuZXcgQ29tbWFuZERhdGEoKTtcbiAgICAgICAgICAgICAgICBjbWQuY29tbWFuZE5hbWUgPSBjb21tYW5kWzBdO1xuICAgICAgICAgICAgICAgIGNtZC5jb21tYW5kRGVzY3JpcHRpb24gPSBjb21tYW5kQ2xhc3MuZGVzY3JpcHRpb247XG4gICAgICAgICAgICAgICAgaWYgKGNvbW1hbmRDbGFzcy5hbGlhc2VzIS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGNtZEFsaWFzZXMgPSBuZXcgQ29tbWFuZEVudW0oKTtcbiAgICAgICAgICAgICAgICAgICAgY21kQWxpYXNlcy5uYW1lID0gYCR7Y29tbWFuZFswXX1BbGlhc2VzYDtcbiAgICAgICAgICAgICAgICAgICAgY21kQWxpYXNlcy52YWx1ZXMgPSBjb21tYW5kQ2xhc3MuYWxpYXNlcyEuY29uY2F0KGNvbW1hbmRbMF0pO1xuICAgICAgICAgICAgICAgICAgICBjbWQuYWxpYXNlcyA9IGNtZEFsaWFzZXM7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgY29tbWFuZFsyXS5mb3JFYWNoKChhcmcsIGluZGV4KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHBhcmFtZXRlcnMgPSBhcmdcbiAgICAgICAgICAgICAgICAgICAgICAgIC5tYXAoKHBhcmFtZXRlcjogQ29tbWFuZEFyZ3VtZW50IHwgbnVsbCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghcGFyYW1ldGVyIHx8ICEocGFyYW1ldGVyIGFzIGFueSk/LmdldFBhcmFtZXRlcnMpIHJldHVybiBbXTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHBhcmFtZXRlcnMgPSBwYXJhbWV0ZXIuZ2V0UGFyYW1ldGVycyh0aGlzLnNlcnZlcik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBhcmFtZXRlcnMpIHJldHVybiBBcnJheS5mcm9tKHBhcmFtZXRlcnMudmFsdWVzKCkpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBhcmFtZXRlciBpbnN0YW5jZW9mIENvbW1hbmRBcmd1bWVudEVudGl0eSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ldyBDb21tYW5kUGFyYW1ldGVyKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbU5hbWU6ICd0YXJnZXQnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtVHlwZTogQ29tbWFuZFBhcmFtZXRlclR5cGUuVGFyZ2V0XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChwYXJhbWV0ZXIgaW5zdGFuY2VvZiBDb21tYW5kQXJndW1lbnRHYW1lbW9kZSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ldyBDb21tYW5kUGFyYW1ldGVyKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbU5hbWU6ICdnYW1lbW9kZScsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1UeXBlOiBDb21tYW5kUGFyYW1ldGVyVHlwZS5TdHJpbmdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBhcmFtZXRlci5jb25zdHJ1Y3Rvci5uYW1lID09PSAnU3RyaW5nQXJndW1lbnRUeXBlJylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ldyBDb21tYW5kUGFyYW1ldGVyKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbU5hbWU6ICd2YWx1ZScsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1UeXBlOiBDb21tYW5kUGFyYW1ldGVyVHlwZS5TdHJpbmdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBhcmFtZXRlci5jb25zdHJ1Y3Rvci5uYW1lID09PSAnSW50ZWdlckFyZ3VtZW50VHlwZScpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXcgQ29tbWFuZFBhcmFtZXRlcih7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1OYW1lOiAnbnVtYmVyJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbVR5cGU6IENvbW1hbmRQYXJhbWV0ZXJUeXBlLkludFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc2VydmVyLmdldExvZ2dlcigpLndhcm4oYEludmFsaWQgcGFyYW1ldGVyICR7cGFyYW1ldGVyLmNvbnN0cnVjdG9yLm5hbWV9YCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3IENvbW1hbmRQYXJhbWV0ZXIoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1OYW1lOiAndmFsdWUnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1UeXBlOiBDb21tYW5kUGFyYW1ldGVyVHlwZS5TdHJpbmdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgICAgIC5mbGF0KCk7XG4gICAgICAgICAgICAgICAgICAgIGNtZC5vdmVybG9hZHNbaW5kZXhdID0gcGFyYW1ldGVycztcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBway5jb21tYW5kRGF0YS5wdXNoKGNtZCk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICBhd2FpdCB0aGlzLmdldENvbm5lY3Rpb24oKS5zZW5kRGF0YVBhY2tldChwayk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0IHRoZSBjbGllbnQncyBtYXhpbXVtIHZpZXcgZGlzdGFuY2UuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gZGlzdGFuY2UgLSBUaGUgdmlldyBkaXN0YW5jZVxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBzZXRWaWV3RGlzdGFuY2UoZGlzdGFuY2U6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBwYWNrZXQgPSBuZXcgQ2h1bmtSYWRpdXNVcGRhdGVkUGFja2V0KCk7XG4gICAgICAgIHBhY2tldC5yYWRpdXMgPSB0aGlzLnBsYXllci52aWV3RGlzdGFuY2UgPSBkaXN0YW5jZTtcbiAgICAgICAgYXdhaXQgdGhpcy5jb25uZWN0aW9uLnNlbmREYXRhUGFja2V0KHBhY2tldCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHNlbmRBdHRyaWJ1dGVzKGF0dHJpYnV0ZXM/OiBBdHRyaWJ1dGVzKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IHZhbHVlID0gYXR0cmlidXRlcz8uZ2V0QXR0cmlidXRlcygpID8/IHRoaXMucGxheWVyLmF0dHJpYnV0ZXMuZ2V0QXR0cmlidXRlcygpO1xuXG4gICAgICAgIGNvbnN0IHBhY2tldCA9IG5ldyBVcGRhdGVBdHRyaWJ1dGVzUGFja2V0KCk7XG4gICAgICAgIHBhY2tldC5ydW50aW1lRW50aXR5SWQgPSB0aGlzLnBsYXllci5nZXRSdW50aW1lSWQoKTtcbiAgICAgICAgcGFja2V0LmF0dHJpYnV0ZXMgPSB2YWx1ZS5sZW5ndGggPiAwID8gdmFsdWUgOiB0aGlzLnBsYXllci5hdHRyaWJ1dGVzLmdldERlZmF1bHRzKCk7XG4gICAgICAgIHBhY2tldC50aWNrID0gQmlnSW50KHRoaXMucGxheWVyLmdldFNlcnZlcigpLmdldFRpY2soKSk7XG4gICAgICAgIGF3YWl0IHRoaXMuY29ubmVjdGlvbi5zZW5kRGF0YVBhY2tldChwYWNrZXQpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBzZW5kTWV0YWRhdGEobWV0YWRhdGE/OiBNZXRhZGF0YSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBwYWNrZXQgPSBuZXcgU2V0QWN0b3JEYXRhUGFja2V0KCk7XG4gICAgICAgIHBhY2tldC5ydW50aW1lRW50aXR5SWQgPSB0aGlzLnBsYXllci5nZXRSdW50aW1lSWQoKTtcbiAgICAgICAgcGFja2V0Lm1ldGFkYXRhID0gbWV0YWRhdGEgPz8gdGhpcy5wbGF5ZXIubWV0YWRhdGE7XG4gICAgICAgIHBhY2tldC50aWNrID0gQmlnSW50KHRoaXMucGxheWVyL