UNPKG

@jsprismarine/prismarine

Version:

Dedicated Minecraft Bedrock Edition server written in TypeScript

333 lines (332 loc) 42.6 kB
"use strict"; Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } }); require("./_virtual/_rolldown/runtime.cjs.cjs"); const require_events_chat_ChatEvent = require("./events/chat/ChatEvent.cjs.cjs"); const require_utils_Timer = require("./utils/Timer.cjs.cjs"); const require_network_type_TextType = require("./network/type/TextType.cjs.cjs"); const require_network_packet_ChangeDimensionPacket = require("./network/packet/ChangeDimensionPacket.cjs.cjs"); const require_network_type_MovementType = require("./network/type/MovementType.cjs.cjs"); const require_entity_Human = require("./entity/Human.cjs.cjs"); const require_chat_Chat = require("./chat/Chat.cjs.cjs"); const require_events_player_PlayerSetGamemodeEvent = require("./events/player/PlayerSetGamemodeEvent.cjs.cjs"); const require_events_player_PlayerToggleFlightEvent = require("./events/player/PlayerToggleFlightEvent.cjs.cjs"); const require_events_player_PlayerToggleSprintEvent = require("./events/player/PlayerToggleSprintEvent.cjs.cjs"); const require_network_type_PlayStatusType = require("./network/type/PlayStatusType.cjs.cjs"); const require_world_CoordinateUtils = require("./world/CoordinateUtils.cjs.cjs"); const require_network_PlayerSession = require("./network/PlayerSession.cjs.cjs"); let _jsprismarine_math = require("@jsprismarine/math"); let _jsprismarine_minecraft = require("@jsprismarine/minecraft"); //#region src/Player.ts /** * Default spawn view distance used in vanilla */ var VANILLA_DEFAULT_SPAWN_RADIUS = 4; var Player = class extends require_entity_Human.default { address; networkSession; permissions; /** * Timer used for various metrics. */ timer; connected = false; xuid = ""; randomId = 0; locale = ""; skin = null; viewDistance = 0; gamemode = _jsprismarine_minecraft.Gametype.WORLD_DEFAULT; onGround = false; flying = false; sneaking = false; platformChatId = ""; device = null; chunkSendQueue = /* @__PURE__ */ new Set(); /** * Player's constructor. */ constructor({ connection, world, server, uuid }) { super({ world, server, uuid }); this.timer = new require_utils_Timer.default(); this.address = connection.getRakNetSession().getAddress(); this.networkSession = new require_network_PlayerSession.default(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 = (0, _jsprismarine_minecraft.getGametypeId)(playerData.gamemode || this.server.getConfig().getGamemode()); this.setPosition({ position: playerData.position ? _jsprismarine_math.Vector3.fromObject(playerData.position) : await this.getWorld().getSpawnPosition(), pitch: playerData.position?.pitch || 0, yaw: playerData.position?.yaw || 0, headYaw: playerData.position?.headYaw || 0, type: require_network_type_MovementType.default.Reset }); await this.sendPosition(); await this.sendSettings(); await Promise.all(this.getWorld().getPlayers().map((target) => this.getNetworkSession().broadcastMove(target, require_network_type_MovementType.default.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 require_events_chat_ChatEvent.default(new require_chat_Chat.Chat({ sender: this.server.getConsole(), message: `§e%multiplayer.player.left`, parameters: [this.getName()], needsTranslation: true, type: require_chat_Chat.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 = require_world_CoordinateUtils.default.fromBlockToChunk(this.x) - 4; const minZ = require_world_CoordinateUtils.default.fromBlockToChunk(this.z) - 4; const maxX = require_world_CoordinateUtils.default.fromBlockToChunk(this.x) + 4; const maxZ = require_world_CoordinateUtils.default.fromBlockToChunk(this.z) + 4; 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(4, 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(4, []); 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 require_network_packet_ChangeDimensionPacket.default(); dim0.dimension = 0; dim0.position = this.getPosition(); dim0.respawn = false; const dim1 = new require_network_packet_ChangeDimensionPacket.default(); 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(require_network_type_PlayStatusType.default.PlayerSpawn); await this.networkSession.send(dim1); await this.networkSession.sendPlayStatus(require_network_type_PlayStatusType.default.PlayerSpawn); await this.sendInitialSpawnChunks(); await this.networkSession.send(dim1); await this.networkSession.sendPlayStatus(require_network_type_PlayStatusType.default.PlayerSpawn); await this.networkSession.send(dim0); await this.networkSession.sendPlayStatus(require_network_type_PlayStatusType.default.PlayerSpawn); await this.networkSession.clearChunks(); await this.networkSession.needNewChunks(); await this.networkSession.sendPlayStatus(require_network_type_PlayStatusType.default.PlayerSpawn); } isOnline() { return this.connected; } async update(tick) { await super.update(tick); await this.networkSession.update(tick); if (tick % (6e3 * 1) === 0) await this.networkSession.sendTime(tick); for (const chunk of this.chunkSendQueue) { await this.networkSession.sendNetworkChunkPublisher(this.viewDistance || 4, []); 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 = require_network_type_TextType.default.Raw, parameters = [], needsTranslation = false) { await this.networkSession.sendMessage({ message, parameters, needsTranslation, type }); } async setGamemode(mode) { mode ??= this.gamemode; const event = new require_events_player_PlayerSetGamemodeEvent.default(this, mode); this.server.post(["playerSetGamemode", event]); if (event.isCancelled()) return; this.gamemode = event.getGamemode(); await this.networkSession.sendGamemode(); if (this.gamemode === _jsprismarine_minecraft.Gametype.CREATIVE || this.gamemode === _jsprismarine_minecraft.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 require_events_player_PlayerToggleSprintEvent.default(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 require_events_player_PlayerToggleFlightEvent.default(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 = require_network_type_MovementType.default.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(); } }; //#endregion exports.VANILLA_DEFAULT_SPAWN_RADIUS = VANILLA_DEFAULT_SPAWN_RADIUS; exports.default = Player; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGxheWVyLmNqcy5janMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vc3JjL1BsYXllci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBWZWN0b3IzIH0gZnJvbSAnQGpzcHJpc21hcmluZS9tYXRoJztcbmltcG9ydCB7IEdhbWV0eXBlLCBnZXRHYW1ldHlwZUlkIH0gZnJvbSAnQGpzcHJpc21hcmluZS9taW5lY3JhZnQnO1xuaW1wb3J0IHR5cGUgeyBJbmV0QWRkcmVzcyB9IGZyb20gJ0Bqc3ByaXNtYXJpbmUvcmFrbmV0JztcbmltcG9ydCB0eXBlIFNlcnZlciBmcm9tICcuL1NlcnZlcic7XG5pbXBvcnQgeyBDaGF0LCBDaGF0VHlwZSB9IGZyb20gJy4vY2hhdC9DaGF0JztcbmltcG9ydCBIdW1hbiBmcm9tICcuL2VudGl0eS9IdW1hbic7XG5pbXBvcnQgQ2hhdEV2ZW50IGZyb20gJy4vZXZlbnRzL2NoYXQvQ2hhdEV2ZW50JztcbmltcG9ydCBQbGF5ZXJTZXRHYW1lbW9kZUV2ZW50IGZyb20gJy4vZXZlbnRzL3BsYXllci9QbGF5ZXJTZXRHYW1lbW9kZUV2ZW50JztcbmltcG9ydCBQbGF5ZXJUb2dnbGVGbGlnaHRFdmVudCBmcm9tICcuL2V2ZW50cy9wbGF5ZXIvUGxheWVyVG9nZ2xlRmxpZ2h0RXZlbnQnO1xuaW1wb3J0IFBsYXllclRvZ2dsZVNwcmludEV2ZW50IGZyb20gJy4vZXZlbnRzL3BsYXllci9QbGF5ZXJUb2dnbGVTcHJpbnRFdmVudCc7XG5pbXBvcnQgdHlwZSBDbGllbnRDb25uZWN0aW9uIGZyb20gJy4vbmV0d29yay9DbGllbnRDb25uZWN0aW9uJztcbmltcG9ydCB7IENoYW5nZURpbWVuc2lvblBhY2tldCB9IGZyb20gJy4vbmV0d29yay9QYWNrZXRzJztcbmltcG9ydCBQbGF5ZXJTZXNzaW9uIGZyb20gJy4vbmV0d29yay9QbGF5ZXJTZXNzaW9uJztcbmltcG9ydCB0eXBlIHsgQ2h1bmtDb29yZCB9IGZyb20gJy4vbmV0d29yay9wYWNrZXQvTmV0d29ya0NodW5rUHVibGlzaGVyVXBkYXRlUGFja2V0JztcbmltcG9ydCBNb3ZlbWVudFR5cGUgZnJvbSAnLi9uZXR3b3JrL3R5cGUvTW92ZW1lbnRUeXBlJztcbmltcG9ydCBQbGF5U3RhdHVzVHlwZSBmcm9tICcuL25ldHdvcmsvdHlwZS9QbGF5U3RhdHVzVHlwZSc7XG5pbXBvcnQgVGV4dFR5cGUgZnJvbSAnLi9uZXR3b3JrL3R5cGUvVGV4dFR5cGUnO1xuaW1wb3J0IHR5cGUgRGV2aWNlIGZyb20gJy4vdXRpbHMvRGV2aWNlJztcbmltcG9ydCBUaW1lciBmcm9tICcuL3V0aWxzL1RpbWVyJztcbmltcG9ydCB0eXBlIFNraW4gZnJvbSAnLi91dGlscy9za2luL1NraW4nO1xuaW1wb3J0IHR5cGUgeyBXb3JsZCB9IGZyb20gJy4vd29ybGQvJztcbmltcG9ydCBDb29yZGluYXRlVXRpbHMgZnJvbSAnLi93b3JsZC9Db29yZGluYXRlVXRpbHMnO1xuaW1wb3J0IHR5cGUgQ2h1bmsgZnJvbSAnLi93b3JsZC9jaHVuay9DaHVuayc7XG5cbi8qKlxuICogRGVmYXVsdCBzcGF3biB2aWV3IGRpc3RhbmNlIHVzZWQgaW4gdmFuaWxsYVxuICovXG5leHBvcnQgY29uc3QgVkFOSUxMQV9ERUZBVUxUX1NQQVdOX1JBRElVUyA9IDQ7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFBsYXllciBleHRlbmRzIEh1bWFuIHtcbiAgICBwcml2YXRlIHJlYWRvbmx5IGFkZHJlc3M6IEluZXRBZGRyZXNzO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgbmV0d29ya1Nlc3Npb246IFBsYXllclNlc3Npb247XG4gICAgcHJpdmF0ZSBwZXJtaXNzaW9uczogc3RyaW5nW107XG5cbiAgICAvKipcbiAgICAgKiBUaW1lciB1c2VkIGZvciB2YXJpb3VzIG1ldHJpY3MuXG4gICAgICovXG4gICAgcHJpdmF0ZSB0aW1lcjogVGltZXI7XG4gICAgcHJpdmF0ZSBjb25uZWN0ZWQgPSBmYWxzZTtcblxuICAgIHB1YmxpYyB4dWlkID0gJyc7XG4gICAgcHVibGljIHJhbmRvbUlkID0gMDtcblxuICAgIHB1YmxpYyBsb2NhbGUgPSAnJztcbiAgICBwdWJsaWMgc2tpbjogU2tpbiB8IG51bGwgPSBudWxsO1xuXG4gICAgcHVibGljIHZpZXdEaXN0YW5jZSA9IDA7XG4gICAgcHVibGljIGdhbWVtb2RlOiBHYW1ldHlwZSA9IEdhbWV0eXBlLldPUkxEX0RFRkFVTFQ7XG5cbiAgICBwcml2YXRlIG9uR3JvdW5kID0gZmFsc2U7XG4gICAgcHJpdmF0ZSBmbHlpbmcgPSBmYWxzZTtcbiAgICBwcml2YXRlIHNuZWFraW5nID0gZmFsc2U7XG5cbiAgICBwdWJsaWMgcGxhdGZvcm1DaGF0SWQgPSAnJzsgLy8gVE9ETzogcmVhZCB0aGlzIHZhbHVlIGZyb20gTG9naW5cbiAgICBwdWJsaWMgZGV2aWNlOiBEZXZpY2UgfCBudWxsID0gbnVsbDtcblxuICAgIHB1YmxpYyByZWFkb25seSBjaHVua1NlbmRRdWV1ZSA9IG5ldyBTZXQ8Q2h1bms+KCk7XG5cbiAgICAvKipcbiAgICAgKiBQbGF5ZXIncyBjb25zdHJ1Y3Rvci5cbiAgICAgKi9cbiAgICBwdWJsaWMgY29uc3RydWN0b3Ioe1xuICAgICAgICBjb25uZWN0aW9uLFxuICAgICAgICB3b3JsZCxcbiAgICAgICAgc2VydmVyLFxuICAgICAgICB1dWlkXG4gICAgfToge1xuICAgICAgICBjb25uZWN0aW9uOiBDbGllbnRDb25uZWN0aW9uO1xuICAgICAgICB3b3JsZDogV29ybGQ7XG4gICAgICAgIHNlcnZlcjogU2VydmVyO1xuICAgICAgICB1dWlkPzogc3RyaW5nO1xuICAgIH0pIHtcbiAgICAgICAgc3VwZXIoe1xuICAgICAgICAgICAgd29ybGQsXG4gICAgICAgICAgICBzZXJ2ZXIsXG4gICAgICAgICAgICB1dWlkXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMudGltZXIgPSBuZXcgVGltZXIoKTtcblxuICAgICAgICB0aGlzLmFkZHJlc3MgPSBjb25uZWN0aW9uLmdldFJha05ldFNlc3Npb24oKS5nZXRBZGRyZXNzKCk7XG4gICAgICAgIHRoaXMubmV0d29ya1Nlc3Npb24gPSBuZXcgUGxheWVyU2Vzc2lvbihzZXJ2ZXIsIGNvbm5lY3Rpb24sIHRoaXMpO1xuICAgICAgICB0aGlzLnBlcm1pc3Npb25zID0gW107XG5cbiAgICAgICAgdGhpcy5zZXJ2ZXIub24oJ2NoYXQnLCB0aGlzLmNoYXRIYW5kbGVyLmJpbmQodGhpcykpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIE9uIGVuYWJsZSBob29rLlxuICAgICAqIEBncm91cCBMaWZlY3ljbGVcbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgZW5hYmxlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBwbGF5ZXJEYXRhID0gYXdhaXQgdGhpcy5nZXRXb3JsZCgpLmdldFBsYXllckRhdGEodGhpcyk7XG5cbiAgICAgICAgdGhpcy5wZXJtaXNzaW9ucyA9IGF3YWl0IHRoaXMuc2VydmVyLmdldFBlcm1pc3Npb25NYW5hZ2VyKCkuZ2V0UGVybWlzc2lvbnModGhpcyk7XG4gICAgICAgIHRoaXMuZ2FtZW1vZGUgPSBnZXRHYW1ldHlwZUlkKHBsYXllckRhdGEuZ2FtZW1vZGUgfHwgdGhpcy5zZXJ2ZXIuZ2V0Q29uZmlnKCkuZ2V0R2FtZW1vZGUoKSk7XG5cbiAgICAgICAgdGhpcy5zZXRQb3NpdGlvbih7XG4gICAgICAgICAgICBwb3NpdGlvbjogcGxheWVyRGF0YS5wb3NpdGlvblxuICAgICAgICAgICAgICAgID8gVmVjdG9yMy5mcm9tT2JqZWN0KHBsYXllckRhdGEucG9zaXRpb24pXG4gICAgICAgICAgICAgICAgOiBhd2FpdCB0aGlzLmdldFdvcmxkKCkuZ2V0U3Bhd25Qb3NpdGlvbigpLFxuICAgICAgICAgICAgcGl0Y2g6IHBsYXllckRhdGEucG9zaXRpb24/LnBpdGNoIHx8IDAsXG4gICAgICAgICAgICB5YXc6IHBsYXllckRhdGEucG9zaXRpb24/LnlhdyB8fCAwLFxuICAgICAgICAgICAgaGVhZFlhdzogcGxheWVyRGF0YS5wb3NpdGlvbj8uaGVhZFlhdyB8fCAwLFxuICAgICAgICAgICAgdHlwZTogTW92ZW1lbnRUeXBlLlJlc2V0XG4gICAgICAgIH0pO1xuICAgICAgICBhd2FpdCB0aGlzLnNlbmRQb3NpdGlvbigpO1xuXG4gICAgICAgIGF3YWl0IHRoaXMuc2VuZFNldHRpbmdzKCk7XG5cbiAgICAgICAgLy8gVXBkYXRlIHBvc2l0aW9uIG9mIGFsbCB0aGUgcGxheWVycyBpbiB0aGUgc2FtZSB3b3JsZC5cbiAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgICAgICB0aGlzLmdldFdvcmxkKClcbiAgICAgICAgICAgICAgICAuZ2V0UGxheWVycygpXG4gICAgICAgICAgICAgICAgLm1hcCgodGFyZ2V0KSA9PiB0aGlzLmdldE5ldHdvcmtTZXNzaW9uKCkuYnJvYWRjYXN0TW92ZSh0YXJnZXQsIE1vdmVtZW50VHlwZS5SZXNldCkpXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gRmluYWxseSBtYXJrIHRoZSBwbGF5ZXIgYXMgY29ubmVjdGVkLlxuICAgICAgICB0aGlzLnNlcnZlci5nZXRMb2dnZXIoKS5kZWJ1ZyhgKENvbXBsZXRlIHBsYXllciBjcmVhdGlvbiB0b29rICR7dGhpcy50aW1lci5zdG9wKCl9IG1zKWApO1xuICAgICAgICB0aGlzLmNvbm5lY3RlZCA9IHRydWU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogT24gZGlzYWJsZSBob29rLlxuICAgICAqIEBncm91cCBMaWZlY3ljbGVcbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgZGlzYWJsZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKHRoaXMuY29ubmVjdGVkICYmIHRoaXMueHVpZCkgYXdhaXQgdGhpcy5nZXRXb3JsZCgpLnNhdmVQbGF5ZXJEYXRhKHRoaXMpO1xuICAgICAgICBhd2FpdCB0aGlzLmdldFdvcmxkKCkucmVtb3ZlRW50aXR5KHRoaXMpO1xuXG4gICAgICAgIC8vIERlLXNwYXduIHRoZSBwbGF5ZXIgdG8gYWxsIG9ubGluZSBwbGF5ZXJzXG4gICAgICAgIGF3YWl0IHRoaXMuZ2V0TmV0d29ya1Nlc3Npb24oKS5yZW1vdmVGcm9tUGxheWVyTGlzdCgpO1xuICAgICAgICBmb3IgKGNvbnN0IG9ubGluZVBsYXllciBvZiB0aGlzLnNlcnZlci5nZXRTZXNzaW9uTWFuYWdlcigpLmdldEFsbFBsYXllcnMoKSkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5nZXROZXR3b3JrU2Vzc2lvbigpLnNlbmREZXNwYXduKG9ubGluZVBsYXllcik7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBBbm5vdW5jZSBkaXNjb25uZWN0aW9uXG4gICAgICAgIGNvbnN0IGV2ZW50ID0gbmV3IENoYXRFdmVudChcbiAgICAgICAgICAgIG5ldyBDaGF0KHtcbiAgICAgICAgICAgICAgICBzZW5kZXI6IHRoaXMuc2VydmVyLmdldENvbnNvbGUoKSEsXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogYMKnZSVtdWx0aXBsYXllci5wbGF5ZXIubGVmdGAsXG4gICAgICAgICAgICAgICAgcGFyYW1ldGVyczogW3RoaXMuZ2V0TmFtZSgpXSxcbiAgICAgICAgICAgICAgICBuZWVkc1RyYW5zbGF0aW9uOiB0cnVlLFxuICAgICAgICAgICAgICAgIHR5cGU6IENoYXRUeXBlLlRSQU5TTEFUSU9OXG4gICAgICAgICAgICB9KVxuICAgICAgICApO1xuICAgICAgICBhd2FpdCB0aGlzLnNlcnZlci5lbWl0KCdjaGF0JywgZXZlbnQpO1xuXG4gICAgICAgIHRoaXMuY29ubmVjdGVkID0gZmFsc2U7XG4gICAgICAgIHRoaXMuc2VydmVyLnJlbW92ZUxpc3RlbmVyKCdjaGF0JywgdGhpcy5jaGF0SGFuZGxlcik7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBjaGF0SGFuZGxlcihldnQ6IENoYXRFdmVudCkge1xuICAgICAgICBpZiAoZXZ0LmlzQ2FuY2VsbGVkKCkpIHJldHVybjtcblxuICAgICAgICAvLyBUT0RPOiBwcm9wZXIgY2hhbm5lbCBzeXN0ZW1cbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgZXZ0LmdldENoYXQoKS5nZXRDaGFubmVsKCkgPT09ICcqLmV2ZXJ5b25lJyB8fFxuICAgICAgICAgICAgKGV2dC5nZXRDaGF0KCkuZ2V0Q2hhbm5lbCgpID09PSAnKi5vcHMnICYmIHRoaXMuaXNPcCgpKSB8fFxuICAgICAgICAgICAgZXZ0LmdldENoYXQoKS5nZXRDaGFubmVsKCkgPT09IGAqLnBsYXllci4ke3RoaXMuZ2V0TmFtZSgpfWBcbiAgICAgICAgKVxuICAgICAgICAgICAgYXdhaXQgdGhpcy5zZW5kTWVzc2FnZShcbiAgICAgICAgICAgICAgICBldnQuZ2V0Q2hhdCgpLmdldE1lc3NhZ2UoKSxcbiAgICAgICAgICAgICAgICBldnQuZ2V0Q2hhdCgpLmdldFR5cGUoKSBhcyBudW1iZXIgYXMgVGV4dFR5cGUsXG4gICAgICAgICAgICAgICAgZXZ0LmdldENoYXQoKS5nZXRQYXJhbWV0ZXJzKCksXG4gICAgICAgICAgICAgICAgZXZ0LmdldENoYXQoKS5pc05lZWRzVHJhbnNsYXRpb24oKVxuICAgICAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBVc2VkIHRvIG1hdGNoIHZhbmlsbGEgYmVoYXZpb3IsIHdpbGwgc2VuZCBjaHVua3NcbiAgICAgKiB3aXRoIGFuIGluaXRpYWwgdmlldyByYWRpdXMgb2YgVkFOSUxMQV9ERUZBVUxUX1NQQVdOX1JBRElVUy5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgc2VuZEluaXRpYWxTcGF3bkNodW5rcygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgbWluWCA9IENvb3JkaW5hdGVVdGlscy5mcm9tQmxvY2tUb0NodW5rKHRoaXMueCkgLSBWQU5JTExBX0RFRkFVTFRfU1BBV05fUkFESVVTO1xuICAgICAgICBjb25zdCBtaW5aID0gQ29vcmRpbmF0ZVV0aWxzLmZyb21CbG9ja1RvQ2h1bmsodGhpcy56KSAtIFZBTklMTEFfREVGQVVMVF9TUEFXTl9SQURJVVM7XG4gICAgICAgIGNvbnN0IG1heFggPSBDb29yZGluYXRlVXRpbHMuZnJvbUJsb2NrVG9DaHVuayh0aGlzLngpICsgVkFOSUxMQV9ERUZBVUxUX1NQQVdOX1JBRElVUztcbiAgICAgICAgY29uc3QgbWF4WiA9IENvb3JkaW5hdGVVdGlscy5mcm9tQmxvY2tUb0NodW5rKHRoaXMueikgKyBWQU5JTExBX0RFRkFVTFRfU1BBV05fUkFESVVTO1xuXG4gICAgICAgIGNvbnN0IHNhdmVkQ2h1bmtzOiBDaHVua0Nvb3JkW10gPSBbXTtcbiAgICAgICAgY29uc3Qgc2VuZFF1ZXVlOiBBcnJheTxQcm9taXNlPENodW5rPj4gPSBbXTtcbiAgICAgICAgZm9yIChsZXQgY2h1bmtYID0gbWluWDsgY2h1bmtYIDw9IG1heFg7ICsrY2h1bmtYKSB7XG4gICAgICAgICAgICBmb3IgKGxldCBjaHVua1ogPSBtaW5aOyBjaHVua1ogPD0gbWF4WjsgKytjaHVua1opIHtcbiAgICAgICAgICAgICAgICAvLyBUT0RPOiB2YW5pbGxhIGRvZXMgbm90IHNlbmQgYWxsIG9mIHRoZW0sIGJ1dCBpbiBhIHJhbmdlXG4gICAgICAgICAgICAgICAgLy8gZm9yIGV4YW1wbGUgaXQgZG9lcyBzZW5kIHRoZW0gZnJvbSB4ID0+IFstMzsgM10gYW5kIHogPT4gWy0zOyAyXVxuICAgICAgICAgICAgICAgIHNhdmVkQ2h1bmtzLnB1c2goeyB4OiBjaHVua1gsIHo6IGNodW5rWiB9KTtcbiAgICAgICAgICAgICAgICBzZW5kUXVldWUucHVzaCh0aGlzLmdldFdvcmxkKCkuZ2V0Q2h1bmsoY2h1bmtYLCBjaHVua1opKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uc2VuZE5ldHdvcmtDaHVua1B1Ymxpc2hlcihWQU5JTExBX0RFRkFVTFRfU1BBV05fUkFESVVTLCBzYXZlZENodW5rcyk7XG5cbiAgICAgICAgY29uc3QgZ2V0VW5pcXVlQ2h1bmtzID0gKHNlbmRMaXN0OiBDaHVua0Nvb3JkW10pID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHhTZXQgPSBuZXcgU2V0PG51bWJlcj4oKTtcbiAgICAgICAgICAgIGNvbnN0IHpTZXQgPSBuZXcgU2V0PG51bWJlcj4oKTtcblxuICAgICAgICAgICAgZm9yIChjb25zdCBjb29yZCBvZiBzZW5kTGlzdCkge1xuICAgICAgICAgICAgICAgIHhTZXQuYWRkKGNvb3JkLngpO1xuICAgICAgICAgICAgICAgIHpTZXQuYWRkKGNvb3JkLnopO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gTWF0aC5mbG9vcigoeFNldC5zaXplICsgelNldC5zaXplKSAvIDIpO1xuICAgICAgICB9O1xuXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZ2V0VW5pcXVlQ2h1bmtzKHNhdmVkQ2h1bmtzKTsgKytpKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLm5ldHdvcmtTZXNzaW9uLnNlbmROZXR3b3JrQ2h1bmtQdWJsaXNoZXIoVkFOSUxMQV9ERUZBVUxUX1NQQVdOX1JBRElVUywgW10pO1xuICAgICAgICB9XG5cbiAgICAgICAgZm9yIGF3YWl0IChjb25zdCBjaHVuayBvZiBzZW5kUXVldWUpIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uc2VuZENodW5rKGNodW5rKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoYW5nZSB0aGUgcGxheWVyJ3MgY3VycmVudCB3b3JsZC5cbiAgICAgKiBAcGFyYW0ge1dvcmxkfSB3b3JsZCAtIHRoZSBuZXcgd29ybGRcbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgc2V0V29ybGQod29ybGQ6IFdvcmxkKSB7XG4gICAgICAgIGNvbnN0IGRpbTAgPSBuZXcgQ2hhbmdlRGltZW5zaW9uUGFja2V0KCk7XG4gICAgICAgIGRpbTAuZGltZW5zaW9uID0gMDtcbiAgICAgICAgZGltMC5wb3NpdGlvbiA9IHRoaXMuZ2V0UG9zaXRpb24oKTtcbiAgICAgICAgZGltMC5yZXNwYXduID0gZmFsc2U7XG5cbiAgICAgICAgY29uc3QgZGltMSA9IG5ldyBDaGFuZ2VEaW1lbnNpb25QYWNrZXQoKTtcbiAgICAgICAgZGltMS5kaW1lbnNpb24gPSAxO1xuICAgICAgICBkaW0xLnBvc2l0aW9uID0gdGhpcy5nZXRQb3NpdGlvbigpO1xuICAgICAgICBkaW0xLnJlc3Bhd24gPSBmYWxzZTtcblxuICAgICAgICBhd2FpdCB0aGlzLnNlbmREZXNwYXduKCk7XG4gICAgICAgIGF3YWl0IHRoaXMuZ2V0V29ybGQoKS5yZW1vdmVFbnRpdHkodGhpcyk7XG5cbiAgICAgICAgYXdhaXQgc3VwZXIuc2V0V29ybGQod29ybGQpO1xuICAgICAgICBhd2FpdCB3b3JsZC5hZGRFbnRpdHkodGhpcyk7XG5cbiAgICAgICAgYXdhaXQgdGhpcy5uZXR3b3JrU2Vzc2lvbi5zZW5kKGRpbTApO1xuICAgICAgICBhd2FpdCB0aGlzLm5ldHdvcmtTZXNzaW9uLnNlbmRQbGF5U3RhdHVzKFBsYXlTdGF0dXNUeXBlLlBsYXllclNwYXduKTtcbiAgICAgICAgYXdhaXQgdGhpcy5uZXR3b3JrU2Vzc2lvbi5zZW5kKGRpbTEpO1xuICAgICAgICBhd2FpdCB0aGlzLm5ldHdvcmtTZXNzaW9uLnNlbmRQbGF5U3RhdHVzKFBsYXlTdGF0dXNUeXBlLlBsYXllclNwYXduKTtcblxuICAgICAgICBhd2FpdCB0aGlzLnNlbmRJbml0aWFsU3Bhd25DaHVua3MoKTtcblxuICAgICAgICBhd2FpdCB0aGlzLm5ldHdvcmtTZXNzaW9uLnNlbmQoZGltMSk7XG4gICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uc2VuZFBsYXlTdGF0dXMoUGxheVN0YXR1c1R5cGUuUGxheWVyU3Bhd24pO1xuICAgICAgICBhd2FpdCB0aGlzLm5ldHdvcmtTZXNzaW9uLnNlbmQoZGltMCk7XG4gICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uc2VuZFBsYXlTdGF0dXMoUGxheVN0YXR1c1R5cGUuUGxheWVyU3Bhd24pO1xuXG4gICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uY2xlYXJDaHVua3MoKTtcbiAgICAgICAgYXdhaXQgdGhpcy5uZXR3b3JrU2Vzc2lvbi5uZWVkTmV3Q2h1bmtzKCk7XG4gICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uc2VuZFBsYXlTdGF0dXMoUGxheVN0YXR1c1R5cGUuUGxheWVyU3Bhd24pO1xuICAgIH1cblxuICAgIHB1YmxpYyBpc09ubGluZSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY29ubmVjdGVkO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyB1cGRhdGUodGljazogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHN1cGVyLnVwZGF0ZSh0aWNrKTtcbiAgICAgICAgYXdhaXQgdGhpcy5uZXR3b3JrU2Vzc2lvbi51cGRhdGUodGljayk7XG5cbiAgICAgICAgLy8gVE9ETzogZ2V0IGRvY3VtZW50YXRpb24gYWJvdXQgdGltaW5ncyBmcm9tIHZhbmlsbGFcbiAgICAgICAgLy8gMSBzZWNvbmQgLyAyMCA9IDEgdGljaywgMjAgKiA1ID0gMSBzZWNvbmRcbiAgICAgICAgLy8gMSBzZWNvbmQgKiA2MCA9IDEgbWludXRlXG4gICAgICAgIGlmICh0aWNrICUgKDIwICogNSAqIDYwICogMSkgPT09IDApIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uc2VuZFRpbWUodGljayk7XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKGNvbnN0IGNodW5rIG9mIHRoaXMuY2h1bmtTZW5kUXVldWUpIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uc2VuZE5ldHdvcmtDaHVua1B1Ymxpc2hlcih0aGlzLnZpZXdEaXN0YW5jZSB8fCBWQU5JTExBX0RFRkFVTFRfU1BBV05fUkFESVVTLCBbXSk7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLm5ldHdvcmtTZXNzaW9uLnNlbmRDaHVuayhjaHVuayk7XG4gICAgICAgICAgICB0aGlzLmNodW5rU2VuZFF1ZXVlLmRlbGV0ZShjaHVuayk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMga2ljayhyZWFzb24gPSAndW5rbm93biByZWFzb24nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuZGlzYWJsZSgpO1xuICAgICAgICBhd2FpdCB0aGlzLm5ldHdvcmtTZXNzaW9uLmtpY2socmVhc29uKTtcbiAgICAgICAgdGhpcy5zZXJ2ZXIuZ2V0TG9nZ2VyKCkudmVyYm9zZShgUGxheWVyIHdpdGggaWQgwqdiJHt0aGlzLmdldFJ1bnRpbWVJZCgpfcKnciB3YXMga2lja2VkOiAke3JlYXNvbn1gKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgc2VuZFNldHRpbmdzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLmdldE5ldHdvcmtTZXNzaW9uKCkuc2VuZEdhbWVtb2RlKCk7XG5cbiAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgICAgICB0aGlzLnNlcnZlclxuICAgICAgICAgICAgICAgIC5nZXRTZXNzaW9uTWFuYWdlcigpXG4gICAgICAgICAgICAgICAgLmdldEFsbFBsYXllcnMoKVxuICAgICAgICAgICAgICAgIC5tYXAoYXN5bmMgKHRhcmdldCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0YXJnZXQuZ2V0TmV0d29ya1Nlc3Npb24oKS5zZW5kQWJpbGl0aWVzKHRoaXMpO1xuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0YXJnZXQuZ2V0TmV0d29ya1Nlc3Npb24oKS5zZW5kU2V0dGluZ3ModGhpcyk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQbGF5ZXIgc3Bhd25pbmcgbG9naWMuXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIHNlbmRTcGF3bigpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5zZW5kUG9zaXRpb24oKTtcbiAgICAgICAgYXdhaXQgdGhpcy5zZXRHYW1lbW9kZSgpO1xuICAgICAgICBhd2FpdCB0aGlzLmdldE5ldHdvcmtTZXNzaW9uKCkuc2VuZEludmVudG9yeSgpO1xuICAgICAgICBhd2FpdCB0aGlzLnNlbmRTZXR0aW5ncygpO1xuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgc2VuZERlc3Bhd24oKSB7fVxuXG4gICAgLyoqXG4gICAgICogU2VuZCBhIGNoYXQgbWVzc2FnZSB0byB0aGUgY2xpZW50LlxuICAgICAqIEBwYXJhbSBtZXNzYWdlIC0gdGhlIG1lc3NhZ2VcbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgc2VuZE1lc3NhZ2UoXG4gICAgICAgIG1lc3NhZ2U6IHN0cmluZyxcbiAgICAgICAgdHlwZTogVGV4dFR5cGUgPSBUZXh0VHlwZS5SYXcsXG4gICAgICAgIHBhcmFtZXRlcnM6IHN0cmluZ1tdID0gW10sXG4gICAgICAgIG5lZWRzVHJhbnNsYXRpb24gPSBmYWxzZVxuICAgICk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICAvLyBUT0RPOiBEbyB0aGlzIHByb3Blcmx5IGxpa2UgamF2YSBlZGl0aW9uLFxuICAgICAgICAvLyBpbiBvdGhlciB3b3JkcywgdGhlIG1lc3NhZ2Ugc2hvdWxkIGJlIEpTT04gZm9ybWF0dGVkLlxuICAgICAgICBhd2FpdCB0aGlzLm5ldHdvcmtTZXNzaW9uLnNlbmRNZXNzYWdlKHtcbiAgICAgICAgICAgIG1lc3NhZ2UsXG4gICAgICAgICAgICBwYXJhbWV0ZXJzLFxuICAgICAgICAgICAgbmVlZHNUcmFuc2xhdGlvbixcbiAgICAgICAgICAgIHR5cGVcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHNldEdhbWVtb2RlKG1vZGU/OiBHYW1ldHlwZSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBtb2RlID8/PSB0aGlzLmdhbWVtb2RlO1xuXG4gICAgICAgIGNvbnN0IGV2ZW50ID0gbmV3IFBsYXllclNldEdhbWVtb2RlRXZlbnQodGhpcywgbW9kZSk7XG4gICAgICAgIHRoaXMuc2VydmVyLnBvc3QoWydwbGF5ZXJTZXRHYW1lbW9kZScsIGV2ZW50XSk7XG4gICAgICAgIGlmIChldmVudC5pc0NhbmNlbGxlZCgpKSByZXR1cm47XG5cbiAgICAgICAgdGhpcy5nYW1lbW9kZSA9IGV2ZW50LmdldEdhbWVtb2RlKCk7XG4gICAgICAgIGF3YWl0IHRoaXMubmV0d29ya1Nlc3Npb24uc2VuZEdhbWVtb2RlKCk7XG5cbiAgICAgICAgaWYgKHRoaXMuZ2FtZW1vZGUgPT09IEdhbWV0eXBlLkNSRUFUSVZFIHx8IHRoaXMuZ2FtZW1vZGUgPT09IEdhbWV0eXBlLlNQRUNUQVRPUikge1xuICAgICAgICAgICAgdGhpcy5tZXRhZGF0YS5zZXRDYW5GbHkodHJ1ZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLm1ldGFkYXRhLnNldENhbkZseShmYWxzZSk7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnNldEZseWluZyhmYWxzZSk7XG4gICAgICAgIH1cblxuICAgICAgICBhd2FpdCB0aGlzLnNlbmRTZXR0aW5ncygpO1xuICAgICAgICBhd2FpdCB0aGlzLm5ldHdvcmtTZXNzaW9uLnNlbmRHYW1lbW9kZSgpO1xuICAgICAgICBhd2FpdCB0aGlzLm5ldHdvcmtTZXNzaW9uLnNlbmRNZXRhZGF0YSgpO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXROZXR3b3JrU2Vzc2lvbigpOiBQbGF5ZXJTZXNzaW9uIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubmV0d29ya1Nlc3Npb247XG4gICAgfVxuXG4gICAgcHVibGljIGdldEFkZHJlc3MoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmFkZHJlc3M7XG4gICAgfVxuXG4gICAgcHVibGljIGdldE5hbWUoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubWV0YWRhdGEubmFtZVRhZztcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0Rm9ybWF0dGVkVXNlcm5hbWUoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIGA8JHt0aGlzLmdldE5hbWUoKX0+YDtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0UGVybWlzc2lvbnMoKTogc3RyaW5nW10ge1xuICAgICAgICByZXR1cm4gdGhpcy5wZXJtaXNzaW9ucztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgdGhlIFhVSUQgb2YgdGhlIHBsYXllci5cbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nIHwgbnVsbH0gWFVJRCBvZiB0aGUgcGxheWVyIG9yIG51bGwgaWYgbm90IGF2YWlsYWJsZVxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRYVUlEKCk6IHN0cmluZyB8IG51bGwge1xuICAgICAgICByZXR1cm4gdGhpcy54dWlkIHx8IG51bGw7XG4gICAgfVxuXG4gICAgcHVibGljIGlzUGxheWVyKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVjayBpZiB0aGUgYFBsYXllcmAgaXMgYW4gb3BlcmF0b3IuXG4gICAgICogQHJldHVybnMgYHRydWVgIGlmIHRoaXMgcGxheWVyIGlzIGFuIG9wZXJhdG9yIG90aGVyd2lzZSBgZmFsc2VgLlxuICAgICAqL1xuICAgIHB1YmxpYyBpc09wKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5zZXJ2ZXIuZ2V0UGVybWlzc2lvbk1hbmFnZXIoKS5pc09wKHRoaXMuZ2V0TmFtZSgpKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgc2V0U3ByaW50aW5nKHNwcmludGluZzogYm9vbGVhbikge1xuICAgICAgICBpZiAoc3ByaW50aW5nID09PSB0aGlzLm1ldGFkYXRhLnNwcmludGluZykgcmV0dXJuO1xuXG4gICAgICAgIGNvbnN0IGV2ZW50ID0gbmV3IFBsYXllclRvZ2dsZVNwcmludEV2ZW50KHRoaXMsIHNwcmludGluZyk7XG4gICAgICAgIHRoaXMuc2VydmVyLnBvc3QoWydwbGF5ZXJUb2dnbGVTcHJpbnQnLCBldmVudF0pO1xuICAgICAgICBpZiAoZXZlbnQuaXNDYW5jZWxsZWQoKSkgcmV0dXJuO1xuXG4gICAgICAgIHRoaXMubWV0YWRhdGEuc2V0U3ByaW50aW5nKGV2ZW50LmdldElzU3ByaW50aW5nKCkpO1xuICAgICAgICBhd2FpdCB0aGlzLm5ldHdvcmtTZXNzaW9uLnNlbmRNZXRhZGF0YSgpO1xuICAgIH1cblxuICAgIHB1YmxpYyBpc0ZseWluZygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmx5aW5nO1xuICAgIH1cbiAgICBwdWJsaWMgYXN5bmMgc2V0Rmx5aW5nKGZseWluZzogYm9vbGVhbikge1xuICAgICAgICBpZiAoZmx5aW5nID09PSB0aGlzLmlzRmx5aW5nKCkpIHJldHVybjtcblxuICAgICAgICBpZiAoIXRoaXMubWV0YWRhdGEuY2FuRmx5KSB7XG4gICAgICAgICAgICB0aGlzLmZseWluZyA9IGZhbHNlO1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5zZW5kU2V0dGluZ3MoKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGV2ZW50ID0gbmV3IFBsYXllclRvZ2dsZUZsaWdodEV2ZW50KHRoaXMsIGZseWluZyk7XG4gICAgICAgIHRoaXMuc2VydmVyLnBvc3QoWydwbGF5ZXJUb2dnbGVGbGlnaHQnLCBldmVudF0pO1xuICAgICAgICBpZiAoZXZlbnQuaXNDYW5jZWxsZWQoKSkgcmV0dXJuO1xuXG4gICAgICAgIHRoaXMuZmx5aW5nID0gZXZlbnQuZ2V0SXNGbHlpbmcoKTtcbiAgICAgICAgYXdhaXQgdGhpcy5zZW5kU2V0dGluZ3MoKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgaXNTbmVha2luZygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc25lYWtpbmc7XG4gICAgfVxuICAgIHB1YmxpYyBhc3luYyBzZXRTbmVha2luZyh2YWw6IGJvb2xlYW4pIHtcbiAgICAgICAgaWYgKHZhbCA9PT0gdGhpcy5zbmVha2luZykgcmV0dXJuO1xuICAgICAgICB0aGlzLnNuZWFraW5nID0gdmFsO1xuICAgIH1cblxuICAgIHB1YmxpYyBpc09uR3JvdW5kKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5vbkdyb3VuZDtcbiAgICB9XG4gICAgcHVibGljIGFzeW5jIHNldE9uR3JvdW5kKHZhbDogYm9vbGVhbikge1xuICAgICAgICBpZiAodmFsID09PSB0aGlzLm9uR3JvdW5kKSByZXR1cm47XG4gICAgICAgIHRoaXMub25Hcm91bmQgPSB2YWw7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0IHRoZSBwb3NpdGlvbi5cbiAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIHRvIHNldCB0aGUgcG9zaXRpb24uXG4gICAgICogQHBhcmFtIHtWZWN0b3IzfSBvcHRpb25zLnBvc2l0aW9uIC0gVGhlIG5ldyBwb3NpdGlvbi5cbiAgICAgKiBAcGFyYW0ge01vdmVtZW50VHlwZX0gW29wdGlvbnMudHlwZT1Nb3ZlbWVudFR5cGUuTm9ybWFsXSAtIFRoZSBtb3ZlbWVudCB0eXBlLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0aW9ucy5waXRjaD10aGlzLnBpdGNoXSAtIFRoZSBuZXcgcGl0Y2guXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IFtvcHRpb25zLnlhdz10aGlzLnlhd10gLSBUaGUgbmV3IHlhdy5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gW29wdGlvbnMuaGVhZFlhdz10aGlzLmhlYWRZYXddIC0gVGhlIG5ldyBoZWFkIHlhdy5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFticm9hZGNhc3Q9dHJ1ZV0gLSBXaGV0aGVyIHRvIGJyb2FkY2FzdCB0aGUgcG9zaXRpb24gY2hhbmdlLlxuICAgICAqIEByZW1hcmtzIFRoaXMgd2lsbCBub3RpZnkgdGhlIHBsYXllcidzIGNsaWVudCBhYm91dCB0aGUgcG9zaXRpb24gY2hhbmdlLlxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBzZXRQb3NpdGlvbihcbiAgICAgICAge1xuICAgICAgICAgICAgcG9zaXRpb24sXG4gICAgICAgICAgICB0eXBlID0gTW92ZW1lbnRUeXBlLk5vcm1hbCxcbiAgICAgICAgICAgIHBpdGNoID0gdGhpcy5waXRjaCxcbiAgICAgICAgICAgIHlhdyA9IHRoaXMueWF3LFxuICAgICAgICAgICAgaGVhZFlhdyA9IHRoaXMuaGVhZFlhd1xuICAgICAgICB9OiB7XG4gICAgICAgICAgICBwb3NpdGlvbjogVmVjdG9yMztcbiAgICAgICAgICAgIHR5cGU/OiBNb3ZlbWVudFR5cGU7XG4gICAgICAgICAgICBwaXRjaD86IG51bWJlcjtcbiAgICAgICAgICAgIHlhdz86IG51bWJlcjtcbiAgICAgICAgICAgIGhlYWRZYXc/OiBudW1iZXI7XG4gICAgICAgIH0sXG4gICAgICAgIGJyb2FkY2FzdCA9IHRydWVcbiAgICApIHtcbiAgICAgICAgYXdhaXQgc3VwZXIuc2V0UG9zaXRpb24oeyBwb3NpdGlvbiB9KTtcbiAgICAgICAgdGhpcy5waXRjaCA9IHBpdGNoO1xuICAgICAgICB0aGlzLnlhdyA9IHlhdztcbiAgICAgICAgdGhpcy5oZWFkWWF3ID0gaGVhZFlhdztcblxuICAgICAgICBpZiAoIWJyb2FkY2FzdCkgcmV0dXJuO1xuICAgICAgICBhd2FpdCB0aGlzLm5ldHdvcmtTZXNzaW9uLmJyb2FkY2FzdE1vdmUodGhpcywgdHlwZSk7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIFNlbmQgdGhlIHBvc2l0aW9uIHRvIGFsbCB0aGUgcGxheWVycyBpbiB0aGUgc2FtZSB3b3JsZC5cbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgcG9zaXRpb24gaXMgc2VudC5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgc2VuZFBvc2l0aW9uKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCBzdXBlci5zZW5kUG9zaXRpb24oKTtcbiAgICB9XG59XG4iXSwi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