UNPKG

@jsprismarine/prismarine

Version:

Dedicated Minecraft Bedrock Edition server written in TypeScript

416 lines (414 loc) 51.3 kB
import { Vector3 } from '@jsprismarine/math'; import { Gametype, getGametypeId } from '@jsprismarine/minecraft'; import { Chat, ChatType } from './chat/Chat.es.js'; import Human from './entity/Human.es.js'; import ChatEvent from './events/chat/ChatEvent.es.js'; import PlayerSetGamemodeEvent from './events/player/PlayerSetGamemodeEvent.es.js'; import PlayerToggleFlightEvent from './events/player/PlayerToggleFlightEvent.es.js'; import PlayerToggleSprintEvent from './events/player/PlayerToggleSprintEvent.es.js'; import './network/packet/ActorFallPacket.es.js'; import './network/packet/AddActorPacket.es.js'; import './network/packet/AddItemActorPacket.es.js'; import './network/packet/AddPlayerPacket.es.js'; import './network/packet/AnimatePacket.es.js'; import './network/packet/AvailableActorIdentifiersPacket.es.js'; import './network/packet/AvailableCommandsPacket.es.js'; import '@jsprismarine/jsbinaryutils'; import 'zlib'; import './network/CompressionProvider.es.js'; import './network/packet/NetworkSettingsPacket.es.js'; import './network/packet/BiomeDefinitionListPacket.es.js'; import ChangeDimensionPacket from './network/packet/ChangeDimensionPacket.es.js'; import './network/packet/ChunkRadiusUpdatedPacket.es.js'; import './network/packet/CommandRequestPacket.es.js'; import './network/packet/ContainerClosePacket.es.js'; import './network/packet/ContainerOpenPacket.es.js'; import './network/packet/CreativeContentPacket.es.js'; import './network/packet/DisconnectPacket.es.js'; import './network/packet/EmoteListPacket.es.js'; import './network/packet/InteractPacket.es.js'; import './network/packet/InventoryContentPacket.es.js'; import './network/packet/InventoryTransactionPacket.es.js'; import './network/packet/ItemComponentPacket.es.js'; import './network/packet/ItemStackRequestPacket.es.js'; import './network/packet/ItemStackResponsePacket.es.js'; import './network/packet/LevelChunkPacket.es.js'; import './network/packet/LevelSoundEventPacket.es.js'; import './network/packet/LoginPacket.es.js'; import './network/packet/MobEquipmentPacket.es.js'; import './network/packet/MoveActorAbsolutePacket.es.js'; import './network/packet/MovePlayerPacket.es.js'; import './network/packet/NetworkChunkPublisherUpdatePacket.es.js'; import './network/packet/OnScreenTextureAnimationPacket.es.js'; import './network/packet/PacketViolationWarningPacket.es.js'; import './network/packet/PlaySoundPacket.es.js'; import './network/packet/PlayStatusPacket.es.js'; import './network/packet/PlayerActionPacket.es.js'; import './network/packet/PlayerListPacket.es.js'; import './network/packet/PlayerSkinPacket.es.js'; import './network/packet/RemoveActorPacket.es.js'; import './network/packet/RequestChunkRadiusPacket.es.js'; import './network/packet/RequestNetworkSettingsPacket.es.js'; import './network/packet/ResourcePackResponsePacket.es.js'; import './network/packet/ResourcePackStackPacket.es.js'; import './network/packet/ResourcePacksInfoPacket.es.js'; import './network/packet/ServerSettingsRequestPacket.es.js'; import './network/packet/SetActorDataPacket.es.js'; import './network/packet/SetDefaultGametypePacket.es.js'; import './network/packet/SetHealthPacket.es.js'; import './network/packet/SetLocalPlayerAsInitializedPacket.es.js'; import './network/packet/SetPlayerGametypePacket.es.js'; import './network/packet/SetTimePacket.es.js'; import './network/packet/ShowProfilePacket.es.js'; import './network/packet/StartGamePacket.es.js'; import './network/packet/TextPacket.es.js'; import './network/packet/TickSyncPacket.es.js'; import './network/packet/TransferPacket.es.js'; import './network/packet/UpdateAdventureSettingsPacket.es.js'; import './network/packet/UpdateAttributesPacket.es.js'; import './network/packet/UpdateBlockPacket.es.js'; import './network/packet/WorldEventPacket.es.js'; import PlayerSession from './network/PlayerSession.es.js'; import MovementType from './network/type/MovementType.es.js'; import PlayStatusType from './network/type/PlayStatusType.es.js'; import TextType from './network/type/TextType.es.js'; import Timer from './utils/Timer.es.js'; import CoordinateUtils from './world/CoordinateUtils.es.js'; const VANILLA_DEFAULT_SPAWN_RADIUS = 4; class Player extends Human { address; networkSession; permissions; /** * Timer used for various metrics. */ timer; connected = false; xuid = ""; randomId = 0; locale = ""; skin = null; viewDistance = 0; gamemode = Gametype.WORLD_DEFAULT; onGround = false; flying = false; sneaking = false; platformChatId = ""; // TODO: read this value from Login device = null; chunkSendQueue = /* @__PURE__ */ new Set(); /** * Player's constructor. */ constructor({ connection, world, server, uuid }) { super({ world, server, uuid }); this.timer = new Timer(); this.address = connection.getRakNetSession().getAddress(); this.networkSession = new PlayerSession(server, connection, this); this.permissions = []; this.server.on("chat", this.chatHandler.bind(this)); } /** * On enable hook. * @group Lifecycle */ async enable() { const playerData = await this.getWorld().getPlayerData(this); this.permissions = await this.server.getPermissionManager().getPermissions(this); this.gamemode = getGametypeId(playerData.gamemode || this.server.getConfig().getGamemode()); this.setPosition({ position: playerData.position ? Vector3.fromObject(playerData.position) : await this.getWorld().getSpawnPosition(), pitch: playerData.position?.pitch || 0, yaw: playerData.position?.yaw || 0, headYaw: playerData.position?.headYaw || 0, type: MovementType.Reset }); await this.sendPosition(); await this.sendSettings(); await Promise.all( this.getWorld().getPlayers().map((target) => this.getNetworkSession().broadcastMove(target, MovementType.Reset)) ); this.server.getLogger().debug(`(Complete player creation took ${this.timer.stop()} ms)`); this.connected = true; } /** * On disable hook. * @group Lifecycle */ async disable() { if (this.connected && this.xuid) await this.getWorld().savePlayerData(this); await this.getWorld().removeEntity(this); await this.getNetworkSession().removeFromPlayerList(); for (const onlinePlayer of this.server.getSessionManager().getAllPlayers()) { await this.getNetworkSession().sendDespawn(onlinePlayer); } const event = new ChatEvent( new Chat({ sender: this.server.getConsole(), message: `§e%multiplayer.player.left`, parameters: [this.getName()], needsTranslation: true, type: ChatType.TRANSLATION }) ); await this.server.emit("chat", event); this.connected = false; this.server.removeListener("chat", this.chatHandler); } async chatHandler(evt) { if (evt.isCancelled()) return; if (evt.getChat().getChannel() === "*.everyone" || evt.getChat().getChannel() === "*.ops" && this.isOp() || evt.getChat().getChannel() === `*.player.${this.getName()}`) await this.sendMessage( evt.getChat().getMessage(), evt.getChat().getType(), evt.getChat().getParameters(), evt.getChat().isNeedsTranslation() ); } /** * Used to match vanilla behavior, will send chunks * with an initial view radius of VANILLA_DEFAULT_SPAWN_RADIUS. */ async sendInitialSpawnChunks() { const minX = CoordinateUtils.fromBlockToChunk(this.x) - VANILLA_DEFAULT_SPAWN_RADIUS; const minZ = CoordinateUtils.fromBlockToChunk(this.z) - VANILLA_DEFAULT_SPAWN_RADIUS; const maxX = CoordinateUtils.fromBlockToChunk(this.x) + VANILLA_DEFAULT_SPAWN_RADIUS; const maxZ = CoordinateUtils.fromBlockToChunk(this.z) + VANILLA_DEFAULT_SPAWN_RADIUS; const savedChunks = []; const sendQueue = []; for (let chunkX = minX; chunkX <= maxX; ++chunkX) { for (let chunkZ = minZ; chunkZ <= maxZ; ++chunkZ) { savedChunks.push({ x: chunkX, z: chunkZ }); sendQueue.push(this.getWorld().getChunk(chunkX, chunkZ)); } } await this.networkSession.sendNetworkChunkPublisher(VANILLA_DEFAULT_SPAWN_RADIUS, savedChunks); const getUniqueChunks = (sendList) => { const xSet = /* @__PURE__ */ new Set(); const zSet = /* @__PURE__ */ new Set(); for (const coord of sendList) { xSet.add(coord.x); zSet.add(coord.z); } return Math.floor((xSet.size + zSet.size) / 2); }; for (let i = 0; i < getUniqueChunks(savedChunks); ++i) { await this.networkSession.sendNetworkChunkPublisher(VANILLA_DEFAULT_SPAWN_RADIUS, []); } for await (const chunk of sendQueue) { await this.networkSession.sendChunk(chunk); } } /** * Change the player's current world. * @param {World} world - the new world */ async setWorld(world) { const dim0 = new ChangeDimensionPacket(); dim0.dimension = 0; dim0.position = this.getPosition(); dim0.respawn = false; const dim1 = new ChangeDimensionPacket(); dim1.dimension = 1; dim1.position = this.getPosition(); dim1.respawn = false; await this.sendDespawn(); await this.getWorld().removeEntity(this); await super.setWorld(world); await world.addEntity(this); await this.networkSession.send(dim0); await this.networkSession.sendPlayStatus(PlayStatusType.PlayerSpawn); await this.networkSession.send(dim1); await this.networkSession.sendPlayStatus(PlayStatusType.PlayerSpawn); await this.sendInitialSpawnChunks(); await this.networkSession.send(dim1); await this.networkSession.sendPlayStatus(PlayStatusType.PlayerSpawn); await this.networkSession.send(dim0); await this.networkSession.sendPlayStatus(PlayStatusType.PlayerSpawn); await this.networkSession.clearChunks(); await this.networkSession.needNewChunks(); await this.networkSession.sendPlayStatus(PlayStatusType.PlayerSpawn); } isOnline() { return this.connected; } async update(tick) { await super.update(tick); await this.networkSession.update(tick); if (tick % (20 * 5 * 60 * 1) === 0) { await this.networkSession.sendTime(tick); } for (const chunk of this.chunkSendQueue) { await this.networkSession.sendNetworkChunkPublisher(this.viewDistance || VANILLA_DEFAULT_SPAWN_RADIUS, []); await this.networkSession.sendChunk(chunk); this.chunkSendQueue.delete(chunk); } } async kick(reason = "unknown reason") { await this.disable(); await this.networkSession.kick(reason); this.server.getLogger().verbose(`Player with id §b${this.getRuntimeId()}§r was kicked: ${reason}`); } async sendSettings() { await this.getNetworkSession().sendGamemode(); await Promise.all( this.server.getSessionManager().getAllPlayers().map(async (target) => { await target.getNetworkSession().sendAbilities(this); await target.getNetworkSession().sendSettings(this); }) ); } /** * Player spawning logic. */ async sendSpawn() { await this.sendPosition(); await this.setGamemode(); await this.getNetworkSession().sendInventory(); await this.sendSettings(); } async sendDespawn() { } /** * Send a chat message to the client. * @param message - the message */ async sendMessage(message, type = TextType.Raw, parameters = [], needsTranslation = false) { await this.networkSession.sendMessage({ message, parameters, needsTranslation, type }); } async setGamemode(mode) { mode ??= this.gamemode; const event = new PlayerSetGamemodeEvent(this, mode); this.server.post(["playerSetGamemode", event]); if (event.isCancelled()) return; this.gamemode = event.getGamemode(); await this.networkSession.sendGamemode(); if (this.gamemode === Gametype.CREATIVE || this.gamemode === Gametype.SPECTATOR) { this.metadata.setCanFly(true); } else { this.metadata.setCanFly(false); await this.setFlying(false); } await this.sendSettings(); await this.networkSession.sendGamemode(); await this.networkSession.sendMetadata(); } getNetworkSession() { return this.networkSession; } getAddress() { return this.address; } getName() { return this.metadata.nameTag; } getFormattedUsername() { return `<${this.getName()}>`; } getPermissions() { return this.permissions; } /** * Get the XUID of the player. * @returns {string | null} XUID of the player or null if not available */ getXUID() { return this.xuid || null; } isPlayer() { return true; } /** * Check if the `Player` is an operator. * @returns `true` if this player is an operator otherwise `false`. */ isOp() { return this.server.getPermissionManager().isOp(this.getName()); } async setSprinting(sprinting) { if (sprinting === this.metadata.sprinting) return; const event = new PlayerToggleSprintEvent(this, sprinting); this.server.post(["playerToggleSprint", event]); if (event.isCancelled()) return; this.metadata.setSprinting(event.getIsSprinting()); await this.networkSession.sendMetadata(); } isFlying() { return this.flying; } async setFlying(flying) { if (flying === this.isFlying()) return; if (!this.metadata.canFly) { this.flying = false; await this.sendSettings(); return; } const event = new PlayerToggleFlightEvent(this, flying); this.server.post(["playerToggleFlight", event]); if (event.isCancelled()) return; this.flying = event.getIsFlying(); await this.sendSettings(); } isSneaking() { return this.sneaking; } async setSneaking(val) { if (val === this.sneaking) return; this.sneaking = val; } isOnGround() { return this.onGround; } async setOnGround(val) { if (val === this.onGround) return; this.onGround = val; } /** * Set the position. * @param {object} options - The options to set the position. * @param {Vector3} options.position - The new position. * @param {MovementType} [options.type=MovementType.Normal] - The movement type. * @param {number} [options.pitch=this.pitch] - The new pitch. * @param {number} [options.yaw=this.yaw] - The new yaw. * @param {number} [options.headYaw=this.headYaw] - The new head yaw. * @param {boolean} [broadcast=true] - Whether to broadcast the position change. * @remarks This will notify the player's client about the position change. */ async setPosition({ position, type = MovementType.Normal, pitch = this.pitch, yaw = this.yaw, headYaw = this.headYaw }, broadcast = true) { await super.setPosition({ position }); this.pitch = pitch; this.yaw = yaw; this.headYaw = headYaw; if (!broadcast) return; await this.networkSession.broadcastMove(this, type); } /** * Send the position to all the players in the same world. * @returns {Promise<void>} A promise that resolves when the position is sent. */ async sendPosition() { await super.sendPosition(); } } export { VANILLA_DEFAULT_SPAWN_RADIUS, Player as default }; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGxheWVyLmVzLmpzIiwic291cmNlcyI6WyIuLi9zcmMvUGxheWVyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICdAanNwcmlzbWFyaW5lL21hdGgnO1xuaW1wb3J0IHsgR2FtZXR5cGUsIGdldEdhbWV0eXBlSWQgfSBmcm9tICdAanNwcmlzbWFyaW5lL21pbmVjcmFmdCc7XG5pbXBvcnQgdHlwZSB7IEluZXRBZGRyZXNzIH0gZnJvbSAnQGpzcHJpc21hcmluZS9yYWtuZXQnO1xuaW1wb3J0IHR5cGUgU2VydmVyIGZyb20gJy4vU2VydmVyJztcbmltcG9ydCB7IENoYXQsIENoYXRUeXBlIH0gZnJvbSAnLi9jaGF0L0NoYXQnO1xuaW1wb3J0IEh1bWFuIGZyb20gJy4vZW50aXR5L0h1bWFuJztcbmltcG9ydCBDaGF0RXZlbnQgZnJvbSAnLi9ldmVudHMvY2hhdC9DaGF0RXZlbnQnO1xuaW1wb3J0IFBsYXllclNldEdhbWVtb2RlRXZlbnQgZnJvbSAnLi9ldmVudHMvcGxheWVyL1BsYXllclNldEdhbWVtb2RlRXZlbnQnO1xuaW1wb3J0IFBsYXllclRvZ2dsZUZsaWdodEV2ZW50IGZyb20gJy4vZXZlbnRzL3BsYXllci9QbGF5ZXJUb2dnbGVGbGlnaHRFdmVudCc7XG5pbXBvcnQgUGxheWVyVG9nZ2xlU3ByaW50RXZlbnQgZnJvbSAnLi9ldmVudHMvcGxheWVyL1BsYXllclRvZ2dsZVNwcmludEV2ZW50JztcbmltcG9ydCB0eXBlIENsaWVudENvbm5lY3Rpb24gZnJvbSAnLi9uZXR3b3JrL0NsaWVudENvbm5lY3Rpb24nO1xuaW1wb3J0IHsgQ2hhbmdlRGltZW5zaW9uUGFja2V0IH0gZnJvbSAnLi9uZXR3b3JrL1BhY2tldHMnO1xuaW1wb3J0IFBsYXllclNlc3Npb24gZnJvbSAnLi9uZXR3b3JrL1BsYXllclNlc3Npb24nO1xuaW1wb3J0IHR5cGUgeyBDaHVua0Nvb3JkIH0gZnJvbSAnLi9uZXR3b3JrL3BhY2tldC9OZXR3b3JrQ2h1bmtQdWJsaXNoZXJVcGRhdGVQYWNrZXQnO1xuaW1wb3J0IE1vdmVtZW50VHlwZSBmcm9tICcuL25ldHdvcmsvdHlwZS9Nb3ZlbWVudFR5cGUnO1xuaW1wb3J0IFBsYXlTdGF0dXNUeXBlIGZyb20gJy4vbmV0d29yay90eXBlL1BsYXlTdGF0dXNUeXBlJztcbmltcG9ydCBUZXh0VHlwZSBmcm9tICcuL25ldHdvcmsvdHlwZS9UZXh0VHlwZSc7XG5pbXBvcnQgdHlwZSBEZXZpY2UgZnJvbSAnLi91dGlscy9EZXZpY2UnO1xuaW1wb3J0IFRpbWVyIGZyb20gJy4vdXRpbHMvVGltZXInO1xuaW1wb3J0IHR5cGUgU2tpbiBmcm9tICcuL3V0aWxzL3NraW4vU2tpbic7XG5pbXBvcnQgdHlwZSB7IFdvcmxkIH0gZnJvbSAnLi93b3JsZC8nO1xuaW1wb3J0IENvb3JkaW5hdGVVdGlscyBmcm9tICcuL3dvcmxkL0Nvb3JkaW5hdGVVdGlscyc7XG5pbXBvcnQgdHlwZSBDaHVuayBmcm9tICcuL3dvcmxkL2NodW5rL0NodW5rJztcblxuLyoqXG4gKiBEZWZhdWx0IHNwYXduIHZpZXcgZGlzdGFuY2UgdXNlZCBpbiB2YW5pbGxhXG4gKi9cbmV4cG9ydCBjb25zdCBWQU5JTExBX0RFRkFVTFRfU1BBV05fUkFESVVTID0gNDtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgUGxheWVyIGV4dGVuZHMgSHVtYW4ge1xuICAgIHByaXZhdGUgcmVhZG9ubHkgYWRkcmVzczogSW5ldEFkZHJlc3M7XG4gICAgcHJpdmF0ZSByZWFkb25seSBuZXR3b3JrU2Vzc2lvbjogUGxheWVyU2Vzc2lvbjtcbiAgICBwcml2YXRlIHBlcm1pc3Npb25zOiBzdHJpbmdbXTtcblxuICAgIC8qKlxuICAgICAqIFRpbWVyIHVzZWQgZm9yIHZhcmlvdXMgbWV0cmljcy5cbiAgICAgKi9cbiAgICBwcml2YXRlIHRpbWVyOiBUaW1lcjtcbiAgICBwcml2YXRlIGNvbm5lY3RlZCA9IGZhbHNlO1xuXG4gICAgcHVibGljIHh1aWQgPSAnJztcbiAgICBwdWJsaWMgcmFuZG9tSWQgPSAwO1xuXG4gICAgcHVibGljIGxvY2FsZSA9ICcnO1xuICAgIHB1YmxpYyBza2luOiBTa2luIHwgbnVsbCA9IG51bGw7XG5cbiAgICBwdWJsaWMgdmlld0Rpc3RhbmNlID0gMDtcbiAgICBwdWJsaWMgZ2FtZW1vZGU6IEdhbWV0eXBlID0gR2FtZXR5cGUuV09STERfREVGQVVMVDtcblxuICAgIHByaXZhdGUgb25Hcm91bmQgPSBmYWxzZTtcbiAgICBwcml2YXRlIGZseWluZyA9IGZhbHNlO1xuICAgIHByaXZhdGUgc25lYWtpbmcgPSBmYWxzZTtcblxuICAgIHB1YmxpYyBwbGF0Zm9ybUNoYXRJZCA9ICcnOyAvLyBUT0RPOiByZWFkIHRoaXMgdmFsdWUgZnJvbSBMb2dpblxuICAgIHB1YmxpYyBkZXZpY2U6IERldmljZSB8IG51bGwgPSBudWxsO1xuXG4gICAgcHVibGljIHJlYWRvbmx5IGNodW5rU2VuZFF1ZXVlID0gbmV3IFNldDxDaHVuaz4oKTtcblxuICAgIC8qKlxuICAgICAqIFBsYXllcidzIGNvbnN0cnVjdG9yLlxuICAgICAqL1xuICAgIHB1YmxpYyBjb25zdHJ1Y3Rvcih7XG4gICAgICAgIGNvbm5lY3Rpb24sXG4gICAgICAgIHdvcmxkLFxuICAgICAgICBzZXJ2ZXIsXG4gICAgICAgIHV1aWRcbiAgICB9OiB7XG4gICAgICAgIGNvbm5lY3Rpb246IENsaWVudENvbm5lY3Rpb247XG4gICAgICAgIHdvcmxkOiBXb3JsZDtcbiAgICAgICAgc2VydmVyOiBTZXJ2ZXI7XG4gICAgICAgIHV1aWQ/OiBzdHJpbmc7XG4gICAgfSkge1xuICAgICAgICBzdXBlcih7XG4gICAgICAgICAgICB3b3JsZCxcbiAgICAgICAgICAgIHNlcnZlcixcbiAgICAgICAgICAgIHV1aWRcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy50aW1lciA9IG5ldyBUaW1lcigpO1xuXG4gICAgICAgIHRoaXMuYWRkcmVzcyA9IGNvbm5lY3Rpb24uZ2V0UmFrTmV0U2Vzc2lvbigpLmdldEFkZHJlc3MoKTtcbiAgICAgICAgdGhpcy5uZXR3b3JrU2Vzc2lvbiA9IG5ldyBQbGF5ZXJTZXNzaW9uKHNlcnZlciwgY29ubmVjdGlvbiwgdGhpcyk7XG4gICAgICAgIHRoaXMucGVybWlzc2lvbnMgPSBbXTtcblxuICAgICAgICB0aGlzLnNlcnZlci5vbignY2hhdCcsIHRoaXMuY2hhdEhhbmRsZXIuYmluZCh0aGlzKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogT24gZW5hYmxlIGhvb2suXG4gICAgICogQGdyb3VwIExpZmVjeWNsZVxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBlbmFibGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IHBsYXllckRhdGEgPSBhd2FpdCB0aGlzLmdldFdvcmxkKCkuZ2V0UGxheWVyRGF0YSh0aGlzKTtcblxuICAgICAgICB0aGlzLnBlcm1pc3Npb25zID0gYXdhaXQgdGhpcy5zZXJ2ZXIuZ2V0UGVybWlzc2lvbk1hbmFnZXIoKS5nZXRQZXJtaXNzaW9ucyh0aGlzKTtcbiAgICAgICAgdGhpcy5nYW1lbW9kZSA9IGdldEdhbWV0eXBlSWQocGxheWVyRGF0YS5nYW1lbW9kZSB8fCB0aGlzLnNlcnZlci5nZXRDb25maWcoKS5nZXRHYW1lbW9kZSgpKTtcblxuICAgICAgICB0aGlzLnNldFBvc2l0aW9uKHtcbiAgICAgICAgICAgIHBvc2l0aW9uOiBwbGF5ZXJEYXRhLnBvc2l0aW9uXG4gICAgICAgICAgICAgICAgPyBWZWN0b3IzLmZyb21PYmplY3QocGxheWVyRGF0YS5wb3NpdGlvbilcbiAgICAgICAgICAgICAgICA6IGF3YWl0IHRoaXMuZ2V0V29ybGQoKS5nZXRTcGF3blBvc2l0aW9uKCksXG4gICAgICAgICAgICBwaXRjaDogcGxheWVyRGF0YS5wb3NpdGlvbj8ucGl0Y2ggfHwgMCxcbiAgICAgICAgICAgIHlhdzogcGxheWVyRGF0YS5wb3NpdGlvbj8ueWF3IHx8IDAsXG4gICAgICAgICAgICBoZWFkWWF3OiBwbGF5ZXJEYXRhLnBvc2l0aW9uPy5oZWFkWWF3IHx8IDAsXG4gICAgICAgICAgICB0eXBlOiBNb3ZlbWVudFR5cGUuUmVzZXRcbiAgICAgICAgfSk7XG4gICAgICAgIGF3YWl0IHRoaXMuc2VuZFBvc2l0aW9uKCk7XG5cbiAgICAgICAgYXdhaXQgdGhpcy5zZW5kU2V0dGluZ3MoKTtcblxuICAgICAgICAvLyBVcGRhdGUgcG9zaXRpb24gb2YgYWxsIHRoZSBwbGF5ZXJzIGluIHRoZSBzYW1lIHdvcmxkLlxuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgICAgIHRoaXMuZ2V0V29ybGQoKVxuICAgICAgICAgICAgICAgIC5nZXRQbGF5ZXJzKClcbiAgICAgICAgICAgICAgICAubWFwKCh0YXJnZXQpID0+IHRoaXMuZ2V0TmV0d29ya1Nlc3Npb24oKS5icm9hZGNhc3RNb3ZlKHRhcmdldCwgTW92ZW1lbnRUeXBlLlJlc2V0KSlcbiAgICAgICAgKTtcblxuICAgICAgICAvLyBGaW5hbGx5IG1hcmsgdGhlIHBsYXllciBhcyBjb25uZWN0ZWQuXG4gICAgICAgIHRoaXMuc2VydmVyLmdldExvZ2dlcigpLmRlYnVnKGAoQ29tcGxldGUgcGxheWVyIGNyZWF0aW9uIHRvb2sgJHt0aGlzLnRpbWVyLnN0b3AoKX0gbXMpYCk7XG4gICAgICAgIHRoaXMuY29ubmVjdGVkID0gdHJ1ZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBPbiBkaXNhYmxlIGhvb2suXG4gICAgICogQGdyb3VwIExpZmVjeWNsZVxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBkaXNhYmxlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAodGhpcy5jb25uZWN0ZWQgJiYgdGhpcy54dWlkKSBhd2FpdCB0aGlzLmdldFdvcmxkKCkuc2F2ZVBsYXllckRhdGEodGhpcyk7XG4gICAgICAgIGF3YWl0IHRoaXMuZ2V0V29ybGQoKS5yZW1vdmVFbnRpdHkodGhpcyk7XG5cbiAgICAgICAgLy8gRGUtc3Bhd24gdGhlIHBsYXllciB0byBhbGwgb25saW5lIHBsYXllcnNcbiAgICAgICAgYXdhaXQgdGhpcy5nZXROZXR3b3JrU2Vzc2lvbigpLnJlbW92ZUZyb21QbGF5ZXJMaXN0KCk7XG4gICAgICAgIGZvciAoY29uc3Qgb25saW5lUGxheWVyIG9mIHRoaXMuc2VydmVyLmdldFNlc3Npb25NYW5hZ2VyKCkuZ2V0QWxsUGxheWVycygpKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmdldE5ldHdvcmtTZXNzaW9uKCkuc2VuZERlc3Bhd24ob25saW5lUGxheWVyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEFubm91bmNlIGRpc2Nvbm5lY3Rpb25cbiAgICAgICAgY29uc3QgZXZlbnQgPSBuZXcgQ2hhdEV2ZW50KFxuICAgICAgICAgICAgbmV3IENoYXQoe1xuICAgICAgICAgICAgICAgIHNlbmRlcjogdGhpcy5zZXJ2ZXIuZ2V0Q29uc29sZSgpISxcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgwqdlJW11bHRpcGxheWVyLnBsYXllci5sZWZ0YCxcbiAgICAgICAgICAgICAgICBwYXJhbWV0ZXJzOiBbdGhpcy5nZXROYW1lKCldLFxuICAgICAgICAgICAgICAgIG5lZWRzVHJhbnNsYXRpb246IHRydWUsXG4gICAgICAgICAgICAgICAgdHlwZTogQ2hhdFR5cGUuVFJBTlNMQVRJT05cbiAgICAgICAgICAgIH0pXG4gICAgICAgICk7XG4gICAgICAgIGF3YWl0IHRoaXMuc2VydmVyLmVtaXQoJ2NoYXQnLCBldmVudCk7XG5cbiAgICAgICAgdGhpcy5jb25uZWN0ZWQgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5zZXJ2ZXIucmVtb3ZlTGlzdGVuZXIoJ2NoYXQnLCB0aGlzLmNoYXRIYW5kbGVyKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIGNoYXRIYW5kbGVyKGV2dDogQ2hhdEV2ZW50KSB7XG4gICAgICAgIGlmIChldnQuaXNDYW5jZWxsZWQoKSkgcmV0dXJuO1xuXG4gICAgICAgIC8vIFRPRE86IHByb3BlciBjaGFubmVsIHN5c3RlbVxuICAgICAgICBpZiAoXG4gICAgICAgICAgICBldnQuZ2V0Q2hhdCgpLmdldENoYW5uZWwoKSA9PT0gJyouZXZlcnlvbmUnIHx8XG4gICAgICAgICAgICAoZXZ0LmdldENoYXQoKS5nZXRDaGFubmVsKCkgPT09ICcqLm9wcycgJiYgdGhpcy5pc09wKCkpIHx8XG4gICAgICAgICAgICBldnQuZ2V0Q2hhdCgpLmdldENoYW5uZWwoKSA9PT0gYCoucGxheWVyLiR7dGhpcy5nZXROYW1lKCl9YFxuICAgICAgICApXG4gICAgICAgICAgICBhd2FpdCB0aGlzLnNlbmRNZXNzYWdlKFxuICAgICAgICAgICAgICAgIGV2dC5nZXRDaGF0KCkuZ2V0TWVzc2FnZSgpLFxuICAgICAgICAgICAgICAgIGV2dC5nZXRDaGF0KCkuZ2V0VHlwZSgpIGFzIG51bWJlciBhcyBUZXh0VHlwZSxcbiAgICAgICAgICAgICAgICBldnQuZ2V0Q2hhdCgpLmdldFBhcmFtZXRlcnMoKSxcbiAgICAgICAgICAgICAgICBldnQuZ2V0Q2hhdCgpLmlzTmVlZHNUcmFuc2xhdGlvbigpXG4gICAgICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFVzZWQgdG8gbWF0Y2ggdmFuaWxsYSBiZWhhdmlvciwgd2lsbCBzZW5kIGNodW5rc1xuICAgICAqIHdpdGggYW4gaW5pdGlhbCB2aWV3IHJhZGl1cyBvZiBWQU5JTExBX0RFRkFVTFRfU1BBV05fUkFESVVTLlxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBzZW5kSW5pdGlhbFNwYXduQ2h1bmtzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBtaW5YID0gQ29vcmRpbmF0ZVV0aWxzLmZyb21CbG9ja1RvQ2h1bmsodGhpcy54KSAtIFZBTklMTEFfREVGQVVMVF9TUEFXTl9SQURJVVM7XG4gICAgICAgIGNvbnN0IG1pblogPSBDb29yZGluYXRlVXRpbHMuZnJvbUJsb2NrVG9DaHVuayh0aGlzLnopIC0gVkFOSUxMQV9ERUZBVUxUX1NQQVdOX1JBRElVUztcbiAgICAgICAgY29uc3QgbWF4WCA9IENvb3JkaW5hdGVVdGlscy5mcm9tQmxvY2tUb0NodW5rKHRoaXMueCkgKyBWQU5JTExBX0RFRkFVTFRfU1BBV05fUkFESVVTO1xuICAgICAgICBjb25zdCBtYXhaID0gQ29vcmRpbmF0ZVV0aWxzLmZyb21CbG9ja1RvQ2h1bmsodGhpcy56KSArIFZBTklMTEFfREVGQVVMVF9TUEFXTl9SQURJVVM7XG5cbiAgICAgICAgY29uc3Qgc2F2ZWRDaHVua3M6IENodW5rQ29vcmRbXSA9IFtdO1xuICAgICAgICBjb25zdCBzZW5kUXVldWU6IEFycmF5PFByb21pc2U8Q2h1bms+PiA9IFtdO1xuICAgICAgICBmb3IgKGxldCBjaHVua1ggPSBtaW5YOyBjaHVua1ggPD0gbWF4WDsgKytjaHVua1gpIHtcbiAgICAgICAgICAgIGZvciAobGV0IGNodW5rWiA9IG1pblo7IGNodW5rWiA8PSBtYXhaOyArK2NodW5rWikge1xuICAgICAgICAgICAgICAgIC8vIFRPRE86IHZhbmlsbGEgZG9lcyBub3Qgc2VuZCBhbGwgb2YgdGhlbSwgYnV0IGluIGEgcmFuZ2VcbiAgICAgICAgICAgICAgICAvLyBmb3IgZXhhbXBsZSBpdCBkb2VzIHNlbmQgdGhlbSBmcm9tIHggPT4gWy0zOyAzXSBhbmQgeiA9PiBbLTM7IDJdXG4gICAgICAgICAgICAgICAgc2F2ZWRDaHVua3MucHVzaCh7IHg6IGNodW5rWCwgejogY2h1bmtaIH0pO1xuICAgICAgICAgICAgICAgIHNlbmRRdWV1ZS5wdXNoKHRoaXMuZ2V0V29ybGQoKS5nZXRDaHVuayhjaHVua1gsIGNodW5rWikpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgYXdhaXQgdGhpcy5uZXR3b3JrU2Vzc2lvbi5zZW5kTmV0d29ya0NodW5rUHVibGlzaGVyKFZBTklMTEFfREVGQVVMVF9TUEFXTl9SQURJVVMsIHNhdmVkQ2h1bmtzKTtcblxuICAgICAgICBjb25zdCBnZXRVbmlxdWVDaHVua3MgPSAoc2VuZExpc3Q6IENodW5rQ29vcmRbXSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgeFNldCA9IG5ldyBTZXQ8bnVtYmVyPigpO1xuICAgICAgICAgICAgY29uc3QgelNldCA9IG5ldyBTZXQ8bnVtYmVyPigpO1xuXG4gICAgICAgICAgICBmb3IgKGNvbnN0IGNvb3JkIG9mIHNlbmRMaXN0KSB7XG4gICAgICAgICAgICAgICAgeFNldC5hZGQoY29vcmQueCk7XG4gICAgICAgICAgICAgICAgelNldC5hZGQoY29vcmQueik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBNYXRoLmZsb29yKCh4U2V0LnNpemUgKyB6U2V0LnNpemUpIC8gMik7XG4gICAgICAgIH07XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBnZXRVbmlxdWVDaHVua3Moc2F2ZWRDaHVua3MpOyArK2kpIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uc2VuZE5ldHdvcmtDaHVua1B1Ymxpc2hlcihWQU5JTExBX0RFRkFVTFRfU1BBV05fUkFESVVTLCBbXSk7XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgYXdhaXQgKGNvbnN0IGNodW5rIG9mIHNlbmRRdWV1ZSkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5uZXR3b3JrU2Vzc2lvbi5zZW5kQ2h1bmsoY2h1bmspO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hhbmdlIHRoZSBwbGF5ZXIncyBjdXJyZW50IHdvcmxkLlxuICAgICAqIEBwYXJhbSB7V29ybGR9IHdvcmxkIC0gdGhlIG5ldyB3b3JsZFxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBzZXRXb3JsZCh3b3JsZDogV29ybGQpIHtcbiAgICAgICAgY29uc3QgZGltMCA9IG5ldyBDaGFuZ2VEaW1lbnNpb25QYWNrZXQoKTtcbiAgICAgICAgZGltMC5kaW1lbnNpb24gPSAwO1xuICAgICAgICBkaW0wLnBvc2l0aW9uID0gdGhpcy5nZXRQb3NpdGlvbigpO1xuICAgICAgICBkaW0wLnJlc3Bhd24gPSBmYWxzZTtcblxuICAgICAgICBjb25zdCBkaW0xID0gbmV3IENoYW5nZURpbWVuc2lvblBhY2tldCgpO1xuICAgICAgICBkaW0xLmRpbWVuc2lvbiA9IDE7XG4gICAgICAgIGRpbTEucG9zaXRpb24gPSB0aGlzLmdldFBvc2l0aW9uKCk7XG4gICAgICAgIGRpbTEucmVzcGF3biA9IGZhbHNlO1xuXG4gICAgICAgIGF3YWl0IHRoaXMuc2VuZERlc3Bhd24oKTtcbiAgICAgICAgYXdhaXQgdGhpcy5nZXRXb3JsZCgpLnJlbW92ZUVudGl0eSh0aGlzKTtcblxuICAgICAgICBhd2FpdCBzdXBlci5zZXRXb3JsZCh3b3JsZCk7XG4gICAgICAgIGF3YWl0IHdvcmxkLmFkZEVudGl0eSh0aGlzKTtcblxuICAgICAgICBhd2FpdCB0aGlzLm5ldHdvcmtTZXNzaW9uLnNlbmQoZGltMCk7XG4gICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uc2VuZFBsYXlTdGF0dXMoUGxheVN0YXR1c1R5cGUuUGxheWVyU3Bhd24pO1xuICAgICAgICBhd2FpdCB0aGlzLm5ldHdvcmtTZXNzaW9uLnNlbmQoZGltMSk7XG4gICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uc2VuZFBsYXlTdGF0dXMoUGxheVN0YXR1c1R5cGUuUGxheWVyU3Bhd24pO1xuXG4gICAgICAgIGF3YWl0IHRoaXMuc2VuZEluaXRpYWxTcGF3bkNodW5rcygpO1xuXG4gICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uc2VuZChkaW0xKTtcbiAgICAgICAgYXdhaXQgdGhpcy5uZXR3b3JrU2Vzc2lvbi5zZW5kUGxheVN0YXR1cyhQbGF5U3RhdHVzVHlwZS5QbGF5ZXJTcGF3bik7XG4gICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uc2VuZChkaW0wKTtcbiAgICAgICAgYXdhaXQgdGhpcy5uZXR3b3JrU2Vzc2lvbi5zZW5kUGxheVN0YXR1cyhQbGF5U3RhdHVzVHlwZS5QbGF5ZXJTcGF3bik7XG5cbiAgICAgICAgYXdhaXQgdGhpcy5uZXR3b3JrU2Vzc2lvbi5jbGVhckNodW5rcygpO1xuICAgICAgICBhd2FpdCB0aGlzLm5ldHdvcmtTZXNzaW9uLm5lZWROZXdDaHVua3MoKTtcbiAgICAgICAgYXdhaXQgdGhpcy5uZXR3b3JrU2Vzc2lvbi5zZW5kUGxheVN0YXR1cyhQbGF5U3RhdHVzVHlwZS5QbGF5ZXJTcGF3bik7XG4gICAgfVxuXG4gICAgcHVibGljIGlzT25saW5lKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jb25uZWN0ZWQ7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHVwZGF0ZSh0aWNrOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgc3VwZXIudXBkYXRlKHRpY2spO1xuICAgICAgICBhd2FpdCB0aGlzLm5ldHdvcmtTZXNzaW9uLnVwZGF0ZSh0aWNrKTtcblxuICAgICAgICAvLyBUT0RPOiBnZXQgZG9jdW1lbnRhdGlvbiBhYm91dCB0aW1pbmdzIGZyb20gdmFuaWxsYVxuICAgICAgICAvLyAxIHNlY29uZCAvIDIwID0gMSB0aWNrLCAyMCAqIDUgPSAxIHNlY29uZFxuICAgICAgICAvLyAxIHNlY29uZCAqIDYwID0gMSBtaW51dGVcbiAgICAgICAgaWYgKHRpY2sgJSAoMjAgKiA1ICogNjAgKiAxKSA9PT0gMCkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5uZXR3b3JrU2Vzc2lvbi5zZW5kVGltZSh0aWNrKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZvciAoY29uc3QgY2h1bmsgb2YgdGhpcy5jaHVua1NlbmRRdWV1ZSkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5uZXR3b3JrU2Vzc2lvbi5zZW5kTmV0d29ya0NodW5rUHVibGlzaGVyKHRoaXMudmlld0Rpc3RhbmNlIHx8IFZBTklMTEFfREVGQVVMVF9TUEFXTl9SQURJVVMsIFtdKTtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uc2VuZENodW5rKGNodW5rKTtcbiAgICAgICAgICAgIHRoaXMuY2h1bmtTZW5kUXVldWUuZGVsZXRlKGNodW5rKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBraWNrKHJlYXNvbiA9ICd1bmtub3duIHJlYXNvbicpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5kaXNhYmxlKCk7XG4gICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24ua2ljayhyZWFzb24pO1xuICAgICAgICB0aGlzLnNlcnZlci5nZXRMb2dnZXIoKS52ZXJib3NlKGBQbGF5ZXIgd2l0aCBpZCDCp2Ike3RoaXMuZ2V0UnVudGltZUlkKCl9wqdyIHdhcyBraWNrZWQ6ICR7cmVhc29ufWApO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBzZW5kU2V0dGluZ3MoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuZ2V0TmV0d29ya1Nlc3Npb24oKS5zZW5kR2FtZW1vZGUoKTtcblxuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgICAgIHRoaXMuc2VydmVyXG4gICAgICAgICAgICAgICAgLmdldFNlc3Npb25NYW5hZ2VyKClcbiAgICAgICAgICAgICAgICAuZ2V0QWxsUGxheWVycygpXG4gICAgICAgICAgICAgICAgLm1hcChhc3luYyAodGFyZ2V0KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHRhcmdldC5nZXROZXR3b3JrU2Vzc2lvbigpLnNlbmRBYmlsaXRpZXModGhpcyk7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHRhcmdldC5nZXROZXR3b3JrU2Vzc2lvbigpLnNlbmRTZXR0aW5ncyh0aGlzKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFBsYXllciBzcGF3bmluZyBsb2dpYy5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgc2VuZFNwYXduKCkge1xuICAgICAgICBhd2FpdCB0aGlzLnNlbmRQb3NpdGlvbigpO1xuICAgICAgICBhd2FpdCB0aGlzLnNldEdhbWVtb2RlKCk7XG4gICAgICAgIGF3YWl0IHRoaXMuZ2V0TmV0d29ya1Nlc3Npb24oKS5zZW5kSW52ZW50b3J5KCk7XG4gICAgICAgIGF3YWl0IHRoaXMuc2VuZFNldHRpbmdzKCk7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBzZW5kRGVzcGF3bigpIHt9XG5cbiAgICAvKipcbiAgICAgKiBTZW5kIGEgY2hhdCBtZXNzYWdlIHRvIHRoZSBjbGllbnQuXG4gICAgICogQHBhcmFtIG1lc3NhZ2UgLSB0aGUgbWVzc2FnZVxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBzZW5kTWVzc2FnZShcbiAgICAgICAgbWVzc2FnZTogc3RyaW5nLFxuICAgICAgICB0eXBlOiBUZXh0VHlwZSA9IFRleHRUeXBlLlJhdyxcbiAgICAgICAgcGFyYW1ldGVyczogc3RyaW5nW10gPSBbXSxcbiAgICAgICAgbmVlZHNUcmFuc2xhdGlvbiA9IGZhbHNlXG4gICAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIC8vIFRPRE86IERvIHRoaXMgcHJvcGVybHkgbGlrZSBqYXZhIGVkaXRpb24sXG4gICAgICAgIC8vIGluIG90aGVyIHdvcmRzLCB0aGUgbWVzc2FnZSBzaG91bGQgYmUgSlNPTiBmb3JtYXR0ZWQuXG4gICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uc2VuZE1lc3NhZ2Uoe1xuICAgICAgICAgICAgbWVzc2FnZSxcbiAgICAgICAgICAgIHBhcmFtZXRlcnMsXG4gICAgICAgICAgICBuZWVkc1RyYW5zbGF0aW9uLFxuICAgICAgICAgICAgdHlwZVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgc2V0R2FtZW1vZGUobW9kZT86IEdhbWV0eXBlKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIG1vZGUgPz89IHRoaXMuZ2FtZW1vZGU7XG5cbiAgICAgICAgY29uc3QgZXZlbnQgPSBuZXcgUGxheWVyU2V0R2FtZW1vZGVFdmVudCh0aGlzLCBtb2RlKTtcbiAgICAgICAgdGhpcy5zZXJ2ZXIucG9zdChbJ3BsYXllclNldEdhbWVtb2RlJywgZXZlbnRdKTtcbiAgICAgICAgaWYgKGV2ZW50LmlzQ2FuY2VsbGVkKCkpIHJldHVybjtcblxuICAgICAgICB0aGlzLmdhbWVtb2RlID0gZXZlbnQuZ2V0R2FtZW1vZGUoKTtcbiAgICAgICAgYXdhaXQgdGhpcy5uZXR3b3JrU2Vzc2lvbi5zZW5kR2FtZW1vZGUoKTtcblxuICAgICAgICBpZiAodGhpcy5nYW1lbW9kZSA9PT0gR2FtZXR5cGUuQ1JFQVRJVkUgfHwgdGhpcy5nYW1lbW9kZSA9PT0gR2FtZXR5cGUuU1BFQ1RBVE9SKSB7XG4gICAgICAgICAgICB0aGlzLm1ldGFkYXRhLnNldENhbkZseSh0cnVlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMubWV0YWRhdGEuc2V0Q2FuRmx5KGZhbHNlKTtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuc2V0Rmx5aW5nKGZhbHNlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGF3YWl0IHRoaXMuc2VuZFNldHRpbmdzKCk7XG4gICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uc2VuZEdhbWVtb2RlKCk7XG4gICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uc2VuZE1ldGFkYXRhKCk7XG4gICAgfVxuXG4gICAgcHVibGljIGdldE5ldHdvcmtTZXNzaW9uKCk6IFBsYXllclNlc3Npb24ge1xuICAgICAgICByZXR1cm4gdGhpcy5uZXR3b3JrU2Vzc2lvbjtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0QWRkcmVzcygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYWRkcmVzcztcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0TmFtZSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdGhpcy5tZXRhZGF0YS5uYW1lVGFnO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRGb3JtYXR0ZWRVc2VybmFtZSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gYDwke3RoaXMuZ2V0TmFtZSgpfT5gO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRQZXJtaXNzaW9ucygpOiBzdHJpbmdbXSB7XG4gICAgICAgIHJldHVybiB0aGlzLnBlcm1pc3Npb25zO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCB0aGUgWFVJRCBvZiB0aGUgcGxheWVyLlxuICAgICAqIEByZXR1cm5zIHtzdHJpbmcgfCBudWxsfSBYVUlEIG9mIHRoZSBwbGF5ZXIgb3IgbnVsbCBpZiBub3QgYXZhaWxhYmxlXG4gICAgICovXG4gICAgcHVibGljIGdldFhVSUQoKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgICAgIHJldHVybiB0aGlzLnh1aWQgfHwgbnVsbDtcbiAgICB9XG5cbiAgICBwdWJsaWMgaXNQbGF5ZXIoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrIGlmIHRoZSBgUGxheWVyYCBpcyBhbiBvcGVyYXRvci5cbiAgICAgKiBAcmV0dXJucyBgdHJ1ZWAgaWYgdGhpcyBwbGF5ZXIgaXMgYW4gb3BlcmF0b3Igb3RoZXJ3aXNlIGBmYWxzZWAuXG4gICAgICovXG4gICAgcHVibGljIGlzT3AoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLnNlcnZlci5nZXRQZXJtaXNzaW9uTWFuYWdlcigpLmlzT3AodGhpcy5nZXROYW1lKCkpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBzZXRTcHJpbnRpbmcoc3ByaW50aW5nOiBib29sZWFuKSB7XG4gICAgICAgIGlmIChzcHJpbnRpbmcgPT09IHRoaXMubWV0YWRhdGEuc3ByaW50aW5nKSByZXR1cm47XG5cbiAgICAgICAgY29uc3QgZXZlbnQgPSBuZXcgUGxheWVyVG9nZ2xlU3ByaW50RXZlbnQodGhpcywgc3ByaW50aW5nKTtcbiAgICAgICAgdGhpcy5zZXJ2ZXIucG9zdChbJ3BsYXllclRvZ2dsZVNwcmludCcsIGV2ZW50XSk7XG4gICAgICAgIGlmIChldmVudC5pc0NhbmNlbGxlZCgpKSByZXR1cm47XG5cbiAgICAgICAgdGhpcy5tZXRhZGF0YS5zZXRTcHJpbnRpbmcoZXZlbnQuZ2V0SXNTcHJpbnRpbmcoKSk7XG4gICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uc2VuZE1ldGFkYXRhKCk7XG4gICAgfVxuXG4gICAgcHVibGljIGlzRmx5aW5nKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5mbHlpbmc7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBzZXRGbHlpbmcoZmx5aW5nOiBib29sZWFuKSB7XG4gICAgICAgIGlmIChmbHlpbmcgPT09IHRoaXMuaXNGbHlpbmcoKSkgcmV0dXJuO1xuXG4gICAgICAgIGlmICghdGhpcy5tZXRhZGF0YS5jYW5GbHkpIHtcbiAgICAgICAgICAgIHRoaXMuZmx5aW5nID0gZmFsc2U7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnNlbmRTZXR0aW5ncygpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZXZlbnQgPSBuZXcgUGxheWVyVG9nZ2xlRmxpZ2h0RXZlbnQodGhpcywgZmx5aW5nKTtcbiAgICAgICAgdGhpcy5zZXJ2ZXIucG9zdChbJ3BsYXllclRvZ2dsZUZsaWdodCcsIGV2ZW50XSk7XG4gICAgICAgIGlmIChldmVudC5pc0NhbmNlbGxlZCgpKSByZXR1cm47XG5cbiAgICAgICAgdGhpcy5mbHlpbmcgPSBldmVudC5nZXRJc0ZseWluZygpO1xuICAgICAgICBhd2FpdCB0aGlzLnNlbmRTZXR0aW5ncygpO1xuICAgIH1cblxuICAgIHB1YmxpYyBpc1NuZWFraW5nKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zbmVha2luZztcbiAgICB9XG4gICAgcHVibGljIGFzeW5jIHNldFNuZWFraW5nKHZhbDogYm9vbGVhbikge1xuICAgICAgICBpZiAodmFsID09PSB0aGlzLnNuZWFraW5nKSByZXR1cm47XG4gICAgICAgIHRoaXMuc25lYWtpbmcgPSB2YWw7XG4gICAgfVxuXG4gICAgcHVibGljIGlzT25Hcm91bmQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm9uR3JvdW5kO1xuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgc2V0T25Hcm91bmQodmFsOiBib29sZWFuKSB7XG4gICAgICAgIGlmICh2YWwgPT09IHRoaXMub25Hcm91bmQpIHJldHVybjtcbiAgICAgICAgdGhpcy5vbkdyb3VuZCA9IHZhbDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXQgdGhlIHBvc2l0aW9uLlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgdG8gc2V0IHRoZSBwb3NpdGlvbi5cbiAgICAgKiBAcGFyYW0ge1ZlY3RvcjN9IG9wdGlvbnMucG9zaXRpb24gLSBUaGUgbmV3IHBvc2l0aW9uLlxuICAgICAqIEBwYXJhbSB7TW92ZW1lbnRUeXBlfSBbb3B0aW9ucy50eXBlPU1vdmVtZW50VHlwZS5Ob3JtYWxdIC0gVGhlIG1vdmVtZW50IHR5cGUuXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IFtvcHRpb25zLnBpdGNoPXRoaXMucGl0Y2hdIC0gVGhlIG5ldyBwaXRjaC5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gW29wdGlvbnMueWF3PXRoaXMueWF3XSAtIFRoZSBuZXcgeWF3LlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0aW9ucy5oZWFkWWF3PXRoaXMuaGVhZFlhd10gLSBUaGUgbmV3IGhlYWQgeWF3LlxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2Jyb2FkY2FzdD10cnVlXSAtIFdoZXRoZXIgdG8gYnJvYWRjYXN0IHRoZSBwb3NpdGlvbiBjaGFuZ2UuXG4gICAgICogQHJlbWFya3MgVGhpcyB3aWxsIG5vdGlmeSB0aGUgcGxheWVyJ3MgY2xpZW50IGFib3V0IHRoZSBwb3NpdGlvbiBjaGFuZ2UuXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIHNldFBvc2l0aW9uKFxuICAgICAgICB7XG4gICAgICAgICAgICBwb3NpdGlvbixcbiAgICAgICAgICAgIHR5cGUgPSBNb3ZlbWVudFR5cGUuTm9ybWFsLFxuICAgICAgICAgICAgcGl0Y2ggPSB0aGlzLnBpdGNoLFxuICAgICAgICAgICAgeWF3ID0gdGhpcy55YXcsXG4gICAgICAgICAgICBoZWFkWWF3ID0gdGhpcy5oZWFkWWF3XG4gICAgICAgIH06IHtcbiAgICAgICAgICAgIHBvc2l0aW9uOiBWZWN0b3IzO1xuICAgICAgICAgICAgdHlwZT86IE1vdmVtZW50VHlwZTtcbiAgICAgICAgICAgIHBpdGNoPzogbnVtYmVyO1xuICAgICAgICAgICAgeWF3PzogbnVtYmVyO1xuICAgICAgICAgICAgaGVhZFlhdz86IG51bWJlcjtcbiAgICAgICAgfSxcbiAgICAgICAgYnJvYWRjYXN0ID0gdHJ1ZVxuICAgICkge1xuICAgICAgICBhd2FpdCBzdXBlci5zZXRQb3NpdGlvbih7IHBvc2l0aW9uIH0pO1xuICAgICAgICB0aGlzLnBpdGNoID0gcGl0Y2g7XG4gICAgICAgIHRoaXMueWF3ID0geWF3O1xuICAgICAgICB0aGlzLmhlYWRZYXcgPSBoZWFkWWF3O1xuXG4gICAgICAgIGlmICghYnJvYWRjYXN0KSByZXR1cm47XG4gICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uYnJvYWRjYXN0TW92ZSh0aGlzLCB0eXBlKTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogU2VuZCB0aGUgcG9zaXRpb24gdG8gYWxsIHRoZSBwbGF5ZXJzIGluIHRoZSBzYW1lIHdvcmxkLlxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBwb3NpdGlvbiBpcyBzZW50LlxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBzZW5kUG9zaXRpb24oKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHN1cGVyLnNlbmRQb3NpdGlvbigpO1xuICAgIH1cbn1cbiJdLCJuYW1lcyI6W10sIm1h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