UNPKG

@jsprismarine/prismarine

Version:

Dedicated Minecraft Bedrock Edition server written in TypeScript

158 lines (157 loc) 17.4 kB
import { withCwd } from "../utils/cwd.es.js"; import { GeneratorManager } from "./GeneratorManager.es.js"; import { World } from "./World.es.js"; import Anvil from "./providers/anvil/Anvil.es.js"; import Filesystem from "./providers/filesystem/Filesystem.es.js"; import fs from "node:fs"; //#region src/world/WorldManager.ts var WORLDS_FOLDER = "worlds"; var DEFAULT_WORLD_PROVIDER = "Filesystem"; /** * The world manager is responsible level loading, unloading, and general level management. */ var WorldManager = class { worlds = /* @__PURE__ */ new Map(); defaultWorld; genManager; server; providers = /* @__PURE__ */ new Map(); constructor(server) { this.server = server; this.genManager = new GeneratorManager(server); if (!fs.existsSync(withCwd(WORLDS_FOLDER))) fs.mkdirSync(withCwd(WORLDS_FOLDER), { recursive: true }); } /** * On enable hook, enables the manager and load all worlds. * @group Lifecycle */ async enable() { this.addProvider("Anvil", Anvil); this.addProvider("Filesystem", Filesystem); const defaultWorld = this.server.getConfig().getLevelName(); if (!defaultWorld) { this.server.getLogger().warn(`Invalid world!`); return; } const worldData = this.server.getConfig().getWorlds()[defaultWorld]; if (!worldData) throw new Error(`Invalid level-name`); await this.loadWorld(worldData, defaultWorld); } /** * On disable hook. * * Signifies that the manager is being disabled and all worlds should be unloaded. * @group Lifecycle */ async disable() { await Promise.all(this.getWorlds().map(async (world) => this.unloadWorld(world.getName()))); this.providers.clear(); } /** * Add a provider to the internal providers map. * * @param name - the name of the provider CASE SENSITIVE * @param provider - the provider */ addProvider(name, provider) { this.providers.set(name, provider); } /** * Remove a provider from the internal providers map. * * @param name - the name of the provider CASE SENSITIVE */ removeProvider(name) { this.providers.delete(name); } /** * Get all providers. */ getProviders() { return this.providers; } /** * Save the world to disk. */ async save() { this.server.getLogger().info("Saving worlds"); for (const world of this.getWorlds()) await world.save(); } /** * Load a world * * @param worldData - the world data including provider key, generator * @param folderName - the name of the folder containing the world */ async loadWorld(worldData, folderName) { if (!worldData) throw new Error("Invalid world data"); if (this.isWorldLoaded(folderName)) throw new Error(`World ${folderName} has already been loaded`); const levelPath = withCwd(WORLDS_FOLDER, folderName); const provider = this.providers.get(worldData.provider ?? DEFAULT_WORLD_PROVIDER); const generator = this.getGeneratorManager().getGenerator(worldData.generator ?? "Flat"); if (!provider) throw new Error(`invalid provider with id ${worldData.provider}`); const world = new World({ name: folderName, path: levelPath, server: this.server, provider: new provider(levelPath, this.server), seed: worldData.seed, generator, config: worldData }); this.worlds.set(world.getUUID(), world); if (!this.defaultWorld) { this.defaultWorld = this.worlds.get(world.getUUID()); this.server.getLogger().info(`Loading ${world.getFormattedName()} as default world!`); } await world.enable(); this.server.getLogger().verbose(`World ${world.getFormattedName()} successfully loaded!`); return world; } /** * Unloads a level by its folder name. */ async unloadWorld(folderName) { if (!this.isWorldLoaded(folderName)) { this.server.getLogger().error(`Cannot unload a not loaded world with name §b${folderName}`); return; } const world = this.getWorldByName(folderName); if (!world) { this.server.getLogger().error(`Cannot unload world ${folderName}`); return; } await world.disable(); this.worlds.delete(world.getUUID()); this.server.getLogger().verbose(`Successfully unloaded world ${world.getFormattedName()}!`); } /** * Returns whatever the world is loaded or not. * @returns {boolean} true if the world is loaded, false otherwise */ isWorldLoaded(folderName) { if (Array.from(this.worlds.values()).find((world) => world.getName().toLowerCase() === folderName.toLowerCase())) return true; return false; } /** * Returns a world by its folder name. */ getWorldByName(folderName) { return this.getWorlds().find((world) => world.getName().toLowerCase() === folderName.toLowerCase()) ?? null; } /** * Returns an array with all worlds. */ getWorlds() { return Array.from(this.worlds.values()); } getDefaultWorld() { return this.defaultWorld ?? this.getWorlds()[0]; } getGeneratorManager() { return this.genManager; } }; //#endregion export { WorldManager as default }; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiV29ybGRNYW5hZ2VyLmVzLmpzIiwibmFtZXMiOltdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93b3JsZC9Xb3JsZE1hbmFnZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBTZXJ2ZXIsIFNlcnZpY2UgfSBmcm9tICcuLi8nO1xuaW1wb3J0IHsgd2l0aEN3ZCB9IGZyb20gJy4uL3V0aWxzL2N3ZCc7XG5pbXBvcnQgeyBHZW5lcmF0b3JNYW5hZ2VyIH0gZnJvbSAnLi8nO1xuaW1wb3J0IHsgV29ybGQgfSBmcm9tICcuL1dvcmxkJztcbmltcG9ydCB0eXBlIFByb3ZpZGVyIGZyb20gJy4vcHJvdmlkZXJzL1Byb3ZpZGVyJztcblxuaW1wb3J0IEFudmlsIGZyb20gJy4vcHJvdmlkZXJzL2FudmlsL0FudmlsJztcbmltcG9ydCBGaWxlc3lzdGVtIGZyb20gJy4vcHJvdmlkZXJzL2ZpbGVzeXN0ZW0vRmlsZXN5c3RlbSc7XG5cbmltcG9ydCBmcyBmcm9tICdub2RlOmZzJztcblxuLyoqXG4gKiBTdGFuZGFyZCB3b3JsZCBkYXRhLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFdvcmxkRGF0YSB7XG4gICAgc2VlZDogbnVtYmVyO1xuICAgIHByb3ZpZGVyPzogc3RyaW5nO1xuICAgIGdlbmVyYXRvcj86IHN0cmluZztcbn1cblxuY29uc3QgV09STERTX0ZPTERFUiA9ICd3b3JsZHMnO1xuY29uc3QgREVGQVVMVF9XT1JMRF9QUk9WSURFUiA9ICdGaWxlc3lzdGVtJztcblxuLyoqXG4gKiBUaGUgd29ybGQgbWFuYWdlciBpcyByZXNwb25zaWJsZSBsZXZlbCBsb2FkaW5nLCB1bmxvYWRpbmcsIGFuZCBnZW5lcmFsIGxldmVsIG1hbmFnZW1lbnQuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFdvcmxkTWFuYWdlciBpbXBsZW1lbnRzIFNlcnZpY2Uge1xuICAgIHByaXZhdGUgcmVhZG9ubHkgd29ybGRzOiBNYXA8c3RyaW5nLCBXb3JsZD4gPSBuZXcgTWFwKCkgYXMgTWFwPHN0cmluZywgV29ybGQ+O1xuICAgIHByaXZhdGUgZGVmYXVsdFdvcmxkOiBXb3JsZCB8IHVuZGVmaW5lZDtcbiAgICBwcml2YXRlIHJlYWRvbmx5IGdlbk1hbmFnZXI6IEdlbmVyYXRvck1hbmFnZXI7XG4gICAgcHJpdmF0ZSByZWFkb25seSBzZXJ2ZXI6IFNlcnZlcjtcbiAgICBwcml2YXRlIHByb3ZpZGVyczogTWFwPHN0cmluZywgYW55PiA9IG5ldyBNYXAoKSBhcyBNYXA8c3RyaW5nLCBhbnk+OyAvLyBUT0RPOiB0aGlzIHNob3VsZCBiZSBhIG1hbmFnZXJcblxuICAgIHB1YmxpYyBjb25zdHJ1Y3RvcihzZXJ2ZXI6IFNlcnZlcikge1xuICAgICAgICB0aGlzLnNlcnZlciA9IHNlcnZlcjtcbiAgICAgICAgdGhpcy5nZW5NYW5hZ2VyID0gbmV3IEdlbmVyYXRvck1hbmFnZXIoc2VydmVyKTtcblxuICAgICAgICAvLyBDcmVhdGUgdGhlIHdvcmxkcyBkaXJlY3RvcnkgaWYgaXQgZG9lc24ndCBleGlzdC5cbiAgICAgICAgaWYgKCFmcy5leGlzdHNTeW5jKHdpdGhDd2QoV09STERTX0ZPTERFUikpKSB7XG4gICAgICAgICAgICBmcy5ta2RpclN5bmMod2l0aEN3ZChXT1JMRFNfRk9MREVSKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBPbiBlbmFibGUgaG9vaywgZW5hYmxlcyB0aGUgbWFuYWdlciBhbmQgbG9hZCBhbGwgd29ybGRzLlxuICAgICAqIEBncm91cCBMaWZlY3ljbGVcbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgZW5hYmxlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB0aGlzLmFkZFByb3ZpZGVyKCdBbnZpbCcsIEFudmlsKTtcbiAgICAgICAgdGhpcy5hZGRQcm92aWRlcignRmlsZXN5c3RlbScsIEZpbGVzeXN0ZW0pO1xuXG4gICAgICAgIGNvbnN0IGRlZmF1bHRXb3JsZCA9IHRoaXMuc2VydmVyLmdldENvbmZpZygpLmdldExldmVsTmFtZSgpO1xuICAgICAgICBpZiAoIWRlZmF1bHRXb3JsZCkge1xuICAgICAgICAgICAgdGhpcy5zZXJ2ZXIuZ2V0TG9nZ2VyKCkud2FybihgSW52YWxpZCB3b3JsZCFgKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHdvcmxkRGF0YSA9IHRoaXMuc2VydmVyLmdldENvbmZpZygpLmdldFdvcmxkcygpW2RlZmF1bHRXb3JsZF07XG4gICAgICAgIGlmICghd29ybGREYXRhKSB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgbGV2ZWwtbmFtZWApO1xuXG4gICAgICAgIGF3YWl0IHRoaXMubG9hZFdvcmxkKHdvcmxkRGF0YSwgZGVmYXVsdFdvcmxkKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBPbiBkaXNhYmxlIGhvb2suXG4gICAgICpcbiAgICAgKiBTaWduaWZpZXMgdGhhdCB0aGUgbWFuYWdlciBpcyBiZWluZyBkaXNhYmxlZCBhbmQgYWxsIHdvcmxkcyBzaG91bGQgYmUgdW5sb2FkZWQuXG4gICAgICogQGdyb3VwIExpZmVjeWNsZVxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBkaXNhYmxlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbCh0aGlzLmdldFdvcmxkcygpLm1hcChhc3luYyAod29ybGQpID0+IHRoaXMudW5sb2FkV29ybGQod29ybGQuZ2V0TmFtZSgpKSkpO1xuICAgICAgICB0aGlzLnByb3ZpZGVycy5jbGVhcigpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFkZCBhIHByb3ZpZGVyIHRvIHRoZSBpbnRlcm5hbCBwcm92aWRlcnMgbWFwLlxuICAgICAqXG4gICAgICogQHBhcmFtIG5hbWUgLSB0aGUgbmFtZSBvZiB0aGUgcHJvdmlkZXIgQ0FTRSBTRU5TSVRJVkVcbiAgICAgKiBAcGFyYW0gcHJvdmlkZXIgLSB0aGUgcHJvdmlkZXJcbiAgICAgKi9cbiAgICBwdWJsaWMgYWRkUHJvdmlkZXIobmFtZTogc3RyaW5nLCBwcm92aWRlcjogYW55KSB7XG4gICAgICAgIHRoaXMucHJvdmlkZXJzLnNldChuYW1lLCBwcm92aWRlcik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlIGEgcHJvdmlkZXIgZnJvbSB0aGUgaW50ZXJuYWwgcHJvdmlkZXJzIG1hcC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBuYW1lIC0gdGhlIG5hbWUgb2YgdGhlIHByb3ZpZGVyIENBU0UgU0VOU0lUSVZFXG4gICAgICovXG4gICAgcHVibGljIHJlbW92ZVByb3ZpZGVyKG5hbWU6IHN0cmluZykge1xuICAgICAgICB0aGlzLnByb3ZpZGVycy5kZWxldGUobmFtZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGFsbCBwcm92aWRlcnMuXG4gICAgICovXG4gICAgcHVibGljIGdldFByb3ZpZGVycygpOiBNYXA8c3RyaW5nLCBQcm92aWRlcj4ge1xuICAgICAgICByZXR1cm4gdGhpcy5wcm92aWRlcnMgYXMgTWFwPHN0cmluZywgUHJvdmlkZXI+O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNhdmUgdGhlIHdvcmxkIHRvIGRpc2suXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIHNhdmUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMuc2VydmVyLmdldExvZ2dlcigpLmluZm8oJ1NhdmluZyB3b3JsZHMnKTtcbiAgICAgICAgZm9yIChjb25zdCB3b3JsZCBvZiB0aGlzLmdldFdvcmxkcygpKSB7XG4gICAgICAgICAgICBhd2FpdCB3b3JsZC5zYXZlKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBMb2FkIGEgd29ybGRcbiAgICAgKlxuICAgICAqIEBwYXJhbSB3b3JsZERhdGEgLSB0aGUgd29ybGQgZGF0YSBpbmNsdWRpbmcgcHJvdmlkZXIga2V5LCBnZW5lcmF0b3JcbiAgICAgKiBAcGFyYW0gZm9sZGVyTmFtZSAtIHRoZSBuYW1lIG9mIHRoZSBmb2xkZXIgY29udGFpbmluZyB0aGUgd29ybGRcbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgbG9hZFdvcmxkKHdvcmxkRGF0YTogV29ybGREYXRhLCBmb2xkZXJOYW1lOiBzdHJpbmcpOiBQcm9taXNlPFdvcmxkPiB7XG4gICAgICAgIGlmICghKHdvcmxkRGF0YSBhcyBhbnkpKSB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgd29ybGQgZGF0YScpO1xuXG4gICAgICAgIGlmICh0aGlzLmlzV29ybGRMb2FkZWQoZm9sZGVyTmFtZSkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgV29ybGQgJHtmb2xkZXJOYW1lfSBoYXMgYWxyZWFkeSBiZWVuIGxvYWRlZGApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgbGV2ZWxQYXRoID0gd2l0aEN3ZChXT1JMRFNfRk9MREVSLCBmb2xkZXJOYW1lKTtcbiAgICAgICAgY29uc3QgcHJvdmlkZXIgPSB0aGlzLnByb3ZpZGVycy5nZXQod29ybGREYXRhLnByb3ZpZGVyID8/IERFRkFVTFRfV09STERfUFJPVklERVIpO1xuICAgICAgICBjb25zdCBnZW5lcmF0b3IgPSB0aGlzLmdldEdlbmVyYXRvck1hbmFnZXIoKS5nZXRHZW5lcmF0b3Iod29ybGREYXRhLmdlbmVyYXRvciA/PyAnRmxhdCcpO1xuXG4gICAgICAgIGlmICghcHJvdmlkZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgaW52YWxpZCBwcm92aWRlciB3aXRoIGlkICR7d29ybGREYXRhLnByb3ZpZGVyfWApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgd29ybGQgPSBuZXcgV29ybGQoe1xuICAgICAgICAgICAgbmFtZTogZm9sZGVyTmFtZSxcbiAgICAgICAgICAgIHBhdGg6IGxldmVsUGF0aCxcbiAgICAgICAgICAgIHNlcnZlcjogdGhpcy5zZXJ2ZXIsXG4gICAgICAgICAgICBwcm92aWRlcjogbmV3IHByb3ZpZGVyKGxldmVsUGF0aCwgdGhpcy5zZXJ2ZXIpLFxuXG4gICAgICAgICAgICBzZWVkOiB3b3JsZERhdGEuc2VlZCxcbiAgICAgICAgICAgIGdlbmVyYXRvcixcbiAgICAgICAgICAgIGNvbmZpZzogd29ybGREYXRhXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLndvcmxkcy5zZXQod29ybGQuZ2V0VVVJRCgpLCB3b3JsZCk7XG5cbiAgICAgICAgLy8gRmlyc3QgbGV2ZWwgdG8gYmUgbG9hZGVkIGlzIGFsc28gdGhlIGRlZmF1bHQgb25lXG4gICAgICAgIGlmICghdGhpcy5kZWZhdWx0V29ybGQpIHtcbiAgICAgICAgICAgIHRoaXMuZGVmYXVsdFdvcmxkID0gdGhpcy53b3JsZHMuZ2V0KHdvcmxkLmdldFVVSUQoKSkhO1xuICAgICAgICAgICAgdGhpcy5zZXJ2ZXIuZ2V0TG9nZ2VyKCkuaW5mbyhgTG9hZGluZyAke3dvcmxkLmdldEZvcm1hdHRlZE5hbWUoKX0gYXMgZGVmYXVsdCB3b3JsZCFgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGF3YWl0IHdvcmxkLmVuYWJsZSgpO1xuICAgICAgICB0aGlzLnNlcnZlci5nZXRMb2dnZXIoKS52ZXJib3NlKGBXb3JsZCAke3dvcmxkLmdldEZvcm1hdHRlZE5hbWUoKX0gc3VjY2Vzc2Z1bGx5IGxvYWRlZCFgKTtcblxuICAgICAgICByZXR1cm4gd29ybGQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVW5sb2FkcyBhIGxldmVsIGJ5IGl0cyBmb2xkZXIgbmFtZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgdW5sb2FkV29ybGQoZm9sZGVyTmFtZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICghdGhpcy5pc1dvcmxkTG9hZGVkKGZvbGRlck5hbWUpKSB7XG4gICAgICAgICAgICB0aGlzLnNlcnZlci5nZXRMb2dnZXIoKS5lcnJvcihgQ2Fubm90IHVubG9hZCBhIG5vdCBsb2FkZWQgd29ybGQgd2l0aCBuYW1lIMKnYiR7Zm9sZGVyTmFtZX1gKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHdvcmxkID0gdGhpcy5nZXRXb3JsZEJ5TmFtZShmb2xkZXJOYW1lKTtcbiAgICAgICAgaWYgKCF3b3JsZCkge1xuICAgICAgICAgICAgdGhpcy5zZXJ2ZXIuZ2V0TG9nZ2VyKCkuZXJyb3IoYENhbm5vdCB1bmxvYWQgd29ybGQgJHtmb2xkZXJOYW1lfWApO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgYXdhaXQgd29ybGQuZGlzYWJsZSgpO1xuICAgICAgICB0aGlzLndvcmxkcy5kZWxldGUod29ybGQuZ2V0VVVJRCgpKTtcbiAgICAgICAgdGhpcy5zZXJ2ZXIuZ2V0TG9nZ2VyKCkudmVyYm9zZShgU3VjY2Vzc2Z1bGx5IHVubG9hZGVkIHdvcmxkICR7d29ybGQuZ2V0Rm9ybWF0dGVkTmFtZSgpfSFgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHdoYXRldmVyIHRoZSB3b3JsZCBpcyBsb2FkZWQgb3Igbm90LlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSB0cnVlIGlmIHRoZSB3b3JsZCBpcyBsb2FkZWQsIGZhbHNlIG90aGVyd2lzZVxuICAgICAqL1xuICAgIHB1YmxpYyBpc1dvcmxkTG9hZGVkKGZvbGRlck5hbWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgICAgICBjb25zdCB3b3JsZCA9IEFycmF5LmZyb20odGhpcy53b3JsZHMudmFsdWVzKCkpLmZpbmQoXG4gICAgICAgICAgICAod29ybGQpID0+IHdvcmxkLmdldE5hbWUoKS50b0xvd2VyQ2FzZSgpID09PSBmb2xkZXJOYW1lLnRvTG93ZXJDYXNlKClcbiAgICAgICAgKTtcblxuICAgICAgICBpZiAod29ybGQpIHJldHVybiB0cnVlO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhIHdvcmxkIGJ5IGl0cyBmb2xkZXIgbmFtZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0V29ybGRCeU5hbWUoZm9sZGVyTmFtZTogc3RyaW5nKTogV29ybGQgfCBudWxsIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0V29ybGRzKCkuZmluZCgod29ybGQpID0+IHdvcmxkLmdldE5hbWUoKS50b0xvd2VyQ2FzZSgpID09PSBmb2xkZXJOYW1lLnRvTG93ZXJDYXNlKCkpID8/IG51bGw7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhbiBhcnJheSB3aXRoIGFsbCB3b3JsZHMuXG4gICAgICovXG4gICAgcHVibGljIGdldFdvcmxkcygpOiBXb3JsZFtdIHtcbiAgICAgICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy53b3JsZHMudmFsdWVzKCkpO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXREZWZhdWx0V29ybGQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmRlZmF1bHRXb3JsZCA/PyB0aGlzLmdldFdvcmxkcygpWzBdO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRHZW5lcmF0b3JNYW5hZ2VyKCk6IEdlbmVyYXRvck1hbmFnZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5nZW5NYW5hZ2VyO1xuICAgIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQW9CQSxJQUFNLGdCQUFnQjtBQUN0QixJQUFNLHlCQUF5Qjs7OztBQUsvQixJQUFxQixlQUFyQixNQUFxRDtDQUNqRCx5QkFBOEMsSUFBSSxJQUFJO0NBQ3REO0NBQ0E7Q0FDQTtDQUNBLDRCQUFzQyxJQUFJLElBQUk7Q0FFOUMsWUFBbUIsUUFBZ0I7RUFDL0IsS0FBSyxTQUFTO0VBQ2QsS0FBSyxhQUFhLElBQUksaUJBQWlCLE1BQU07RUFHN0MsSUFBSSxDQUFDLEdBQUcsV0FBVyxRQUFRLGFBQWEsQ0FBQyxHQUNyQyxHQUFHLFVBQVUsUUFBUSxhQUFhLEdBQUcsRUFBRSxXQUFXLEtBQUssQ0FBQztDQUVoRTs7Ozs7Q0FNQSxNQUFhLFNBQXdCO0VBQ2pDLEtBQUssWUFBWSxTQUFT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