UNPKG

@jsprismarine/prismarine

Version:

Dedicated Minecraft Bedrock Edition server written in TypeScript

307 lines (304 loc) • 30.7 kB
import fs from 'node:fs'; import { parseJSON5 } from 'confbox'; import { PlayerNotFoundError } from '@jsprismarine/errors'; import '@jsprismarine/jsbinaryutils'; import 'node:assert'; import { withCwd } from '../utils/cwd.es.js'; import '../block/BlockToolType.es.js'; import '@jsprismarine/bedrock-data'; import '@jsprismarine/nbt'; import 'zlib'; import '@jsprismarine/math'; import '@jsprismarine/minecraft'; import '../network/packet/AddActorPacket.es.js'; import '../network/packet/MoveActorAbsolutePacket.es.js'; import '../network/packet/RemoveActorPacket.es.js'; import 'node:crypto'; import '../network/packet/ActorFallPacket.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 '../network/CompressionProvider.es.js'; import '../network/packet/NetworkSettingsPacket.es.js'; import '../network/packet/BiomeDefinitionListPacket.es.js'; import '../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/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/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 'node:path'; import '@jsprismarine/brigadier'; import '../config/Config.es.js'; import playerToggleOperatorEvent from '../events/player/PlayerToggleOperatorEvent.es.js'; import '../network/handler/AnimateHandler.es.js'; import '../network/handler/CommandRequestHandler.es.js'; import '../network/handler/ContainerCloseHandler.es.js'; import '../network/handler/EmoteListHandler.es.js'; import '../network/handler/InteractHandler.es.js'; import '../network/handler/InventoryTransactionHandler.es.js'; import '../network/handler/LevelSoundEventHandler.es.js'; import '../network/handler/LoginHandler.es.js'; import '../network/handler/MobEquipmentHandler.es.js'; import '../network/handler/MovePlayerHandler.es.js'; import '../network/handler/PacketViolationWarningHandler.es.js'; import '../network/handler/PlayerActionHandler.es.js'; import '../network/handler/RequestChunkRadiusHandler.es.js'; import '../network/handler/RequestNetworkSettingsHandler.es.js'; import '../network/handler/ResourcePackResponseHandler.es.js'; import '../network/handler/ServerSettingsRequestHandler.es.js'; import '../network/handler/SetDefaultGametypeHandler.es.js'; import '../network/handler/SetLocalPlayerAsInitializedHandler.es.js'; import '../network/handler/SetPlayerGametypeHandler.es.js'; import '../network/handler/TextHandler.es.js'; import '../network/handler/TickSyncHandler.es.js'; import 'node:process'; import 'node:readline'; import 'heap'; import '../network/packet/UpdateAbilitiesPacket.es.js'; import '@jsprismarine/raknet'; import 'evt'; import 'assert'; const PERMISSION_FILE_NAME = "permissions.json"; const OPS_FILE_NAME = "ops.json"; class PermissionManager { server; ops = /* @__PURE__ */ new Set(); permissions = /* @__PURE__ */ new Map(); defaultPermissions = []; defaultOperatorPermissions = []; /** * Create a new permission manager. * @param {Server} server - The server instance. */ constructor(server) { this.server = server; } /** * Enable the manager and load all permissions. * @returns {Promise<void>} A promise that resolves when the manager is enabled. * @group Lifecycle */ async enable() { await this.parseOps(); await this.parsePermissions(); } /** * Signifies that the manager is being disabled and all permissions should be unloaded. * @returns {Promise<void>} A promise that resolves when the manager is disabled. * @group Lifecycle */ async disable() { this.ops.clear(); this.permissions.clear(); this.defaultPermissions = []; } /** * Get the default permissions. * @returns {string[]} The default permissions. */ getDefaultPermissions() { return this.defaultPermissions; } /** * Get a player's permissions. * @param {Player} player - The player to get permissions for. * @returns {Promise<string[]>} A promise that resolves with the player's permissions. */ async getPermissions(player) { return [ ...this.defaultPermissions, ...this.permissions.get(player.getName()) ?? [], ...player.isOp() ? this.defaultOperatorPermissions : [] ]; } /** * Set a player's permissions. * * @remarks * This will not be saved to the permissions.json file. * * @param {Player} player - The player to set permissions for. * @param {string[]} [permissions=[]] - The permissions to set. */ setPermissions(player, permissions = []) { this.permissions.set(player.getName(), permissions); } async parsePermissions() { try { if (!fs.existsSync(withCwd(PERMISSION_FILE_NAME))) { this.server.getLogger().warn(`Failed to load permissions list!`); fs.writeFileSync( // FIXME: This overwrites comments in the file. withCwd(PERMISSION_FILE_NAME), JSON.stringify( { defaultPermissions: [ "minecraft.command.help", "minecraft.command.list", "minecraft.command.me", "jsprismarine.command.plugins", "jsprismarine.command.version", "jsprismarine.command.tps" ], defaultOperatorPermissions: ["*"], players: [ { name: "filfat", permissions: ["*"] } ] }, null, 4 ) ); } const permissionsObject = parseJSON5((await fs.promises.readFile(withCwd(PERMISSION_FILE_NAME))).toString()); this.defaultPermissions = permissionsObject.defaultPermissions || []; this.defaultOperatorPermissions = permissionsObject.defaultOperatorPermissions || ["*"]; permissionsObject.players?.map( (player) => this.permissions.set(player.name, player.permissions.length <= 0 ? [] : player.permissions) ); } catch (error) { this.server.getLogger().error(error); throw new Error(`Invalid ${PERMISSION_FILE_NAME} file.`); } } async parseOps() { try { if (!fs.existsSync(withCwd(OPS_FILE_NAME))) { this.server.getLogger().warn(`Failed to load operators list!`); fs.writeFileSync(withCwd(OPS_FILE_NAME), "[]"); } const ops = parseJSON5((await fs.promises.readFile(withCwd(OPS_FILE_NAME))).toString()); ops.map((op) => this.ops.add(op.name)); } catch (error) { this.server.getLogger().error(error); throw new Error(`Invalid ${OPS_FILE_NAME} file.`); } } /** * Set a player as an operator. * * @param {string} username - The player to set as an operator. * @param {boolean} op - Whether the player should be an operator. * @returns {Promise<boolean>} A promise that resolves with a boolean indicating whether the operation was successful. */ async setOp(username, op) { const target = this.server.getSessionManager().getPlayerByExactName(username); if (!target) throw new PlayerNotFoundError(username); const event = new playerToggleOperatorEvent(target, op); this.server.post(["playerToggleOperator", event]); if (event.isCancelled()) return false; await target.getNetworkSession().sendAvailableCommands(); if (op) this.ops.add(username); else this.ops.delete(username); try { await fs.promises.writeFile( // FIXME: This overwrites comments in the file. withCwd(OPS_FILE_NAME), JSON.stringify( Array.from(this.ops.values()).map((name) => ({ name, level: 4 })), null, 4 ) ); await target.sendSettings(); return true; } catch { return false; } } /** * Check if a player is an operator. * * @param {string} username - The player to check. * @returns {boolean} Whether the player is an operator. */ isOp(username) { return this.ops.has(username); } /** * Check if a player can execute a command. * * @param {Player} executer - The player to check. * @returns {object} An object with an execute method that takes a permission string and returns whether the player can execute the command. */ can(executer) { const execute = (permission) => { if (!executer) throw new Error(`Executer can't be undefined or null`); if (!permission) return true; if (executer.isConsole()) return true; if (executer.isOp()) return true; if (executer.getPermissions().includes(permission)) return true; if (executer.getPermissions().includes("*")) return true; const split = permission.split("."); let scope = ""; for (const action of split) { if (scope) scope = `${scope}.${action}`; else scope = action; if (executer.getPermissions().includes(scope)) return true; if (executer.getPermissions().includes(`${scope}.*`)) return true; } return false; }; return { execute, not: () => { return { execute: (permission) => !execute(permission) }; } }; } } export { PermissionManager }; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGVybWlzc2lvbk1hbmFnZXIuZXMuanMiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wZXJtaXNzaW9uL1Blcm1pc3Npb25NYW5hZ2VyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBmcyBmcm9tICdub2RlOmZzJztcblxuaW1wb3J0IHsgcGFyc2VKU09ONSB9IGZyb20gJ2NvbmZib3gnO1xuXG5pbXBvcnQgeyBQbGF5ZXJOb3RGb3VuZEVycm9yIH0gZnJvbSAnQGpzcHJpc21hcmluZS9lcnJvcnMnO1xuaW1wb3J0IHR5cGUgeyBQbGF5ZXIsIFNlcnZlciwgU2VydmljZSB9IGZyb20gJy4uLyc7XG5pbXBvcnQgeyB3aXRoQ3dkIH0gZnJvbSAnLi4vJztcbmltcG9ydCBwbGF5ZXJUb2dnbGVPcGVyYXRvckV2ZW50IGZyb20gJy4uL2V2ZW50cy9wbGF5ZXIvUGxheWVyVG9nZ2xlT3BlcmF0b3JFdmVudCc7XG5cbmludGVyZmFjZSBPcFR5cGUge1xuICAgIG5hbWU6IHN0cmluZztcbn1cblxuY29uc3QgUEVSTUlTU0lPTl9GSUxFX05BTUUgPSAncGVybWlzc2lvbnMuanNvbic7XG5jb25zdCBPUFNfRklMRV9OQU1FID0gJ29wcy5qc29uJztcblxuLyoqXG4gKiBQZXJtaXNzaW9uIG1hbmFnZXIuXG4gKi9cbmV4cG9ydCBjbGFzcyBQZXJtaXNzaW9uTWFuYWdlciBpbXBsZW1lbnRzIFNlcnZpY2Uge1xuICAgIHByaXZhdGUgcmVhZG9ubHkgc2VydmVyOiBTZXJ2ZXI7XG4gICAgcHJpdmF0ZSByZWFkb25seSBvcHM6IFNldDxzdHJpbmc+ID0gbmV3IFNldCgpO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgcGVybWlzc2lvbnM6IE1hcDxzdHJpbmcsIHN0cmluZ1tdPiA9IG5ldyBNYXAoKTtcbiAgICBwcml2YXRlIGRlZmF1bHRQZXJtaXNzaW9uczogc3RyaW5nW10gPSBbXTtcbiAgICBwcml2YXRlIGRlZmF1bHRPcGVyYXRvclBlcm1pc3Npb25zOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGEgbmV3IHBlcm1pc3Npb24gbWFuYWdlci5cbiAgICAgKiBAcGFyYW0ge1NlcnZlcn0gc2VydmVyIC0gVGhlIHNlcnZlciBpbnN0YW5jZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgY29uc3RydWN0b3Ioc2VydmVyOiBTZXJ2ZXIpIHtcbiAgICAgICAgdGhpcy5zZXJ2ZXIgPSBzZXJ2ZXI7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRW5hYmxlIHRoZSBtYW5hZ2VyIGFuZCBsb2FkIGFsbCBwZXJtaXNzaW9ucy5cbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgbWFuYWdlciBpcyBlbmFibGVkLlxuICAgICAqIEBncm91cCBMaWZlY3ljbGVcbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgZW5hYmxlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLnBhcnNlT3BzKCk7XG4gICAgICAgIGF3YWl0IHRoaXMucGFyc2VQZXJtaXNzaW9ucygpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNpZ25pZmllcyB0aGF0IHRoZSBtYW5hZ2VyIGlzIGJlaW5nIGRpc2FibGVkIGFuZCBhbGwgcGVybWlzc2lvbnMgc2hvdWxkIGJlIHVubG9hZGVkLlxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBtYW5hZ2VyIGlzIGRpc2FibGVkLlxuICAgICAqIEBncm91cCBMaWZlY3ljbGVcbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgZGlzYWJsZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdGhpcy5vcHMuY2xlYXIoKTtcbiAgICAgICAgdGhpcy5wZXJtaXNzaW9ucy5jbGVhcigpO1xuICAgICAgICB0aGlzLmRlZmF1bHRQZXJtaXNzaW9ucyA9IFtdO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCB0aGUgZGVmYXVsdCBwZXJtaXNzaW9ucy5cbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nW119IFRoZSBkZWZhdWx0IHBlcm1pc3Npb25zLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXREZWZhdWx0UGVybWlzc2lvbnMoKTogc3RyaW5nW10ge1xuICAgICAgICByZXR1cm4gdGhpcy5kZWZhdWx0UGVybWlzc2lvbnM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGEgcGxheWVyJ3MgcGVybWlzc2lvbnMuXG4gICAgICogQHBhcmFtIHtQbGF5ZXJ9IHBsYXllciAtIFRoZSBwbGF5ZXIgdG8gZ2V0IHBlcm1pc3Npb25zIGZvci5cbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmdbXT59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIHBsYXllcidzIHBlcm1pc3Npb25zLlxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBnZXRQZXJtaXNzaW9ucyhwbGF5ZXI6IFBsYXllcik6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIC4uLnRoaXMuZGVmYXVsdFBlcm1pc3Npb25zLFxuICAgICAgICAgICAgLi4uKHRoaXMucGVybWlzc2lvbnMuZ2V0KHBsYXllci5nZXROYW1lKCkpID8/IFtdKSxcbiAgICAgICAgICAgIC4uLihwbGF5ZXIuaXNPcCgpID8gdGhpcy5kZWZhdWx0T3BlcmF0b3JQZXJtaXNzaW9ucyA6IFtdKVxuICAgICAgICBdO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCBhIHBsYXllcidzIHBlcm1pc3Npb25zLlxuICAgICAqXG4gICAgICogQHJlbWFya3NcbiAgICAgKiBUaGlzIHdpbGwgbm90IGJlIHNhdmVkIHRvIHRoZSBwZXJtaXNzaW9ucy5qc29uIGZpbGUuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1BsYXllcn0gcGxheWVyIC0gVGhlIHBsYXllciB0byBzZXQgcGVybWlzc2lvbnMgZm9yLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nW119IFtwZXJtaXNzaW9ucz1bXV0gLSBUaGUgcGVybWlzc2lvbnMgdG8gc2V0LlxuICAgICAqL1xuICAgIHB1YmxpYyBzZXRQZXJtaXNzaW9ucyhwbGF5ZXI6IFBsYXllciwgcGVybWlzc2lvbnM6IHN0cmluZ1tdID0gW10pIHtcbiAgICAgICAgdGhpcy5wZXJtaXNzaW9ucy5zZXQocGxheWVyLmdldE5hbWUoKSwgcGVybWlzc2lvbnMpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgcGFyc2VQZXJtaXNzaW9ucygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGlmICghZnMuZXhpc3RzU3luYyh3aXRoQ3dkKFBFUk1JU1NJT05fRklMRV9OQU1FKSkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNlcnZlci5nZXRMb2dnZXIoKS53YXJuKGBGYWlsZWQgdG8gbG9hZCBwZXJtaXNzaW9ucyBsaXN0IWApO1xuICAgICAgICAgICAgICAgIGZzLndyaXRlRmlsZVN5bmMoXG4gICAgICAgICAgICAgICAgICAgIC8vIEZJWE1FOiBUaGlzIG92ZXJ3cml0ZXMgY29tbWVudHMgaW4gdGhlIGZpbGUuXG4gICAgICAgICAgICAgICAgICAgIHdpdGhDd2QoUEVSTUlTU0lPTl9GSUxFX05BTUUpLFxuICAgICAgICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWZhdWx0UGVybWlzc2lvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ21pbmVjcmFmdC5jb21tYW5kLmhlbHAnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnbWluZWNyYWZ0LmNvbW1hbmQubGlzdCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdtaW5lY3JhZnQuY29tbWFuZC5tZScsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdqc3ByaXNtYXJpbmUuY29tbWFuZC5wbHVnaW5zJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2pzcHJpc21hcmluZS5jb21tYW5kLnZlcnNpb24nLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnanNwcmlzbWFyaW5lLmNvbW1hbmQudHBzJ1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmYXVsdE9wZXJhdG9yUGVybWlzc2lvbnM6IFsnKiddLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsYXllcnM6IFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZTogJ2ZpbGZhdCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZXJtaXNzaW9uczogWycqJ11cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgICAgICAgICAgICAgNFxuICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgcGVybWlzc2lvbnNPYmplY3Q6IFBhcnRpYWw8e1xuICAgICAgICAgICAgICAgIGRlZmF1bHRQZXJtaXNzaW9uczogc3RyaW5nW107XG4gICAgICAgICAgICAgICAgZGVmYXVsdE9wZXJhdG9yUGVybWlzc2lvbnM6IHN0cmluZ1tdO1xuICAgICAgICAgICAgICAgIHBsYXllcnM6IEFycmF5PHtcbiAgICAgICAgICAgICAgICAgICAgbmFtZTogc3RyaW5nO1xuICAgICAgICAgICAgICAgICAgICBwZXJtaXNzaW9uczogc3RyaW5nW107XG4gICAgICAgICAgICAgICAgfT47XG4gICAgICAgICAgICB9PiA9IHBhcnNlSlNPTjUoKGF3YWl0IGZzLnByb21pc2VzLnJlYWRGaWxlKHdpdGhDd2QoUEVSTUlTU0lPTl9GSUxFX05BTUUpKSkudG9TdHJpbmcoKSk7XG5cbiAgICAgICAgICAgIHRoaXMuZGVmYXVsdFBlcm1pc3Npb25zID0gcGVybWlzc2lvbnNPYmplY3QuZGVmYXVsdFBlcm1pc3Npb25zIHx8IFtdO1xuICAgICAgICAgICAgdGhpcy5kZWZhdWx0T3BlcmF0b3JQZXJtaXNzaW9ucyA9IHBlcm1pc3Npb25zT2JqZWN0LmRlZmF1bHRPcGVyYXRvclBlcm1pc3Npb25zIHx8IFsnKiddO1xuICAgICAgICAgICAgcGVybWlzc2lvbnNPYmplY3QucGxheWVycz8ubWFwKChwbGF5ZXIpID0+XG4gICAgICAgICAgICAgICAgdGhpcy5wZXJtaXNzaW9ucy5zZXQocGxheWVyLm5hbWUsIHBsYXllci5wZXJtaXNzaW9ucy5sZW5ndGggPD0gMCA/IFtdIDogcGxheWVyLnBlcm1pc3Npb25zKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICAgICAgICAgIHRoaXMuc2VydmVyLmdldExvZ2dlcigpLmVycm9yKGVycm9yKTtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCAke1BFUk1JU1NJT05fRklMRV9OQU1FfSBmaWxlLmApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBwYXJzZU9wcygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGlmICghZnMuZXhpc3RzU3luYyh3aXRoQ3dkKE9QU19GSUxFX05BTUUpKSkge1xuICAgICAgICAgICAgICAgIHRoaXMuc2VydmVyLmdldExvZ2dlcigpLndhcm4oYEZhaWxlZCB0byBsb2FkIG9wZXJhdG9ycyBsaXN0IWApO1xuICAgICAgICAgICAgICAgIGZzLndyaXRlRmlsZVN5bmMod2l0aEN3ZChPUFNfRklMRV9OQU1FKSwgJ1tdJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBvcHM6IE9wVHlwZVtdID0gcGFyc2VKU09ONSgoYXdhaXQgZnMucHJvbWlzZXMucmVhZEZpbGUod2l0aEN3ZChPUFNfRklMRV9OQU1FKSkpLnRvU3RyaW5nKCkpO1xuXG4gICAgICAgICAgICBvcHMubWFwKChvcCkgPT4gdGhpcy5vcHMuYWRkKG9wLm5hbWUpKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICAgICAgICAgIHRoaXMuc2VydmVyLmdldExvZ2dlcigpLmVycm9yKGVycm9yKTtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCAke09QU19GSUxFX05BTUV9IGZpbGUuYCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXQgYSBwbGF5ZXIgYXMgYW4gb3BlcmF0b3IuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdXNlcm5hbWUgLSBUaGUgcGxheWVyIHRvIHNldCBhcyBhbiBvcGVyYXRvci5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IG9wIC0gV2hldGhlciB0aGUgcGxheWVyIHNob3VsZCBiZSBhbiBvcGVyYXRvci5cbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCBhIGJvb2xlYW4gaW5kaWNhdGluZyB3aGV0aGVyIHRoZSBvcGVyYXRpb24gd2FzIHN1Y2Nlc3NmdWwuXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIHNldE9wKHVzZXJuYW1lOiBzdHJpbmcsIG9wOiBib29sZWFuKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIGNvbnN0IHRhcmdldCA9IHRoaXMuc2VydmVyLmdldFNlc3Npb25NYW5hZ2VyKCkuZ2V0UGxheWVyQnlFeGFjdE5hbWUodXNlcm5hbWUpOyAvLyBUT0RPOiBieSBuYW1lIG5vdCBleGFjdFxuICAgICAgICBpZiAoIXRhcmdldCkgdGhyb3cgbmV3IFBsYXllck5vdEZvdW5kRXJyb3IodXNlcm5hbWUpO1xuICAgICAgICBjb25zdCBldmVudCA9IG5ldyBwbGF5ZXJUb2dnbGVPcGVyYXRvckV2ZW50KHRhcmdldCwgb3ApO1xuICAgICAgICB0aGlzLnNlcnZlci5wb3N0KFsncGxheWVyVG9nZ2xlT3BlcmF0b3InLCBldmVudF0pO1xuICAgICAgICBpZiAoZXZlbnQuaXNDYW5jZWxsZWQoKSkgcmV0dXJuIGZhbHNlO1xuXG4gICAgICAgIGF3YWl0IHRhcmdldC5nZXROZXR3b3JrU2Vzc2lvbigpLnNlbmRBdmFpbGFibGVDb21tYW5kcygpO1xuXG4gICAgICAgIGlmIChvcCkgdGhpcy5vcHMuYWRkKHVzZXJuYW1lKTtcbiAgICAgICAgZWxzZSB0aGlzLm9wcy5kZWxldGUodXNlcm5hbWUpO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBmcy5wcm9taXNlcy53cml0ZUZpbGUoXG4gICAgICAgICAgICAgICAgLy8gRklYTUU6IFRoaXMgb3ZlcndyaXRlcyBjb21tZW50cyBpbiB0aGUgZmlsZS5cbiAgICAgICAgICAgICAgICB3aXRoQ3dkKE9QU19GSUxFX05BTUUpLFxuICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KFxuICAgICAgICAgICAgICAgICAgICBBcnJheS5mcm9tKHRoaXMub3BzLnZhbHVlcygpKS5tYXAoKG5hbWUpID0+ICh7XG4gICAgICAgICAgICAgICAgICAgICAgICBuYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWw6IDRcbiAgICAgICAgICAgICAgICAgICAgfSkpLFxuICAgICAgICAgICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgICAgICAgICA0XG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgYXdhaXQgdGFyZ2V0LnNlbmRTZXR0aW5ncygpO1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2sgaWYgYSBwbGF5ZXIgaXMgYW4gb3BlcmF0b3IuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdXNlcm5hbWUgLSBUaGUgcGxheWVyIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSBXaGV0aGVyIHRoZSBwbGF5ZXIgaXMgYW4gb3BlcmF0b3IuXG4gICAgICovXG4gICAgcHVibGljIGlzT3AodXNlcm5hbWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5vcHMuaGFzKHVzZXJuYW1lKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVjayBpZiBhIHBsYXllciBjYW4gZXhlY3V0ZSBhIGNvbW1hbmQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1BsYXllcn0gZXhlY3V0ZXIgLSBUaGUgcGxheWVyIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtvYmplY3R9IEFuIG9iamVjdCB3aXRoIGFuIGV4ZWN1dGUgbWV0aG9kIHRoYXQgdGFrZXMgYSBwZXJtaXNzaW9uIHN0cmluZyBhbmQgcmV0dXJucyB3aGV0aGVyIHRoZSBwbGF5ZXIgY2FuIGV4ZWN1dGUgdGhlIGNvbW1hbmQuXG4gICAgICovXG4gICAgcHVibGljIGNhbihleGVjdXRlcj86IFBsYXllcikge1xuICAgICAgICBjb25zdCBleGVjdXRlID0gKHBlcm1pc3Npb24/OiBzdHJpbmcpID0+IHtcbiAgICAgICAgICAgIGlmICghZXhlY3V0ZXIpIHRocm93IG5ldyBFcnJvcihgRXhlY3V0ZXIgY2FuJ3QgYmUgdW5kZWZpbmVkIG9yIG51bGxgKTtcblxuICAgICAgICAgICAgaWYgKCFwZXJtaXNzaW9uKSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIGlmIChleGVjdXRlci5pc0NvbnNvbGUoKSkgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICBpZiAoZXhlY3V0ZXIuaXNPcCgpKSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIGlmIChleGVjdXRlci5nZXRQZXJtaXNzaW9ucygpLmluY2x1ZGVzKHBlcm1pc3Npb24pKSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIGlmIChleGVjdXRlci5nZXRQZXJtaXNzaW9ucygpLmluY2x1ZGVzKCcqJykpIHJldHVybiB0cnVlO1xuXG4gICAgICAgICAgICBjb25zdCBzcGxpdCA9IHBlcm1pc3Npb24uc3BsaXQoJy4nKTtcbiAgICAgICAgICAgIGxldCBzY29wZSA9ICcnO1xuICAgICAgICAgICAgZm9yIChjb25zdCBhY3Rpb24gb2Ygc3BsaXQpIHtcbiAgICAgICAgICAgICAgICBpZiAoc2NvcGUpIHNjb3BlID0gYCR7c2NvcGV9LiR7YWN0aW9ufWA7XG4gICAgICAgICAgICAgICAgZWxzZSBzY29wZSA9IGFjdGlvbjtcblxuICAgICAgICAgICAgICAgIGlmIChleGVjdXRlci5nZXRQZXJtaXNzaW9ucygpLmluY2x1ZGVzKHNjb3BlKSkgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgaWYgKGV4ZWN1dGVyLmdldFBlcm1pc3Npb25zKCkuaW5jbHVkZXMoYCR7c2NvcGV9LipgKSkgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgZXhlY3V0ZSxcbiAgICAgICAgICAgIG5vdDogKCkgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgIGV4ZWN1dGU6IChwZXJtaXNzaW9uPzogc3RyaW5nKSA9PiAhZXhlY3V0ZShwZXJtaXNzaW9uKVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgfVxufVxuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFhQSxNQUFNLG9CQUF1QixHQUFBLGtCQUFBO0FBQzdCLE1BQU0sYUFBZ0IsR0FBQSxVQUFBO0FBS2YsTUFBTSxpQkFBcUMsQ0FBQTtBQUFBLEVBQzdCLE1BQUE7QUFBQSxFQUNBLEdBQUEsdUJBQXVCLEdBQUksRUFBQTtBQUFBLEVBQzNCLFdBQUEsdUJBQXlDLEdBQUksRUFBQTtBQUFBLEVBQ3RELHFCQUErQixFQUFDO0FBQUEsRUFDaEMsNkJBQXVDLEVBQUM7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLEVBTXpDLFlBQVksTUFBZ0IsRUFBQTtBQUMvQixJQUFBLElBQUEsQ0FBSyxNQUFTLEdBQUEsTUFBQTtBQUFBO0FBQ2xCO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxFQU9BLE1BQWEsTUFBd0IsR0FBQTtBQUNqQyxJQUFBLE1BQU0sS0FBSyxRQUFTLEVBQUE7QUFDcEIsSUFBQSxNQUFNLEtBQUssZ0JBQWlCLEVBQUE7QUFBQTtBQUNoQztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsRUFPQSxNQUFhLE9BQXlCLEdBQUE7QUFDbEMsSUFBQSxJQUFBLENBQUssSUFBSSxLQUFNLEVBQUE7QUFDZixJQUFBLElBQUEsQ0FBSyxZQUFZLEtBQU0sRUFBQTtBQUN2QixJQUFBLElBQUEsQ0FBSyxxQkFBcUIsRUFBQztBQUFBO0FBQy9CO0FBQUE7QUFBQTtBQUFBO0FBQUEsRUFNTyxxQkFBa0MsR0FBQTtBQUNyQyxJQUFBLE9BQU8sSUFBSyxDQUFBLGtCQUFBO0FBQUE7QUFDaEI7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLEVBT0EsTUFBYSxlQUFlLE1BQW1DLEVBQUE7QUFDM0QsSUFBTyxPQUFBO0FBQUEsTUFDSCxHQUFHLElBQUssQ0FBQSxrQkFBQTtBQUFBLE1BQ1IsR0FBSSxLQUFLLFdBQVksQ0FBQSxHQUFBLENBQUksT0FBTyxPQUFRLEVBQUMsS0FBSyxFQUFDO0FBQUEsTUFDL0MsR0FBSSxNQUFPLENBQUEsSUFBQSxFQUFTLEdBQUEsSUFBQSxDQUFLLDZCQUE2QjtBQUFDLEtBQzNEO0FBQUE7QUFDSjtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxFQVdPLGNBQWUsQ0FBQSxNQUFBLEVBQWdCLFdBQXdCLEdBQUEsRUFBSSxFQUFBO0FBQzlELElBQUEsSUFBQSxDQUFLLFdBQVksQ0FBQSxHQUFBLENBQUksTUFBTyxDQUFBLE9BQUEsSUFBVyxXQUFXLENBQUE7QUFBQTtBQUN0RCxFQUVBLE1BQWMsZ0JBQWtDLEdBQUE7QUFDNUMsSUFBSSxJQUFBO0FBQ0EsTUFBQSxJQUFJLENBQUMsRUFBRyxDQUFBLFVBQUEsQ0FBVyxPQUFRLENBQUEsb0JBQW9CLENBQUMsQ0FBRyxFQUFBO0FBQy9DLFFBQUEsSUFBQSxDQUFLLE1BQU8sQ0FBQSxTQUFBLEVBQVksQ0FBQSxJQUFBLENBQUssQ0FBa0MsZ0NBQUEsQ0FBQSxDQUFBO0FBQy9ELFFBQUcsRUFBQSxDQUFBLGFBQUE7QUFBQTtBQUFBLFVBRUMsUUFBUSxvQkFBb0IsQ0FBQTtBQUFBLFVBQzVCLElBQUssQ0FBQSxTQUFBO0FBQUEsWUFDRDtBQUFBLGNBQ0ksa0JBQW9CLEVBQUE7QUFBQSxnQkFDaEIsd0JBQUE7QUFBQSxnQkFDQSx3QkFBQTtBQUFBLGdCQUNBLHNCQUFBO0FBQUEsZ0JBQ0EsOEJBQUE7QUFBQSxnQkFDQSw4QkFBQTtBQUFBLGdCQUNBO0FBQUEsZUFDSjtBQUFBLGNBQ0EsMEJBQUEsRUFBNEIsQ0FBQyxHQUFHLENBQUE7QUFBQSxjQUNoQyxPQUFTLEVBQUE7QUFBQSxnQkFDTDtBQUFBLGtCQUNJLElBQU0sRUFBQSxRQUFBO0FBQUEsa0JBQ04sV0FBQSxFQUFhLENBQUMsR0FBRztBQUFBO0FBQ3JCO0FBQ0osYUFDSjtBQUFBLFlBQ0EsSUFBQTtBQUFBLFlBQ0E7QUFBQTtBQUNKLFNBQ0o7QUFBQTtBQUdKLE1BQU0sTUFBQSxpQkFBQSxHQU9ELFVBQVksQ0FBQSxDQUFBLE1BQU0sRUFBRyxDQUFBLFFBQUEsQ0FBUyxRQUFTLENBQUEsT0FBQSxDQUFRLG9CQUFvQixDQUFDLENBQUcsRUFBQSxRQUFBLEVBQVUsQ0FBQTtBQUV0RixNQUFLLElBQUEsQ0FBQSxrQkFBQSxHQUFxQixpQkFBa0IsQ0FBQSxrQkFBQSxJQUFzQixFQUFDO0FBQ25FLE1BQUEsSUFBQSxDQUFLLDBCQUE2QixHQUFBLGlCQUFBLENBQWtCLDBCQUE4QixJQUFBLENBQUMsR0FBRyxDQUFBO0FBQ3RGLE1BQUEsaUJBQUEsQ0FBa0IsT0FBUyxFQUFBLEdBQUE7QUFBQSxRQUFJLENBQUMsTUFBQSxLQUM1QixJQUFLLENBQUEsV0FBQSxDQUFZLElBQUksTUFBTyxDQUFBLElBQUEsRUFBTSxNQUFPLENBQUEsV0FBQSxDQUFZLE1BQVUsSUFBQSxDQUFBLEdBQUksRUFBQyxHQUFJLE9BQU8sV0FBVztBQUFBLE9BQzlGO0FBQUEsYUFDSyxLQUFnQixFQUFBO0FBQ3JCLE1BQUEsSUFBQSxDQUFLLE1BQU8sQ0FBQSxTQUFBLEVBQVksQ0FBQSxLQUFBLENBQU0sS0FBSyxDQUFBO0FBQ25DLE1BQUEsTUFBTSxJQUFJLEtBQUEsQ0FBTSxDQUFXLFFBQUEsRUFBQSxvQkFBb0IsQ0FBUSxNQUFBLENBQUEsQ0FBQTtBQUFBO0FBQzNEO0FBQ0osRUFFQSxNQUFjLFFBQTBCLEdBQUE7QUFDcEMsSUFBSSxJQUFBO0FBQ0EsTUFBQSxJQUFJLENBQUMsRUFBRyxDQUFBLFVBQUEsQ0FBVyxPQUFRLENBQUEsYUFBYSxDQUFDLENBQUcsRUFBQTtBQUN4QyxRQUFBLElBQUEsQ0FBSyxNQUFPLENBQUEsU0FBQSxFQUFZLENBQUEsSUFBQSxDQUFLLENBQWdDLDhCQUFBLENBQUEsQ0FBQTtBQUM3RCxRQUFBLEVBQUEsQ0FBRyxhQUFjLENBQUEsT0FBQSxDQUFRLGFBQWEsQ0FBQSxFQUFHLElBQUksQ0FBQTtBQUFBO0FBRWpELE1BQU0sTUFBQSxHQUFBLEdBQWdCLFVBQVksQ0FBQSxDQUFBLE1BQU0sRUFBRyxDQUFBLFFBQUEsQ0FBUyxRQUFTLENBQUEsT0FBQSxDQUFRLGFBQWEsQ0FBQyxDQUFHLEVBQUEsUUFBQSxFQUFVLENBQUE7QUFFaEcsTUFBSSxHQUFBLENBQUEsR0FBQSxDQUFJLENBQUMsRUFBTyxLQUFBLElBQUEsQ0FBSyxJQUFJLEdBQUksQ0FBQSxFQUFBLENBQUcsSUFBSSxDQUFDLENBQUE7QUFBQSxhQUNoQyxLQUFnQixFQUFBO0FBQ3JCLE1BQUEsSUFBQSxDQUFLLE1BQU8sQ0FBQSxTQUFBLEVBQVksQ0FBQSxLQUFBLENBQU0sS0FBSyxDQUFBO0FBQ25DLE1BQUEsTUFBTSxJQUFJLEtBQUEsQ0FBTSxDQUFXLFFBQUEsRUFBQSxhQUFhLENBQVEsTUFBQSxDQUFBLENBQUE7QUFBQTtBQUNwRDtBQUNKO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsRUFTQSxNQUFhLEtBQU0sQ0FBQSxRQUFBLEVBQWtCLEVBQStCLEVBQUE7QUFDaEUsSUFBQSxNQUFNLFNBQVMsSUFBSyxDQUFBLE1BQUEsQ0FBTyxpQkFBa0IsRUFBQSxDQUFFLHFCQUFxQixRQUFRLENBQUE7QUFDNUUsSUFBQSxJQUFJLENBQUMsTUFBQSxFQUFjLE1BQUEsSUFBSSxvQkFBb0IsUUFBUSxDQUFBO0FBQ25ELElBQUEsTUFBTSxLQUFRLEdBQUEsSUFBSSx5QkFBMEIsQ0FBQSxNQUFBLEVBQVEsRUFBRSxDQUFBO0FBQ3RELElBQUEsSUFBQSxDQUFLLE1BQU8sQ0FBQSxJQUFBLENBQUssQ0FBQyxzQkFBQSxFQUF3QixLQUFLLENBQUMsQ0FBQTtBQUNoRCxJQUFJLElBQUEsS0FBQSxDQUFNLFdBQVksRUFBQSxFQUFVLE9BQUEsS0FBQTtBQUVoQyxJQUFNLE1BQUEsTUFBQSxDQUFPLGlCQUFrQixFQUFBLENBQUUscUJBQXNCLEVBQUE7QUFFdkQsSUFBQSxJQUFJLEVBQUksRUFBQSxJQUFBLENBQUssR0FBSSxDQUFBLEdBQUEsQ0FBSSxRQUFRLENBQUE7QUFBQSxTQUN4QixJQUFBLENBQUssR0FBSSxDQUFBLE1BQUEsQ0FBTyxRQUFRLENBQUE7QUFFN0IsSUFBSSxJQUFBO0FBQ0EsTUFBQSxNQUFNLEdBQUcsUUFBUyxDQUFBLFNBQUE7QUFBQTtBQUFBLFFBRWQsUUFBUSxhQUFhLENBQUE7QUFBQSxRQUNyQixJQUFLLENBQUEsU0FBQTtBQUFBLFVBQ0QsS0FBQSxDQUFNLEtBQUssSUFBSyxDQUFBLEdBQUEsQ0FBSSxRQUFRLENBQUEsQ0FBRSxHQUFJLENBQUEsQ0FBQyxJQUFVLE1BQUE7QUFBQSxZQUN6QyxJQUFBO0FBQUEsWUFDQSxLQUFPLEVBQUE7QUFBQSxXQUNULENBQUEsQ0FBQTtBQUFBLFVBQ0YsSUFBQTtBQUFBLFVBQ0E7QUFBQTtBQUNKLE9BQ0o7QUFFQSxNQUFBLE1BQU0sT0FBTyxZQUFhLEVBQUE7QUFDMUIsTUFBTyxPQUFBLElBQUE7QUFBQSxLQUNILENBQUEsTUFBQTtBQUNKLE1BQU8sT0FBQSxLQUFBO0FBQUE7QUFDWDtBQUNKO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLEVBUU8sS0FBSyxRQUEyQixFQUFBO0FBQ25DLElBQU8sT0FBQSxJQUFBLENBQUssR0FBSSxDQUFBLEdBQUEsQ0FBSSxRQUFRLENBQUE7QUFBQTtBQUNoQztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxFQVFPLElBQUksUUFBbUIsRUFBQTtBQUMxQixJQUFNLE1BQUEsT0FBQSxHQUFVLENBQUMsVUFBd0IsS0FBQTtBQUNyQyxNQUFBLElBQUksQ0FBQyxRQUFBLEVBQWdCLE1BQUEsSUFBSSxNQUFNLENBQXFDLG1DQUFBLENBQUEsQ0FBQTtBQUVwRSxNQUFJLElBQUEsQ0FBQyxZQUFtQixPQUFBLElBQUE7QUFDeEIsTUFBSSxJQUFBLFFBQUEsQ0FBUyxTQUFVLEVBQUEsRUFBVSxPQUFBLElBQUE7QUFDakMsTUFBSSxJQUFBLFFBQUEsQ0FBUyxJQUFLLEVBQUEsRUFBVSxPQUFBLElBQUE7QUFDNUIsTUFBQSxJQUFJLFNBQVMsY0FBZSxFQUFBLENBQUUsUUFBUyxDQUFBLFVBQVUsR0FBVSxPQUFBLElBQUE7QUFDM0QsTUFBQSxJQUFJLFNBQVMsY0FBZSxFQUFBLENBQUUsUUFBUyxDQUFBLEdBQUcsR0FBVSxPQUFBLElBQUE7QUFFcEQsTUFBTSxNQUFBLEtBQUEsR0FBUSxVQUFXLENBQUEsS0FBQSxDQUFNLEdBQUcsQ0FBQTtBQUNsQyxNQUFBLElBQUksS0FBUSxHQUFBLEVBQUE7QUFDWixNQUFBLEtBQUEsTUFBVyxVQUFVLEtBQU8sRUFBQTtBQUN4QixRQUFBLElBQUksS0FBTyxFQUFBLEtBQUEsR0FBUSxDQUFHLEVBQUEsS0FBSyxJQUFJLE1BQU0sQ0FBQSxDQUFBO0FBQUEsYUFDeEIsS0FBQSxHQUFBLE1BQUE7QUFFYixRQUFBLElBQUksU0FBUyxjQUFlLEVBQUEsQ0FBRSxRQUFTLENBQUEsS0FBSyxHQUFVLE9BQUEsSUFBQTtBQUN0RCxRQUFJLElBQUEsUUFBQSxDQUFTLGdCQUFpQixDQUFBLFFBQUEsQ0FBUyxHQUFHLEtBQUssQ0FBQSxFQUFBLENBQUksR0FBVSxPQUFBLElBQUE7QUFBQTtBQUdqRSxNQUFPLE9BQUEsS0FBQTtBQUFBLEtBQ1g7QUFFQSxJQUFPLE9BQUE7QUFBQSxNQUNILE9BQUE7QUFBQSxNQUNBLEtBQUssTUFBTTtBQUNQLFFBQU8sT0FBQTtBQUFBLFVBQ0gsT0FBUyxFQUFBLENBQUMsVUFBd0IsS0FBQSxDQUFDLFFBQVEsVUFBVTtBQUFBLFNBQ3pEO0FBQUE7QUFDSixLQUNKO0FBQUE7QUFFUjs7OzsifQ==