UNPKG

@jsprismarine/prismarine

Version:

Dedicated Minecraft Bedrock Edition server written in TypeScript

578 lines (572 loc) • 87.9 kB
'use strict'; Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } }); const BedrockData = require('@jsprismarine/bedrock-data'); const minecraft = require('@jsprismarine/minecraft'); const Heap = require('heap'); const command_CommandArguments = require('../command/CommandArguments.cjs.cjs'); const inventory_WindowIds = require('../inventory/WindowIds.cjs.cjs'); const item_Item = require('../item/Item.cjs.cjs'); const utils_UUID = require('../utils/UUID.cjs.cjs'); const world_BlockPosition = require('../world/BlockPosition.cjs.cjs'); const world_CoordinateUtils = require('../world/CoordinateUtils.cjs.cjs'); const world_chunk_Chunk = require('../world/chunk/Chunk.cjs.cjs'); require('./packet/ActorFallPacket.cjs.cjs'); require('./packet/AddActorPacket.cjs.cjs'); require('./packet/AddItemActorPacket.cjs.cjs'); const network_packet_AddPlayerPacket = require('./packet/AddPlayerPacket.cjs.cjs'); require('./packet/AnimatePacket.cjs.cjs'); require('./packet/AvailableActorIdentifiersPacket.cjs.cjs'); const network_packet_AvailableCommandsPacket = require('./packet/AvailableCommandsPacket.cjs.cjs'); const network_packet_BatchPacket = require('./packet/BatchPacket.cjs.cjs'); require('./packet/BiomeDefinitionListPacket.cjs.cjs'); require('./packet/ChangeDimensionPacket.cjs.cjs'); const network_packet_ChunkRadiusUpdatedPacket = require('./packet/ChunkRadiusUpdatedPacket.cjs.cjs'); require('./packet/CommandRequestPacket.cjs.cjs'); require('./packet/ContainerClosePacket.cjs.cjs'); require('./packet/ContainerOpenPacket.cjs.cjs'); const network_packet_CreativeContentPacket = require('./packet/CreativeContentPacket.cjs.cjs'); require('@jsprismarine/jsbinaryutils'); const network_packet_DisconnectPacket = require('./packet/DisconnectPacket.cjs.cjs'); require('./packet/EmoteListPacket.cjs.cjs'); require('./packet/InteractPacket.cjs.cjs'); const network_packet_InventoryContentPacket = require('./packet/InventoryContentPacket.cjs.cjs'); require('./packet/InventoryTransactionPacket.cjs.cjs'); require('./packet/ItemComponentPacket.cjs.cjs'); require('./packet/ItemStackRequestPacket.cjs.cjs'); require('./packet/ItemStackResponsePacket.cjs.cjs'); const network_packet_LevelChunkPacket = require('./packet/LevelChunkPacket.cjs.cjs'); require('./packet/LevelSoundEventPacket.cjs.cjs'); require('./packet/LoginPacket.cjs.cjs'); const network_packet_MobEquipmentPacket = require('./packet/MobEquipmentPacket.cjs.cjs'); require('./packet/MoveActorAbsolutePacket.cjs.cjs'); const network_packet_MovePlayerPacket = require('./packet/MovePlayerPacket.cjs.cjs'); const network_packet_NetworkChunkPublisherUpdatePacket = require('./packet/NetworkChunkPublisherUpdatePacket.cjs.cjs'); require('./packet/OnScreenTextureAnimationPacket.cjs.cjs'); require('./packet/PacketViolationWarningPacket.cjs.cjs'); require('./packet/PlaySoundPacket.cjs.cjs'); const network_packet_PlayStatusPacket = require('./packet/PlayStatusPacket.cjs.cjs'); require('./packet/PlayerActionPacket.cjs.cjs'); const network_packet_PlayerListPacket = require('./packet/PlayerListPacket.cjs.cjs'); require('./packet/PlayerSkinPacket.cjs.cjs'); const network_packet_RemoveActorPacket = require('./packet/RemoveActorPacket.cjs.cjs'); require('./packet/RequestChunkRadiusPacket.cjs.cjs'); require('./packet/RequestNetworkSettingsPacket.cjs.cjs'); require('./packet/ResourcePackResponsePacket.cjs.cjs'); require('./packet/ResourcePackStackPacket.cjs.cjs'); require('./packet/ResourcePacksInfoPacket.cjs.cjs'); require('./packet/ServerSettingsRequestPacket.cjs.cjs'); const network_packet_SetActorDataPacket = require('./packet/SetActorDataPacket.cjs.cjs'); require('./packet/SetDefaultGametypePacket.cjs.cjs'); require('./packet/SetHealthPacket.cjs.cjs'); require('./packet/SetLocalPlayerAsInitializedPacket.cjs.cjs'); const network_packet_SetPlayerGametypePacket = require('./packet/SetPlayerGametypePacket.cjs.cjs'); const network_packet_SetTimePacket = require('./packet/SetTimePacket.cjs.cjs'); require('./packet/ShowProfilePacket.cjs.cjs'); require('./packet/StartGamePacket.cjs.cjs'); const network_packet_TextPacket = require('./packet/TextPacket.cjs.cjs'); require('./packet/TickSyncPacket.cjs.cjs'); require('./packet/TransferPacket.cjs.cjs'); const network_packet_UpdateAdventureSettingsPacket = require('./packet/UpdateAdventureSettingsPacket.cjs.cjs'); const network_packet_UpdateAttributesPacket = require('./packet/UpdateAttributesPacket.cjs.cjs'); require('./packet/UpdateBlockPacket.cjs.cjs'); require('./packet/WorldEventPacket.cjs.cjs'); const network_packet_UpdateAbilitiesPacket = require('./packet/UpdateAbilitiesPacket.cjs.cjs'); const network_type_CommandData = require('./type/CommandData.cjs.cjs'); const network_type_CommandEnum = require('./type/CommandEnum.cjs.cjs'); const network_type_CommandParameter = require('./type/CommandParameter.cjs.cjs'); const network_type_MovementType = require('./type/MovementType.cjs.cjs'); const network_type_PermissionType = require('./type/PermissionType.cjs.cjs'); const network_type_PlayerPermissionType = require('./type/PlayerPermissionType.cjs.cjs'); const network_type_TextType = require('./type/TextType.cjs.cjs'); const _interopDefault = e => e && e.__esModule ? e : { default: e }; const Heap__default = /*#__PURE__*/_interopDefault(Heap); class PlayerSession { 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 network_packet_BatchPacket.default(); for (const chunk of chunksToSend) { const pk = new 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 = 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 network_packet_UpdateAdventureSettingsPacket.default(); packet.worldImmutable = target.gamemode === minecraft.Gametype.SPECTATOR; packet.noAttackingPlayers = target.gamemode === minecraft.Gametype.SPECTATOR; packet.noAttackingMobs = target.gamemode === 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 network_packet_UpdateAbilitiesPacket.AbilityLayer(); mainLayer.layerType = network_packet_UpdateAbilitiesPacket.AbilityLayerType.BASE; mainLayer.layerFlags = /* @__PURE__ */ new Map([ [network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.FLY_SPEED, true], [network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.WALK_SPEED, true], [network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.MAY_FLY, target.metadata.canFly], [network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.FLYING, target.isFlying()], [network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.NO_CLIP, target.gamemode === minecraft.Gametype.SPECTATOR], [network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.OPERATOR_COMMANDS, target.isOp()], [network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.TELEPORT, target.isOp()], [network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.INVULNERABLE, target.gamemode === minecraft.Gametype.SPECTATOR], [network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.MUTED, false], [network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.WORLD_BUILDER, false], [network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.INSTABUILD, target.gamemode === minecraft.Gametype.SPECTATOR], [network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.LIGHTNING, false], [network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.BUILD, target.gamemode !== minecraft.Gametype.SPECTATOR], [network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.MINE, target.gamemode !== minecraft.Gametype.SPECTATOR], [network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.DOORS_AND_SWITCHES, target.gamemode !== minecraft.Gametype.SPECTATOR], [network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.OPEN_CONTAINERS, target.gamemode !== minecraft.Gametype.SPECTATOR], [network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.ATTACK_PLAYERS, target.gamemode !== minecraft.Gametype.SPECTATOR], [network_packet_UpdateAbilitiesPacket.AbilityLayerFlag.ATTACK_MOBS, target.gamemode !== minecraft.Gametype.SPECTATOR] ]); mainLayer.flySpeed = 0.05; mainLayer.walkSpeed = 0.1; const packet = new network_packet_UpdateAbilitiesPacket.default(); packet.commandPermission = target.isOp() ? network_type_PermissionType.default.Operator : network_type_PermissionType.default.Normal; packet.playerPermission = target.isOp() ? network_type_PlayerPermissionType.default.Operator : network_type_PlayerPermissionType.default.Member; packet.targetActorUniqueId = target.getRuntimeId(); packet.abilityLayers = [mainLayer]; await this.send(packet); } async needNewChunks(forceResend = false, dist) { const currentXChunk = world_CoordinateUtils.default.fromBlockToChunk(this.player.getX()); const currentZChunk = world_CoordinateUtils.default.fromBlockToChunk(this.player.getZ()); const viewDistance = this.player.viewDistance || dist || 0; const chunksToSendHeap = new Heap__default.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 = 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 = 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] = 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] = 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 network_packet_InventoryContentPacket.default(); pk.items = this.player.getInventory().getItems(true); pk.windowId = inventory_WindowIds.WindowIds.INVENTORY; } async sendCreativeContents(empty = false) { const pk = new network_packet_CreativeContentPacket.default(); if (empty) { await this.connection.sendDataPacket(pk); return; } const entries = [ ...this.player.getServer().getBlockManager().getBlocks(), ...this.player.getServer().getItemManager().getItems() ]; BedrockData.creativeitems.forEach((item) => { pk.items.push( ...entries.filter((entry) => { return entry.meta === (item.damage ?? 0) && entry.getId() === item.id; }).map( (entry) => new 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 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 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 network_packet_SetPlayerGametypePacket.default(); packet.gametype = gamemode ?? this.player.gamemode; await this.connection.sendDataPacket(packet); } async sendNetworkChunkPublisher(distance, savedChunks) { const pk = new network_packet_NetworkChunkPublisherUpdatePacket.default(); pk.position = world_BlockPosition.default.fromVector3(this.player.getPosition()); pk.radius = distance << 4; pk.savedChunks = savedChunks; await this.connection.sendDataPacket(pk); } async sendAvailableCommands() { const playerEnum = new network_type_CommandEnum.CommandEnum(); playerEnum.soft = true; playerEnum.name = "Player"; playerEnum.values = this.player.getServer().getSessionManager().getAllPlayers().map((player) => player.getName()); const pk = new network_packet_AvailableCommandsPacket.default(); pk.softEnums = [playerEnum]; this.server.getCommandManager().getCommandsList().forEach((command) => { const commandClass = Array.from(this.server.getCommandManager().getCommands().values()).find( (cmd2) => cmd2.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 network_type_CommandData.default(); cmd.commandName = command[0]; cmd.commandDescription = commandClass.description; if (commandClass.aliases.length > 0) { const cmdAliases = new 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 parameters2 = parameter.getParameters(this.server); if (parameters2) return Array.from(parameters2.values()); if (parameter instanceof command_CommandArguments.CommandArgumentEntity) return [ new network_type_CommandParameter.default({ paramName: "target", paramType: network_type_CommandParameter.CommandParameterType.Target }) ]; if (parameter instanceof command_CommandArguments.CommandArgumentGamemode) return [ new network_type_CommandParameter.default({ paramName: "gamemode", paramType: network_type_CommandParameter.CommandParameterType.String }) ]; if (parameter.constructor.name === "StringArgumentType") return [ new network_type_CommandParameter.default({ paramName: "value", paramType: network_type_CommandParameter.CommandParameterType.String }) ]; if (parameter.constructor.name === "IntegerArgumentType") return [ new network_type_CommandParameter.default({ paramName: "number", paramType: network_type_CommandParameter.CommandParameterType.Int }) ]; this.server.getLogger().warn(`Invalid parameter ${parameter.constructor.name}`); return [ new network_type_CommandParameter.default({ paramName: "value", paramType: 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 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 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 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 = network_type_TextType.default.Raw }) { if (!message) throw new Error("A message is required"); const pk = new 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 = world_chunk_Chunk.default.packXZ(chunk.getX(), chunk.getZ()); const packet = new 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 = network_type_MovementType.default.Normal) { const packet = new 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 === 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 network_packet_PlayerListPacket.PlayerListEntry({ uuid: 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 network_packet_PlayerListPacket.default(); packet.type = 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 network_packet_PlayerListPacket.PlayerListEntry({ uuid: utils_UUID.default.fromString(this.player.getUUID()) }); this.server.getSessionManager().getPlayerList().delete(this.player.getUUID()); const packet = new network_packet_PlayerListPacket.default(); packet.type = 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 network_packet_PlayerListPacket.default(); packet.type = 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 network_packet_AddPlayerPacket.default(); pk.uuid = 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 network_packet_RemoveActorPacket.default(); pk.uniqueEntityId = this.player.getRuntimeId(); await player.getNetworkSession().getConnection().sendDataPacket(pk); } async sendPlayStatus(status) { const pk = new network_packet_PlayStatusPacket.default(); pk.status = status; await this.connection.sendDataPacket(pk, true); } async kick(reason = "unknown reason") { const pk = new network_packet_DisconnectPacket.default(); pk.skipMessage = false; pk.message = reason; await this.connection.sendDataPacket(pk, true); } getConnection() { return this.connection; } getPlayer() { return this.player; } } exports.default = PlayerSession; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGxheWVyU2Vzc2lvbi5janMuY2pzIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbmV0d29yay9QbGF5ZXJTZXNzaW9uLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNyZWF0aXZlaXRlbXMgYXMgQ3JlYXRpdmVJdGVtcyB9IGZyb20gJ0Bqc3ByaXNtYXJpbmUvYmVkcm9jay1kYXRhJztcbmltcG9ydCB7IEdhbWV0eXBlIH0gZnJvbSAnQGpzcHJpc21hcmluZS9taW5lY3JhZnQnO1xuaW1wb3J0IEhlYXAgZnJvbSAnaGVhcCc7XG5pbXBvcnQgdHlwZSBQbGF5ZXIgZnJvbSAnLi4vUGxheWVyJztcbmltcG9ydCB0eXBlIFNlcnZlciBmcm9tICcuLi9TZXJ2ZXInO1xuaW1wb3J0IHR5cGUgeyBDb21tYW5kQXJndW1lbnQgfSBmcm9tICcuLi9jb21tYW5kL0NvbW1hbmRBcmd1bWVudHMnO1xuaW1wb3J0IHsgQ29tbWFuZEFyZ3VtZW50RW50aXR5LCBDb21tYW5kQXJndW1lbnRHYW1lbW9kZSB9IGZyb20gJy4uL2NvbW1hbmQvQ29tbWFuZEFyZ3VtZW50cyc7XG5pbXBvcnQgdHlwZSB7IEF0dHJpYnV0ZXMgfSBmcm9tICcuLi9lbnRpdHkvQXR0cmlidXRlJztcbmltcG9ydCB0eXBlIHsgTWV0YWRhdGEgfSBmcm9tICcuLi9lbnRpdHkvTWV0YWRhdGEnO1xuaW1wb3J0IHsgV2luZG93SWRzIH0gZnJvbSAnLi4vaW52ZW50b3J5L1dpbmRvd0lkcyc7XG5pbXBvcnQgeyBJdGVtIH0gZnJvbSAnLi4vaXRlbS9JdGVtJztcbmltcG9ydCBVVUlEIGZyb20gJy4uL3V0aWxzL1VVSUQnO1xuaW1wb3J0IEJsb2NrUG9zaXRpb24gZnJvbSAnLi4vd29ybGQvQmxvY2tQb3NpdGlvbic7XG5pbXBvcnQgQ29vcmRpbmF0ZVV0aWxzIGZyb20gJy4uL3dvcmxkL0Nvb3JkaW5hdGVVdGlscyc7XG5pbXBvcnQgQ2h1bmsgZnJvbSAnLi4vd29ybGQvY2h1bmsvQ2h1bmsnO1xuaW1wb3J0IHR5cGUgQ2xpZW50Q29ubmVjdGlvbiBmcm9tICcuL0NsaWVudENvbm5lY3Rpb24nO1xuaW1wb3J0IHR5cGUgeyBEYXRhUGFja2V0IH0gZnJvbSAnLi9QYWNrZXRzJztcbmltcG9ydCB7IEJhdGNoUGFja2V0IH0gZnJvbSAnLi9QYWNrZXRzJztcbmltcG9ydCBBZGRQbGF5ZXJQYWNrZXQgZnJvbSAnLi9wYWNrZXQvQWRkUGxheWVyUGFja2V0JztcbmltcG9ydCBBdmFpbGFibGVDb21tYW5kc1BhY2tldCBmcm9tICcuL3BhY2tldC9BdmFpbGFibGVDb21tYW5kc1BhY2tldCc7XG5pbXBvcnQgQ2h1bmtSYWRpdXNVcGRhdGVkUGFja2V0IGZyb20gJy4vcGFja2V0L0NodW5rUmFkaXVzVXBkYXRlZFBhY2tldCc7XG5pbXBvcnQgQ3JlYXRpdmVDb250ZW50UGFja2V0IGZyb20gJy4vcGFja2V0L0NyZWF0aXZlQ29udGVudFBhY2tldCc7XG5pbXBvcnQgRGlzY29ubmVjdFBhY2tldCBmcm9tICcuL3BhY2tldC9EaXNjb25uZWN0UGFja2V0JztcbmltcG9ydCBJbnZlbnRvcnlDb250ZW50UGFja2V0IGZyb20gJy4vcGFja2V0L0ludmVudG9yeUNvbnRlbnRQYWNrZXQnO1xuaW1wb3J0IExldmVsQ2h1bmtQYWNrZXQgZnJvbSAnLi9wYWNrZXQvTGV2ZWxDaHVua1BhY2tldCc7XG5pbXBvcnQgTW9iRXF1aXBtZW50UGFja2V0IGZyb20gJy4vcGFja2V0L01vYkVxdWlwbWVudFBhY2tldCc7XG5pbXBvcnQgTW92ZVBsYXllclBhY2tldCBmcm9tICcuL3BhY2tldC9Nb3ZlUGxheWVyUGFja2V0JztcbmltcG9ydCB0eXBlIHsgQ2h1bmtDb29yZCB9IGZyb20gJy4vcGFja2V0L05ldHdvcmtDaHVua1B1Ymxpc2hlclVwZGF0ZVBhY2tldCc7XG5pbXBvcnQgTmV0d29ya0NodW5rUHVibGlzaGVyVXBkYXRlUGFja2V0IGZyb20gJy4vcGFja2V0L05ldHdvcmtDaHVua1B1Ymxpc2hlclVwZGF0ZVBhY2tldCc7XG5pbXBvcnQgUGxheVN0YXR1c1BhY2tldCBmcm9tICcuL3BhY2tldC9QbGF5U3RhdHVzUGFja2V0JztcbmltcG9ydCBQbGF5ZXJMaXN0UGFja2V0LCB7IFBsYXllckxpc3RBY3Rpb24sIFBsYXllckxpc3RFbnRyeSB9IGZyb20gJy4vcGFja2V0L1BsYXllckxpc3RQYWNrZXQnO1xuaW1wb3J0IFJlbW92ZUFjdG9yUGFja2V0IGZyb20gJy4vcGFja2V0L1JlbW92ZUFjdG9yUGFja2V0JztcbmltcG9ydCBTZXRBY3RvckRhdGFQYWNrZXQgZnJvbSAnLi9wYWNrZXQvU2V0QWN0b3JEYXRhUGFja2V0JztcbmltcG9ydCBTZXRQbGF5ZXJHYW1ldHlwZVBhY2tldCBmcm9tICcuL3BhY2tldC9TZXRQbGF5ZXJHYW1ldHlwZVBhY2tldCc7XG5pbXBvcnQgU2V0VGltZVBhY2tldCBmcm9tICcuL3BhY2tldC9TZXRUaW1lUGFja2V0JztcbmltcG9ydCBUZXh0UGFja2V0IGZyb20gJy4vcGFja2V0L1RleHRQYWNrZXQnO1xuaW1wb3J0IFVwZGF0ZUFiaWxpdGllc1BhY2tldCwge1xuICAgIEFiaWxpdHlMYXllcixcbiAgICBBYmlsaXR5TGF5ZXJGbGFnLFxuICAgIEFiaWxpdHlMYXllclR5cGVcbn0gZnJvbSAnLi9wYWNrZXQvVXBkYXRlQWJpbGl0aWVzUGFja2V0JztcbmltcG9ydCBVcGRhdGVBZHZlbnR1cmVTZXR0aW5nc1BhY2tldCBmcm9tICcuL3BhY2tldC9VcGRhdGVBZHZlbnR1cmVTZXR0aW5nc1BhY2tldCc7XG5pbXBvcnQgVXBkYXRlQXR0cmlidXRlc1BhY2tldCBmcm9tICcuL3BhY2tldC9VcGRhdGVBdHRyaWJ1dGVzUGFja2V0JztcbmltcG9ydCBDb21tYW5kRGF0YSBmcm9tICcuL3R5cGUvQ29tbWFuZERhdGEnO1xuaW1wb3J0IHsgQ29tbWFuZEVudW0gfSBmcm9tICcuL3R5cGUvQ29tbWFuZEVudW0nO1xuaW1wb3J0IENvbW1hbmRQYXJhbWV0ZXIsIHsgQ29tbWFuZFBhcmFtZXRlclR5cGUgfSBmcm9tICcuL3R5cGUvQ29tbWFuZFBhcmFtZXRlcic7XG5pbXBvcnQgTW92ZW1lbnRUeXBlIGZyb20gJy4vdHlwZS9Nb3ZlbWVudFR5cGUnO1xuaW1wb3J0IFBlcm1pc3Npb25UeXBlIGZyb20gJy4vdHlwZS9QZXJtaXNzaW9uVHlwZSc7XG5pbXBvcnQgUGxheWVyUGVybWlzc2lvblR5cGUgZnJvbSAnLi90eXBlL1BsYXllclBlcm1pc3Npb25UeXBlJztcbmltcG9ydCBUZXh0VHlwZSBmcm9tICcuL3R5cGUvVGV4dFR5cGUnO1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBQbGF5ZXJTZXNzaW9uIHtcbiAgICBwcml2YXRlIGNvbm5lY3Rpb246IENsaWVudENvbm5lY3Rpb247XG4gICAgcHJpdmF0ZSByZWFkb25seSBzZXJ2ZXI6IFNlcnZlcjtcbiAgICBwcml2YXRlIHBsYXllcjogUGxheWVyO1xuXG4gICAgcHJpdmF0ZSByZWFkb25seSBjaHVua1NlbmRRdWV1ZTogQ2h1bmtbXSA9IFtdO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgbG9hZGVkQ2h1bmtzOiBTZXQ8YmlnaW50PiA9IG5ldyBTZXQoKTtcbiAgICBwcml2YXRlIHJlYWRvbmx5IGxvYWRpbmdDaHVua3M6IFNldDxiaWdpbnQ+ID0gbmV3IFNldCgpO1xuXG4gICAgcHVibGljIGNvbnN0cnVjdG9yKHNlcnZlcjogU2VydmVyLCBjb25uZWN0aW9uOiBDbGllbnRDb25uZWN0aW9uLCBwbGF5ZXI6IFBsYXllcikge1xuICAgICAgICB0aGlzLnNlcnZlciA9IHNlcnZlcjtcbiAgICAgICAgdGhpcy5jb25uZWN0aW9uID0gY29ubmVjdGlvbjtcbiAgICAgICAgdGhpcy5wbGF5ZXIgPSBwbGF5ZXI7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHVwZGF0ZShfdGljazogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICh0aGlzLmNodW5rU2VuZFF1ZXVlLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGNvbnN0IGNodW5rc1RvU2VuZCA9IHRoaXMuY2h1bmtTZW5kUXVldWUuc3BsaWNlKDAsIE1hdGgubWluKHRoaXMuY2h1bmtTZW5kUXVldWUubGVuZ3RoLCA1MCkpO1xuICAgICAgICAgICAgY29uc3QgYmF0Y2ggPSBuZXcgQmF0Y2hQYWNrZXQoKTtcbiAgICAgICAgICAgIGZvciAoY29uc3QgY2h1bmsgb2YgY2h1bmtzVG9TZW5kKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgcGsgPSBuZXcgTGV2ZWxDaHVua1BhY2tldCgpO1xuICAgICAgICAgICAgICAgIHBrLmNodW5rWCA9IGNodW5rLmdldFgoKTtcbiAgICAgICAgICAgICAgICBway5jaHVua1ogPSBjaHVuay5nZXRaKCk7XG4gICAgICAgICAgICAgICAgcGsuY2xpZW50U3ViQ2h1bmtSZXF1ZXN0c0VuYWJsZWQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBway5zdWJDaHVua0NvdW50ID0gY2h1bmsuZ2V0VG9wRW1wdHkoKSArIDQ7XG4gICAgICAgICAgICAgICAgcGsuZGF0YSA9IGNodW5rLm5ldHdvcmtTZXJpYWxpemUoKTtcbiAgICAgICAgICAgICAgICBiYXRjaC5hZGRQYWNrZXQocGspO1xuXG4gICAgICAgICAgICAgICAgY29uc3QgaGFzaCA9IENodW5rLnBhY2tYWihjaHVuay5nZXRYKCksIGNodW5rLmdldFooKSk7XG4gICAgICAgICAgICAgICAgdGhpcy5sb2FkZWRDaHVua3MuYWRkKGhhc2gpO1xuICAgICAgICAgICAgICAgIHRoaXMubG9hZGluZ0NodW5rcy5kZWxldGUoaGFzaCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uc2VuZEJhdGNoKGJhdGNoLCBmYWxzZSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnBsYXllci52aWV3RGlzdGFuY2UgJiYgKGF3YWl0IHRoaXMubmVlZE5ld0NodW5rcygpKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgc2VuZChwYWNrZXQ6IERhdGFQYWNrZXQpIHtcbiAgICAgICAgdGhpcy5jb25uZWN0aW9uLnNlbmREYXRhUGFja2V0KHBhY2tldCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTm90aWZ5IGEgY2xpZW50IGFib3V0IGNoYW5nZShzKSB0byB0aGUgYWR2ZW50dXJlIHNldHRpbmdzLlxuICAgICAqXG4gICAgICogQHBhcmFtIHBsYXllciAtIFRoZSBjbGllbnQtY29udHJvbGxlZCBlbnRpdHlcbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgc2VuZFNldHRpbmdzKHBsYXllcj86IFBsYXllcik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCB0YXJnZXQgPSBwbGF5ZXIgPz8gdGhpcy5wbGF5ZXI7XG5cbiAgICAgICAgY29uc3QgcGFja2V0ID0gbmV3IFVwZGF0ZUFkdmVudHVyZVNldHRpbmdzUGFja2V0KCk7XG4gICAgICAgIHBhY2tldC53b3JsZEltbXV0YWJsZSA9IHRhcmdldC5nYW1lbW9kZSA9PT0gR2FtZXR5cGUuU1BFQ1RBVE9SO1xuICAgICAgICBwYWNrZXQubm9BdHRhY2tpbmdQbGF5ZXJzID0gdGFyZ2V0LmdhbWVtb2RlID09PSBHYW1ldHlwZS5TUEVDVEFUT1I7XG4gICAgICAgIHBhY2tldC5ub0F0dGFja2luZ01vYnMgPSB0YXJnZXQuZ2FtZW1vZGUgPT09IEdhbWV0eXBlLlNQRUNUQVRPUjtcbiAgICAgICAgcGFja2V0LmF1dG9KdW1wID0gdHJ1ZTtcbiAgICAgICAgcGFja2V0LnNob3dOYW1lVGFncyA9IHRydWU7XG4gICAgICAgIGF3YWl0IHRoaXMuY29ubmVjdGlvbi5zZW5kRGF0YVBhY2tldChwYWNrZXQpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBzZW5kQWJpbGl0aWVzKHBsYXllcj86IFBsYXllcik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCB0YXJnZXQgPSBwbGF5ZXIgPz8gdGhpcy5wbGF5ZXI7XG5cbiAgICAgICAgY29uc3QgbWFpbkxheWVyID0gbmV3IEFiaWxpdHlMYXllcigpO1xuICAgICAgICBtYWluTGF5ZXIubGF5ZXJUeXBlID0gQWJpbGl0eUxheWVyVHlwZS5CQVNFO1xuICAgICAgICBtYWluTGF5ZXIubGF5ZXJGbGFncyA9IG5ldyBNYXAoW1xuICAgICAgICAgICAgW0FiaWxpdHlMYXllckZsYWcuRkxZX1NQRUVELCB0cnVlXSxcbiAgICAgICAgICAgIFtBYmlsaXR5TGF5ZXJGbGFnLldBTEtfU1BFRUQsIHRydWVdLFxuICAgICAgICAgICAgW0FiaWxpdHlMYXllckZsYWcuTUFZX0ZMWSwgdGFyZ2V0Lm1ldGFkYXRhLmNhbkZseV0sXG4gICAgICAgICAgICBbQWJpbGl0eUxheWVyRmxhZy5GTFlJTkcsIHRhcmdldC5pc0ZseWluZygpXSxcbiAgICAgICAgICAgIFtBYmlsaXR5TGF5ZXJGbGFnLk5PX0NMSVAsIHRhcmdldC5nYW1lbW9kZSA9PT0gR2FtZXR5cGUuU1BFQ1RBVE9SXSxcbiAgICAgICAgICAgIFtBYmlsaXR5TGF5ZXJGbGFnLk9QRVJBVE9SX0NPTU1BTkRTLCB0YXJnZXQuaXNPcCgpXSxcbiAgICAgICAgICAgIFtBYmlsaXR5TGF5ZXJGbGFnLlRFTEVQT1JULCB0YXJnZXQuaXNPcCgpXSxcbiAgICAgICAgICAgIFtBYmlsaXR5TGF5ZXJGbGFnLklOVlVMTkVSQUJMRSwgdGFyZ2V0LmdhbWVtb2RlID09PSBHYW1ldHlwZS5TUEVDVEFUT1JdLFxuICAgICAgICAgICAgW0FiaWxpdHlMYXllckZsYWcuTVVURUQsIGZhbHNlXSxcbiAgICAgICAgICAgIFtBYmlsaXR5TGF5ZXJGbGFnLldPUkxEX0JVSUxERVIsIGZhbHNlXSxcbiAgICAgICAgICAgIFtBYmlsaXR5TGF5ZXJGbGFnLklOU1RBQlVJTEQsIHRhcmdldC5nYW1lbW9kZSA9PT0gR2FtZXR5cGUuU1BFQ1RBVE9SXSxcbiAgICAgICAgICAgIFtBYmlsaXR5TGF5ZXJGbGFnLkxJR0hUTklORywgZmFsc2VdLFxuICAgICAgICAgICAgW0FiaWxpdHlMYXllckZsYWcuQlVJTEQsIHRhcmdldC5nYW1lbW9kZSAhPT0gR2FtZXR5cGUuU1BFQ1RBVE9SXSxcbiAgICAgICAgICAgIFtBYmlsaXR5TGF5ZXJGbGFnLk1JTkUsIHRhcmdldC5nYW1lbW9kZSAhPT0gR2FtZXR5cGUuU1BFQ1RBVE9SXSxcbiAgICAgICAgICAgIFtBYmlsaXR5TGF5ZXJGbGFnLkRPT1JTX0FORF9TV0lUQ0hFUywgdGFyZ2V0LmdhbWVtb2RlICE9PSBHYW1ldHlwZS5TUEVDVEFUT1JdLFxuICAgICAgICAgICAgW0FiaWxpdHlMYXllckZsYWcuT1BFTl9DT05UQUlORVJTLCB0YXJnZXQuZ2FtZW1vZGUgIT09IEdhbWV0eXBlLlNQRUNUQVRPUl0sXG4gICAgICAgICAgICBbQWJpbGl0eUxheWVyRmxhZy5BVFRBQ0tfUExBWUVSUywgdGFyZ2V0LmdhbWVtb2RlICE9PSBHYW1ldHlwZS5TUEVDVEFUT1JdLFxuICAgICAgICAgICAgW0FiaWxpdHlMYXllckZsYWcuQVRUQUNLX01PQlMsIHRhcmdldC5nYW1lbW9kZSAhPT0gR2FtZXR5cGUuU1BFQ1RBVE9SXVxuICAgICAgICBdKTtcbiAgICAgICAgbWFpbkxheWVyLmZseVNwZWVkID0gMC4wNTtcbiAgICAgICAgbWFpbkxheWVyLndhbGtTcGVlZCA9IDAuMTtcblxuICAgICAgICBjb25zdCBwYWNrZXQgPSBuZXcgVXBkYXRlQWJpbGl0aWVzUGFja2V0KCk7XG4gICAgICAgIHBhY2tldC5jb21tYW5kUGVybWlzc2lvbiA9IHRhcmdldC5pc09wKCkgPyBQZXJtaXNzaW9uVHlwZS5PcGVyYXRvciA6IFBlcm1pc3Npb25UeXBlLk5vcm1hbDtcbiAgICAgICAgcGFja2V0LnBsYXllclBlcm1pc3Npb24gPSB0YXJnZXQuaXNPcCgpID8gUGxheWVyUGVybWlzc2lvblR5cGUuT3BlcmF0b3IgOiBQbGF5ZXJQZXJtaXNzaW9uVHlwZS5NZW1iZXI7XG4gICAgICAgIHBhY2tldC50YXJnZXRBY3RvclVuaXF1ZUlkID0gdGFyZ2V0LmdldFJ1bnRpbWVJZCgpO1xuICAgICAgICBwYWNrZXQuYWJpbGl0eUxheWVycyA9IFttYWluTGF5ZXJdO1xuICAgICAgICBhd2FpdCB0aGlzLnNlbmQocGFja2V0KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgbmVlZE5ld0NodW5rcyhmb3JjZVJlc2VuZCA9IGZhbHNlLCBkaXN0PzogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IGN1cnJlbnRYQ2h1bmsgPSBDb29yZGluYXRlVXRpbHMuZnJvbUJsb2NrVG9DaHVuayh0aGlzLnBsYXllci5nZXRYKCkpO1xuICAgICAgICBjb25zdCBjdXJyZW50WkNodW5rID0gQ29vcmRpbmF0ZVV0aWxzLmZyb21CbG9ja1RvQ2h1bmsodGhpcy5wbGF5ZXIuZ2V0WigpKTtcblxuICAgICAgICBjb25zdCB2aWV3RGlzdGFuY2UgPSB0aGlzLnBsYXllci52aWV3RGlzdGFuY2UgfHwgZGlzdCB8fCAwO1xuXG4gICAgICAgIGNvbnN0IGNodW5rc1RvU2VuZEhlYXAgPSBuZXcgSGVhcCgoYTogbnVtYmVyW10sIGI6IG51bWJlcltdKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBkaXN0WEZpcnN0ID0gTWF0aC5hYnMoYVswXSEgLSBjdXJyZW50WENodW5rKTtcbiAgICAgICAgICAgIGNvbnN0IGRpc3RYU2Vjb25kID0gTWF0aC5hYnMoYlswXSEgLSBjdXJyZW50WENodW5rKTtcblxuICAgICAgICAgICAgY29uc3QgZGlzdFpGaXJzdCA9IE1hdGguYWJzKGFbMV0hIC0gY3VycmVudFpDaHVuayk7XG4gICAgICAgICAgICBjb25zdCBkaXN0WlNlY29uZCA9IE1hdGguYWJzKGJbMV0hIC0gY3VycmVudFpDaHVuayk7XG5cbiAgICAgICAgICAgIHJldHVybiBkaXN0WEZpcnN0ICsgZGlzdFpGaXJzdCA+IGRpc3RYU2Vjb25kICsgZGlzdFpTZWNvbmQgPyAxIDogLTE7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGZvciAobGV0IHNlbmRYQ2h1bmsgPSAtdmlld0Rpc3RhbmNlOyBzZW5kWENodW5rIDw9IHZpZXdEaXN0YW5jZTsgc2VuZFhDaHVuaysrKSB7XG4gICAgICAgICAgICBmb3IgKGxldCBzZW5kWkNodW5rID0gLXZpZXdEaXN0YW5jZTsgc2VuZFpDaHVuayA8PSB2aWV3RGlzdGFuY2U7IHNlbmRaQ2h1bmsrKykge1xuICAgICAgICAgICAgICAgIGlmIChzZW5kWENodW5rICogc2VuZFhDaHVuayArIHNlbmRaQ2h1bmsgKiBzZW5kWkNodW5rID4gdmlld0Rpc3RhbmNlICogdmlld0Rpc3RhbmNlKSBjb250aW51ZTsgLy8gZWFybHkgZXhpdCBpZiBjaHVuayBpcyBvdXRzaWRlIG9mIHZpZXcgZGlzdGFuY2VcbiAgICAgICAgICAgICAgICBjb25zdCBuZXdDaHVuayA9IFtjdXJyZW50WENodW5rICsgc2VuZFhDaHVuaywgY3VycmVudFpDaHVuayArIHNlbmRaQ2h1bmtdO1xuICAgICAgICAgICAgICAgIGNvbnN0IGhhc2ggPSBDaHVuay5wYWNrWFoobmV3Q2h1bmtbMF0hLCBuZXdDaHVua1sxXSEpO1xuXG4gICAgICAgICAgICAgICAgaWYgKGZvcmNlUmVzZW5kKSB7XG4gICAgICAgICAgICAgICAgICAgIGNodW5rc1RvU2VuZEhlYXAucHVzaChuZXdDaHVuayk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmICghdGhpcy5sb2FkZWRDaHVua3MuaGFzKGhhc2gpICYmICF0aGlzLmxvYWRpbmdDaHVua3MuaGFzKGhhc2gpKSB7XG4gICAgICAgICAgICAgICAgICAgIGNodW5rc1RvU2VuZEhlYXAucHVzaChuZXdDaHVuayk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgd2hpbGUgKGNodW5rc1RvU2VuZEhlYXAuc2l6ZSgpID4gMCkge1xuICAgICAgICAgICAgY29uc3QgY2xvc2VzdENodW5rID0gY2h1bmtzVG9TZW5kSGVhcC5wb3AoKSE7XG4gICAgICAgICAgICBjb25zdCBoYXNoID0gQ2h1bmsucGFja1haKGNsb3Nlc3RDaHVua1swXSEsIGNsb3Nlc3RDaHVua1sxXSEpO1xuICAgICAgICAgICAgaWYgKGZvcmNlUmVzZW5kKSB7XG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLmxvYWRlZENodW5rcy5oYXMoaGFzaCkgJiYgIXRoaXMubG9hZGluZ0NodW5rcy5oYXMoaGFzaCkpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2FkaW5nQ2h1bmtzLmFkZChoYXNoKTtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5yZXF1ZXN0Q2h1bmsoY2xvc2VzdENodW5rWzBdISwgY2xvc2VzdENodW5rWzFdISk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgbG9hZGVkQ2h1bmsgPSBhd2FpdCB0aGlzLnBsYXllci5nZXRXb3JsZCgpLmdldENodW5rKGNsb3Nlc3RDaHVua1swXSEsIGNsb3Nlc3RDaHVua1sxXSEpO1xuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnNlbmRDaHVuayhsb2FkZWRDaHVuayk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLmxvYWRpbmdDaHVua3MuYWRkKGhhc2gpO1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucmVxdWVzdENodW5rKGNsb3Nlc3RDaHVua1swXSEsIGNsb3Nlc3RDaHVua1sxXSEpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHVubG9hZGVkID0gZmFsc2U7XG5cbiAgICAgICAgZm9yIChjb25zdCBoYXNoIG9mIHRoaXMubG9hZGVkQ2h1bmtzKSB7XG4gICAgICAgICAgICBjb25zdCBbeCwgel0gPSBDaHVuay51bnBhY2tYWihoYXNoKTtcblxuICAgICAgICAgICAgaWYgKE1hdGguYWJzKHghIC0gY3VycmVudFhDaHVuaykgPiB2aWV3RGlzdGFuY2UgfHwgTWF0aC5hYnMoeiEgLSBjdXJyZW50WkNodW5rKSA+IHZpZXdEaXN0YW5jZSkge1xuICAgICAgICAgICAgICAgIHVubG9hZGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB0aGlzLmxvYWRlZENodW5rcy5kZWxldGUoaGFzaCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKGNvbnN0IGhhc2ggb2YgdGhpcy5sb2FkaW5nQ2h1bmtzKSB7XG4gICAgICAgICAgICBjb25zdCBbeCwgel0gPSBDaHVuay51bnBhY2tYWihoYXNoKTtcblxuICAgICAgICAgICAgaWYgKE1hdGguYWJzKHghIC0gY3VycmVudFhDaHVuaykgPiB2aWV3RGlzdGFuY2UgfHwgTWF0aC5hYnMoeiEgLSBjdXJyZW50WkNodW5rKSA+IHZpZXdEaXN0YW5jZSkge1xuICAgICAgICAgICAgICAgIHRoaXMubG9hZGluZ0NodW5rcy5kZWxldGUoaGFzaCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIXVubG9hZGVkICYmIHRoaXMuY2h1bmtTZW5kUXVldWUubGVuZ3RoICE9PSAwKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnNlbmROZXR3b3JrQ2h1bmtQdWJsaXNoZXIoZGlzdCA/PyB2aWV3RGlzdGFuY2UsIFtdKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyByZXF1ZXN0Q2h1bmsoeDogbnVtYmVyLCB6OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgY2h1bmsgPSBhd2FpdCB0aGlzLnBsYXllci5nZXRXb3JsZCgpLmdldENodW5rKHgsIHopO1xuICAgICAgICB0aGlzLmNodW5rU2VuZFF1ZXVlLnB1c2goY2h1bmspO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENsZWFyIHRoZSBjdXJyZW50bHkgbG9hZGVkIGFuZCBsb2FkaW5nIGNodW5rcy5cbiAgICAgKlxuICAgICAqIEByZW1hcmtzXG4gICAgICogVXN1YWxseSB1c2VkIGZvciBjaGFuZ2luZyBkaW1lbnNpb24sIHdvcmxkLCBldGMuXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIGNsZWFyQ2h1bmtzKCkge1xuICAgICAgICB0aGlzLmxvYWRlZENodW5rcy5jbGVhcigpO1xuICAgICAgICB0aGlzLmxvYWRpbmdDaHVua3MuY2xlYXIoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAVE9ETzogSW1wbGVtZW50IHRoaXMuXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIHNlbmRJbnZlbnRvcnkoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IHBrID0gbmV3IEludmVudG9yeUNvbnRlbnRQYWNrZXQoKTtcbiAgICAgICAgcGsuaXRlbXMgPSB0aGlzLnBsYXllci5nZXRJbnZlbnRvcnkoKS5nZXRJdGVtcyh0cnVlKTtcbiAgICAgICAgcGsud2luZG93SWQgPSBXaW5kb3dJZHMuSU5WRU5UT1JZOyAvLyBJbnZlbnRvcnkgd2luZG93XG4gICAgICAgIC8vYXdhaXQgdGhpcy5jb25uZWN0aW9uLnNlbmREYXRhUGFja2V0KHBrKTtcbiAgICAgICAgLy9hd2FpdCB0aGlzLnNlbmRIYW5kSXRlbSh0aGlzLnBsYXllci5nZXRJbnZlbnRvcnkoKS5nZXRJdGVtSW5IYW5kKCkpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBzZW5kQ3JlYXRpdmVDb250ZW50cyhlbXB0eSA9IGZhbHNlKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IHBrID0gbmV3IENyZWF0aXZlQ29udGVudFBhY2tldCgpO1xuICAgICAgICBpZiAoZW1wdHkpIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuY29ubmVjdGlvbi5zZW5kRGF0YVBhY2tldChwayk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBlbnRyaWVzID0gW1xuICAgICAgICAgICAgLi4udGhpcy5wbGF5ZXIuZ2V0U2VydmVyKCkuZ2V0QmxvY2tNYW5hZ2VyKCkuZ2V0QmxvY2tzKCksXG4gICAgICAgICAgICAuLi50aGlzLnBsYXllci5nZXRTZXJ2ZXIoKS5nZXRJdGVtTWFuYWdlcigpLmdldEl0ZW1zKClcbiAgICAgICAgXTtcblxuICAgICAgICAvLyBTb3J0IGJhc2VkIG9uIFBtbVAgQmVkcm9jay1kYXRhXG4gICAgICAgIENyZWF0aXZlSXRlbXMuZm9yRWFjaCgoaXRlbTogYW55KSA9PiB7XG4gICAgICAgICAgICBway5pdGVtcy5wdXNoKFxuICAgICAgICAgICAgICAgIC4uLmVudHJpZXNcbiAgICAgICAgICAgICAgICAgICAgLmZpbHRlcigoZW50cnk6IGFueSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGVudHJ5Lm1ldGEgPT09IChpdGVtLmRhbWFnZSA/PyAwKSAmJiBlbnRyeS5nZXRJZCgpID09PSBpdGVtLmlkO1xuICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICAubWFwKFxuICAgICAgICAgICAgICAgICAgICAgICAgKGVudHJ5KSA9PlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ldyBJdGVtKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWQ6IGVudHJ5LmdldElkKCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWU6IGVudHJ5LmdldE5hbWUoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0YTogZW50cnkubWV0YVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGF3YWl0IHRoaXMuY29ubmVjdGlvbi5zZW5kRGF0YVBhY2tldChwayk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgaXRlbSBpbiB0aGUgcGxheWVyIGhhbmQuXG4gICAgICogQHBhcmFtIHtJdGVtfSBpdGVtIC0gVGhlIGVudGl0eS5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgc2VuZEhhbmRJdGVtKGl0ZW06IEl0ZW0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgcGsgPSBuZXcgTW9iRXF1aXBtZW50UGFja2V0KCk7XG4gICAgICAgIHBrLnJ1bnRpbWVFbnRpdHlJZCA9IHRoaXMucGxheWVyLmdldFJ1bnRpbWVJZCgpO1xuICAgICAgICBway5pdGVtID0gaXRlbTtcbiAgICAgICAgcGsuaW52ZW50b3J5U2xvdCA9IHRoaXMucGxheWVyLmdldEludmVudG9yeSgpLmdldEhhbmRTbG90SW5kZXgoKTtcbiAgICAgICAgcGsuaG90YmFyU2xvdCA9IHRoaXMucGxheWVyLmdldEludmVudG9yeSgpLmdldEhhbmRTbG90SW5kZXgoKTtcbiAgICAgICAgcGsud2luZG93SWQgPSAwOyAvLyBJbnZlbnRvcnkgSURcbiAgICAgICAgYXdhaXQgdGhpcy5jb25uZWN0aW9uLnNlbmREYXRhUGFja2V0KHBrKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZW5kIHRoZSBjdXJyZW50IHRpY2sgdG8gYSBjbGllbnQuXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHRpY2sgLSBUaGUgdGlja1xuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBzZW5kVGltZSh0aWNrOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgcGsgPSBuZXcgU2V0VGltZVBhY2tldCgpO1xuICAgICAgICBway50aW1lID0gdGljaztcbiAgICAgICAgYXdhaXQgdGhpcy5jb25uZWN0aW9uLnNlbmREYXRhUGFja2V0KHBrKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZW5kIGdhbWVtb2RlIHRvIGEgY2xpZW50LlxuICAgICAqIEBwYXJhbSB7R2FtZXR5cGV9IGdhbWVtb2RlIC0gdGhlIG51bWVyaWMgZ2FtZW1vZGUgSUQuXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIHNlbmRHYW1lbW9kZShnYW1lbW9kZT86IEdhbWV0eXBlKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IHBhY2tldCA9IG5ldyBTZXRQbGF5ZXJHYW1ldHlwZVBhY2tldCgpO1xuICAgICAgICBwYWNrZXQuZ2FtZXR5cGUgPSBnYW1lbW9kZSA/PyB0aGlzLnBsYXllci5nYW1lbW9kZTtcbiAgICAgICAgYXdhaXQgdGhpcy5jb25uZWN0aW9uLnNlbmREYXRhUGFja2V0KHBhY2tldCk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHNlbmROZXR3b3JrQ2h1bmtQdWJsaXNoZXIoZGlzdGFuY2U6IG51bWJlciwgc2F2ZWRDaHVua3M6IENodW5rQ29vcmRbXSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBwayA9IG5ldyBOZXR3b3JrQ2h1bmtQdWJsaXNoZXJVcGRhdGVQYWNrZXQoKTtcbiAgICAgICAgcGsucG9zaXRpb24gPSBCbG9ja1Bvc2l0aW9uLmZyb21WZWN0b3IzKHRoaXMucGxheWVyLmdldFBvc2l0aW9uKCkpO1xuICAgICAgICBway5yYWRpdXMgPSBkaXN0YW5jZSA8PCA0O1xuICAgICAgICBway5zYXZlZENodW5rcyA9IHNhdmVkQ2h1bmtzO1xuICAgICAgICBhd2FpdCB0aGlzLmNvbm5lY3Rpb24uc2VuZERhdGFQYWNrZXQocGspO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBzZW5kQXZhaWxhYmxlQ29tbWFuZHMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IHBsYXllckVudW0gPSBuZXcgQ29tbWFuZEVudW0oKTtcbiAgICAgICAgcGxheWVyRW51bS5zb2Z0ID0gdHJ1ZTtcbiAgICAgICAgcGxheWVyRW51bS5uYW1lID0gJ1BsYXllcic7XG4gICAgICAgIHBsYXllckVudW0udmFsdWVzID0gdGhpcy5wbGF5ZXJcbiAgICAgICAgICAgIC5nZXRTZXJ2ZXIoKVxuICAgICAgICAgICAgLmdldFNlc3Npb25NYW5hZ2VyKClcbiAgICAgICAgICAgIC5nZXRBbGxQbGF5ZXJzKClcbiAgICAgICAgICAgIC5tYXAoKHBsYXllcikgPT4gcGxheWVyLmdldE5hbWUoKSk7XG5cbiAgICAgICAgY29uc3QgcGsgPSBuZXcgQXZhaWxhYmxlQ29tbWFuZHNQYWNrZXQoKTtcbiAgICAgICAgcGsuc29mdEVudW1zID0gW3BsYXllckVudW1dO1xuICAgICAgICB0aGlzLnNlcnZlclxuICAgICAgICAgICAgLmdldENvbW1hbmRNYW5hZ2VyKClcbiAgICAgICAgICAgIC5nZXRDb21tYW5kc0xpc3QoKVxuICAgICAgICAgICAgLmZvckVhY2goKGNvbW1hbmQpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBjb21tYW5kQ2xhc3MgPSBBcnJheS5mcm9tKHRoaXMuc2VydmVyLmdldENvbW1hbmRNYW5hZ2VyKCkuZ2V0Q29tbWFuZHMoKS52YWx1ZXMoKSkuZmluZChcbiAgICAgICAgICAgICAgICAgICAgKGNtZCkgPT4gY21kLm5hbWUgPT09IGNvbW1hbmRbMF1cbiAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgICAgaWYgKCFjb21tYW5kQ2xhc3MpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wbGF5ZXJcbiAgICAgICAgICAgICAgICAgICAgICAgIC5nZXRTZXJ2ZXIoKVxuICAgICAgICAgICAgICAgICAgICAgICAgLmdldExvZ2dlcigpXG4gICAgICAgICAgICAgICAgICAgICAgICAud2FybihgQ2FuJ3QgZmluZCBjb3JyZXNwb25kaW5nIGNvbW1hbmQgY2xhc3MgZm9yIFwiJHtjb21tYW5kWzBdfVwiYCk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoIXRoaXMucGxheWVyLmdldFNlcnZlcigpLmdldFBlcm1pc3Npb25NYW5hZ2VyKCkuY2FuKHRoaXMucGxheWVyKS5leGVjdXRlKGNvbW1hbmRDbGFzcy5wZXJtaXNzaW9uKSlcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgICAgICAgICAgY29uc3QgY21kID0gbmV3IENvbW1hbmREYXRhKCk7XG4gICAgICAgICAgICAgICAgY21kLmNvbW1hbmROYW1lID0gY29tbWFuZFswXTtcbiAgICAgICAgICAgICAgICBjbWQuY29tbWFuZERlc2NyaXB0aW9uID0gY29tbWFuZENsYXNzLmRlc2NyaXB0aW9uO1xuICAgICAgICAgICAgICAgIGlmIChjb21tYW5kQ2xhc3MuYWxpYXNlcyEubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBjbWRBbGlhc2VzID0gbmV3IENvbW1hbmRFbnVtKCk7XG4gICAgICAgICAgICAgICAgICAgIGNtZEFsaWFzZXMubmFtZSA9IGAke2NvbW1hbmRbMF19QWxpYXNlc2A7XG4gICAgICAgICAgICAgICAgICAgIGNtZEFsaWFzZXMudmFsdWVzID0gY29tbWFuZENsYXNzLmFsaWFzZXMhLmNvbmNhdChjb21tYW5kWzBdKTtcbiAgICAgICAgICAgICAgICAgICAgY21kLmFsaWFzZXMgPSBjbWRBbGlhc2VzO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGNvbW1hbmRbMl0uZm9yRWFjaCgoYXJnLCBpbmRleCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBwYXJhbWV0ZXJzID0gYXJnXG4gICAgICAgICAgICAgICAgICAgICAgICAubWFwKChwYXJhbWV0ZXI6IENvbW1hbmRBcmd1bWVudCB8IG51bGwpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXBhcmFtZXRlciB8fCAhKHBhcmFtZXRlciBhcyBhbnkpPy5nZXRQYXJhbWV0ZXJzKSByZXR1cm4gW107XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwYXJhbWV0ZXJzID0gcGFyYW1ldGVyLmdldFBhcmFtZXRlcnModGhpcy5zZXJ2ZXIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChwYXJhbWV0ZXJzKSByZXR1cm4gQXJyYXkuZnJvbShwYXJhbWV0ZXJzLnZhbHVlcygpKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChwYXJhbWV0ZXIgaW5zdGFuY2VvZiBDb21tYW5kQXJndW1lbnRFbnRpdHkpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXcgQ29tbWFuZFBhcmFtZXRlcih7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1OYW1lOiAndGFyZ2V0JyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbVR5cGU6IENvbW1hbmRQYXJhbWV0ZXJUeXBlLlRhcmdldFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocGFyYW1ldGVyIGluc3RhbmNlb2YgQ29tbWFuZEFyZ3VtZW50R2FtZW1vZGUpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXcgQ29tbWFuZFBhcmFtZXRlcih7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1OYW1lOiAnZ2FtZW1vZGUnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtVHlwZTogQ29tbWFuZFBhcmFtZXRlclR5cGUuU3RyaW5nXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChwYXJhbWV0ZXIuY29uc3RydWN0b3IubmFtZSA9PT0gJ1N0cmluZ0FyZ3VtZW50VHlwZScpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXcgQ29tbWFuZFBhcmFtZXRlcih7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1OYW1lOiAndmFsdWUnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtVHlwZTogQ29tbWFuZFBhcmFtZXRlclR5cGUuU3RyaW5nXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChwYXJhbWV0ZXIuY29uc3RydWN0b3IubmFtZSA9PT0gJ0ludGVnZXJBcmd1bWVudFR5cGUnKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3IENvbW1hbmRQYXJhbWV0ZXIoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtTmFtZTogJ251bWJlcicsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1UeXBlOiBDb21tYW5kUGFyYW1ldGVyVHlwZS5JbnRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIF07XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnNlcnZlci5nZXRMb2dnZXIoKS53YXJuKGBJbnZhbGlkIHBhcmFtZXRlciAke3BhcmFtZXRlci5