UNPKG

@jsprismarine/prismarine

Version:

Dedicated Minecraft Bedrock Edition server written in TypeScript

165 lines (164 loc) 18.1 kB
"use strict"; Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } }); const require_runtime = require("../_virtual/_rolldown/runtime.cjs.cjs"); const require_utils_cwd = require("../utils/cwd.cjs.cjs"); const require_world_GeneratorManager = require("./GeneratorManager.cjs.cjs"); const require_world_World = require("./World.cjs.cjs"); const require_world_providers_anvil_Anvil = require("./providers/anvil/Anvil.cjs.cjs"); const require_world_providers_filesystem_Filesystem = require("./providers/filesystem/Filesystem.cjs.cjs"); let node_fs = require("node:fs"); node_fs = require_runtime.__toESM(node_fs, 1); //#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 require_world_GeneratorManager.GeneratorManager(server); if (!node_fs.default.existsSync(require_utils_cwd.withCwd(WORLDS_FOLDER))) node_fs.default.mkdirSync(require_utils_cwd.withCwd(WORLDS_FOLDER), { recursive: true }); } /** * On enable hook, enables the manager and load all worlds. * @group Lifecycle */ async enable() { this.addProvider("Anvil", require_world_providers_anvil_Anvil.default); this.addProvider("Filesystem", require_world_providers_filesystem_Filesystem.default); 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 = require_utils_cwd.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 require_world_World.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 exports.default = WorldManager; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiV29ybGRNYW5hZ2VyLmNqcy5janMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3dvcmxkL1dvcmxkTWFuYWdlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IFNlcnZlciwgU2VydmljZSB9IGZyb20gJy4uLyc7XG5pbXBvcnQgeyB3aXRoQ3dkIH0gZnJvbSAnLi4vdXRpbHMvY3dkJztcbmltcG9ydCB7IEdlbmVyYXRvck1hbmFnZXIgfSBmcm9tICcuLyc7XG5pbXBvcnQgeyBXb3JsZCB9IGZyb20gJy4vV29ybGQnO1xuaW1wb3J0IHR5cGUgUHJvdmlkZXIgZnJvbSAnLi9wcm92aWRlcnMvUHJvdmlkZXInO1xuXG5pbXBvcnQgQW52aWwgZnJvbSAnLi9wcm92aWRlcnMvYW52aWwvQW52aWwnO1xuaW1wb3J0IEZpbGVzeXN0ZW0gZnJvbSAnLi9wcm92aWRlcnMvZmlsZXN5c3RlbS9GaWxlc3lzdGVtJztcblxuaW1wb3J0IGZzIGZyb20gJ25vZGU6ZnMnO1xuXG4vKipcbiAqIFN0YW5kYXJkIHdvcmxkIGRhdGEuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgV29ybGREYXRhIHtcbiAgICBzZWVkOiBudW1iZXI7XG4gICAgcHJvdmlkZXI/OiBzdHJpbmc7XG4gICAgZ2VuZXJhdG9yPzogc3RyaW5nO1xufVxuXG5jb25zdCBXT1JMRFNfRk9MREVSID0gJ3dvcmxkcyc7XG5jb25zdCBERUZBVUxUX1dPUkxEX1BST1ZJREVSID0gJ0ZpbGVzeXN0ZW0nO1xuXG4vKipcbiAqIFRoZSB3b3JsZCBtYW5hZ2VyIGlzIHJlc3BvbnNpYmxlIGxldmVsIGxvYWRpbmcsIHVubG9hZGluZywgYW5kIGdlbmVyYWwgbGV2ZWwgbWFuYWdlbWVudC5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgV29ybGRNYW5hZ2VyIGltcGxlbWVudHMgU2VydmljZSB7XG4gICAgcHJpdmF0ZSByZWFkb25seSB3b3JsZHM6IE1hcDxzdHJpbmcsIFdvcmxkPiA9IG5ldyBNYXAoKSBhcyBNYXA8c3RyaW5nLCBXb3JsZD47XG4gICAgcHJpdmF0ZSBkZWZhdWx0V29ybGQ6IFdvcmxkIHwgdW5kZWZpbmVkO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgZ2VuTWFuYWdlcjogR2VuZXJhdG9yTWFuYWdlcjtcbiAgICBwcml2YXRlIHJlYWRvbmx5IHNlcnZlcjogU2VydmVyO1xuICAgIHByaXZhdGUgcHJvdmlkZXJzOiBNYXA8c3RyaW5nLCBhbnk+ID0gbmV3IE1hcCgpIGFzIE1hcDxzdHJpbmcsIGFueT47IC8vIFRPRE86IHRoaXMgc2hvdWxkIGJlIGEgbWFuYWdlclxuXG4gICAgcHVibGljIGNvbnN0cnVjdG9yKHNlcnZlcjogU2VydmVyKSB7XG4gICAgICAgIHRoaXMuc2VydmVyID0gc2VydmVyO1xuICAgICAgICB0aGlzLmdlbk1hbmFnZXIgPSBuZXcgR2VuZXJhdG9yTWFuYWdlcihzZXJ2ZXIpO1xuXG4gICAgICAgIC8vIENyZWF0ZSB0aGUgd29ybGRzIGRpcmVjdG9yeSBpZiBpdCBkb2Vzbid0IGV4aXN0LlxuICAgICAgICBpZiAoIWZzLmV4aXN0c1N5bmMod2l0aEN3ZChXT1JMRFNfRk9MREVSKSkpIHtcbiAgICAgICAgICAgIGZzLm1rZGlyU3luYyh3aXRoQ3dkKFdPUkxEU19GT0xERVIpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIE9uIGVuYWJsZSBob29rLCBlbmFibGVzIHRoZSBtYW5hZ2VyIGFuZCBsb2FkIGFsbCB3b3JsZHMuXG4gICAgICogQGdyb3VwIExpZmVjeWNsZVxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBlbmFibGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMuYWRkUHJvdmlkZXIoJ0FudmlsJywgQW52aWwpO1xuICAgICAgICB0aGlzLmFkZFByb3ZpZGVyKCdGaWxlc3lzdGVtJywgRmlsZXN5c3RlbSk7XG5cbiAgICAgICAgY29uc3QgZGVmYXVsdFdvcmxkID0gdGhpcy5zZXJ2ZXIuZ2V0Q29uZmlnKCkuZ2V0TGV2ZWxOYW1lKCk7XG4gICAgICAgIGlmICghZGVmYXVsdFdvcmxkKSB7XG4gICAgICAgICAgICB0aGlzLnNlcnZlci5nZXRMb2dnZXIoKS53YXJuKGBJbnZhbGlkIHdvcmxkIWApO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgd29ybGREYXRhID0gdGhpcy5zZXJ2ZXIuZ2V0Q29uZmlnKCkuZ2V0V29ybGRzKClbZGVmYXVsdFdvcmxkXTtcbiAgICAgICAgaWYgKCF3b3JsZERhdGEpIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBsZXZlbC1uYW1lYCk7XG5cbiAgICAgICAgYXdhaXQgdGhpcy5sb2FkV29ybGQod29ybGREYXRhLCBkZWZhdWx0V29ybGQpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIE9uIGRpc2FibGUgaG9vay5cbiAgICAgKlxuICAgICAqIFNpZ25pZmllcyB0aGF0IHRoZSBtYW5hZ2VyIGlzIGJlaW5nIGRpc2FibGVkIGFuZCBhbGwgd29ybGRzIHNob3VsZCBiZSB1bmxvYWRlZC5cbiAgICAgKiBAZ3JvdXAgTGlmZWN5Y2xlXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIGRpc2FibGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKHRoaXMuZ2V0V29ybGRzKCkubWFwKGFzeW5jICh3b3JsZCkgPT4gdGhpcy51bmxvYWRXb3JsZCh3b3JsZC5nZXROYW1lKCkpKSk7XG4gICAgICAgIHRoaXMucHJvdmlkZXJzLmNsZWFyKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQWRkIGEgcHJvdmlkZXIgdG8gdGhlIGludGVybmFsIHByb3ZpZGVycyBtYXAuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gbmFtZSAtIHRoZSBuYW1lIG9mIHRoZSBwcm92aWRlciBDQVNFIFNFTlNJVElWRVxuICAgICAqIEBwYXJhbSBwcm92aWRlciAtIHRoZSBwcm92aWRlclxuICAgICAqL1xuICAgIHB1YmxpYyBhZGRQcm92aWRlcihuYW1lOiBzdHJpbmcsIHByb3ZpZGVyOiBhbnkpIHtcbiAgICAgICAgdGhpcy5wcm92aWRlcnMuc2V0KG5hbWUsIHByb3ZpZGVyKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZW1vdmUgYSBwcm92aWRlciBmcm9tIHRoZSBpbnRlcm5hbCBwcm92aWRlcnMgbWFwLlxuICAgICAqXG4gICAgICogQHBhcmFtIG5hbWUgLSB0aGUgbmFtZSBvZiB0aGUgcHJvdmlkZXIgQ0FTRSBTRU5TSVRJVkVcbiAgICAgKi9cbiAgICBwdWJsaWMgcmVtb3ZlUHJvdmlkZXIobmFtZTogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMucHJvdmlkZXJzLmRlbGV0ZShuYW1lKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgYWxsIHByb3ZpZGVycy5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0UHJvdmlkZXJzKCk6IE1hcDxzdHJpbmcsIFByb3ZpZGVyPiB7XG4gICAgICAgIHJldHVybiB0aGlzLnByb3ZpZGVycyBhcyBNYXA8c3RyaW5nLCBQcm92aWRlcj47XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2F2ZSB0aGUgd29ybGQgdG8gZGlzay5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgc2F2ZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdGhpcy5zZXJ2ZXIuZ2V0TG9nZ2VyKCkuaW5mbygnU2F2aW5nIHdvcmxkcycpO1xuICAgICAgICBmb3IgKGNvbnN0IHdvcmxkIG9mIHRoaXMuZ2V0V29ybGRzKCkpIHtcbiAgICAgICAgICAgIGF3YWl0IHdvcmxkLnNhdmUoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIExvYWQgYSB3b3JsZFxuICAgICAqXG4gICAgICogQHBhcmFtIHdvcmxkRGF0YSAtIHRoZSB3b3JsZCBkYXRhIGluY2x1ZGluZyBwcm92aWRlciBrZXksIGdlbmVyYXRvclxuICAgICAqIEBwYXJhbSBmb2xkZXJOYW1lIC0gdGhlIG5hbWUgb2YgdGhlIGZvbGRlciBjb250YWluaW5nIHRoZSB3b3JsZFxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBsb2FkV29ybGQod29ybGREYXRhOiBXb3JsZERhdGEsIGZvbGRlck5hbWU6IHN0cmluZyk6IFByb21pc2U8V29ybGQ+IHtcbiAgICAgICAgaWYgKCEod29ybGREYXRhIGFzIGFueSkpIHRocm93IG5ldyBFcnJvcignSW52YWxpZCB3b3JsZCBkYXRhJyk7XG5cbiAgICAgICAgaWYgKHRoaXMuaXNXb3JsZExvYWRlZChmb2xkZXJOYW1lKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBXb3JsZCAke2ZvbGRlck5hbWV9IGhhcyBhbHJlYWR5IGJlZW4gbG9hZGVkYCk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBsZXZlbFBhdGggPSB3aXRoQ3dkKFdPUkxEU19GT0xERVIsIGZvbGRlck5hbWUpO1xuICAgICAgICBjb25zdCBwcm92aWRlciA9IHRoaXMucHJvdmlkZXJzLmdldCh3b3JsZERhdGEucHJvdmlkZXIgPz8gREVGQVVMVF9XT1JMRF9QUk9WSURFUik7XG4gICAgICAgIGNvbnN0IGdlbmVyYXRvciA9IHRoaXMuZ2V0R2VuZXJhdG9yTWFuYWdlcigpLmdldEdlbmVyYXRvcih3b3JsZERhdGEuZ2VuZXJhdG9yID8/ICdGbGF0Jyk7XG5cbiAgICAgICAgaWYgKCFwcm92aWRlcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBpbnZhbGlkIHByb3ZpZGVyIHdpdGggaWQgJHt3b3JsZERhdGEucHJvdmlkZXJ9YCk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB3b3JsZCA9IG5ldyBXb3JsZCh7XG4gICAgICAgICAgICBuYW1lOiBmb2xkZXJOYW1lLFxuICAgICAgICAgICAgcGF0aDogbGV2ZWxQYXRoLFxuICAgICAgICAgICAgc2VydmVyOiB0aGlzLnNlcnZlcixcbiAgICAgICAgICAgIHByb3ZpZGVyOiBuZXcgcHJvdmlkZXIobGV2ZWxQYXRoLCB0aGlzLnNlcnZlciksXG5cbiAgICAgICAgICAgIHNlZWQ6IHdvcmxkRGF0YS5zZWVkLFxuICAgICAgICAgICAgZ2VuZXJhdG9yLFxuICAgICAgICAgICAgY29uZmlnOiB3b3JsZERhdGFcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMud29ybGRzLnNldCh3b3JsZC5nZXRVVUlEKCksIHdvcmxkKTtcblxuICAgICAgICAvLyBGaXJzdCBsZXZlbCB0byBiZSBsb2FkZWQgaXMgYWxzbyB0aGUgZGVmYXVsdCBvbmVcbiAgICAgICAgaWYgKCF0aGlzLmRlZmF1bHRXb3JsZCkge1xuICAgICAgICAgICAgdGhpcy5kZWZhdWx0V29ybGQgPSB0aGlzLndvcmxkcy5nZXQod29ybGQuZ2V0VVVJRCgpKSE7XG4gICAgICAgICAgICB0aGlzLnNlcnZlci5nZXRMb2dnZXIoKS5pbmZvKGBMb2FkaW5nICR7d29ybGQuZ2V0Rm9ybWF0dGVkTmFtZSgpfSBhcyBkZWZhdWx0IHdvcmxkIWApO1xuICAgICAgICB9XG5cbiAgICAgICAgYXdhaXQgd29ybGQuZW5hYmxlKCk7XG4gICAgICAgIHRoaXMuc2VydmVyLmdldExvZ2dlcigpLnZlcmJvc2UoYFdvcmxkICR7d29ybGQuZ2V0Rm9ybWF0dGVkTmFtZSgpfSBzdWNjZXNzZnVsbHkgbG9hZGVkIWApO1xuXG4gICAgICAgIHJldHVybiB3b3JsZDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBVbmxvYWRzIGEgbGV2ZWwgYnkgaXRzIGZvbGRlciBuYW1lLlxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyB1bmxvYWRXb3JsZChmb2xkZXJOYW1lOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKCF0aGlzLmlzV29ybGRMb2FkZWQoZm9sZGVyTmFtZSkpIHtcbiAgICAgICAgICAgIHRoaXMuc2VydmVyLmdldExvZ2dlcigpLmVycm9yKGBDYW5ub3QgdW5sb2FkIGEgbm90IGxvYWRlZCB3b3JsZCB3aXRoIG5hbWUgwqdiJHtmb2xkZXJOYW1lfWApO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgd29ybGQgPSB0aGlzLmdldFdvcmxkQnlOYW1lKGZvbGRlck5hbWUpO1xuICAgICAgICBpZiAoIXdvcmxkKSB7XG4gICAgICAgICAgICB0aGlzLnNlcnZlci5nZXRMb2dnZXIoKS5lcnJvcihgQ2Fubm90IHVubG9hZCB3b3JsZCAke2ZvbGRlck5hbWV9YCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBhd2FpdCB3b3JsZC5kaXNhYmxlKCk7XG4gICAgICAgIHRoaXMud29ybGRzLmRlbGV0ZSh3b3JsZC5nZXRVVUlEKCkpO1xuICAgICAgICB0aGlzLnNlcnZlci5nZXRMb2dnZXIoKS52ZXJib3NlKGBTdWNjZXNzZnVsbHkgdW5sb2FkZWQgd29ybGQgJHt3b3JsZC5nZXRGb3JtYXR0ZWROYW1lKCl9IWApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgd2hhdGV2ZXIgdGhlIHdvcmxkIGlzIGxvYWRlZCBvciBub3QuXG4gICAgICogQHJldHVybnMge2Jvb2xlYW59IHRydWUgaWYgdGhlIHdvcmxkIGlzIGxvYWRlZCwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAgICovXG4gICAgcHVibGljIGlzV29ybGRMb2FkZWQoZm9sZGVyTmFtZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgICAgIGNvbnN0IHdvcmxkID0gQXJyYXkuZnJvbSh0aGlzLndvcmxkcy52YWx1ZXMoKSkuZmluZChcbiAgICAgICAgICAgICh3b3JsZCkgPT4gd29ybGQuZ2V0TmFtZSgpLnRvTG93ZXJDYXNlKCkgPT09IGZvbGRlck5hbWUudG9Mb3dlckNhc2UoKVxuICAgICAgICApO1xuXG4gICAgICAgIGlmICh3b3JsZCkgcmV0dXJuIHRydWU7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIGEgd29ybGQgYnkgaXRzIGZvbGRlciBuYW1lLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRXb3JsZEJ5TmFtZShmb2xkZXJOYW1lOiBzdHJpbmcpOiBXb3JsZCB8IG51bGwge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRXb3JsZHMoKS5maW5kKCh3b3JsZCkgPT4gd29ybGQuZ2V0TmFtZSgpLnRvTG93ZXJDYXNlKCkgPT09IGZvbGRlck5hbWUudG9Mb3dlckNhc2UoKSkgPz8gbnVsbDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIGFuIGFycmF5IHdpdGggYWxsIHdvcmxkcy5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0V29ybGRzKCk6IFdvcmxkW10ge1xuICAgICAgICByZXR1cm4gQXJyYXkuZnJvbSh0aGlzLndvcmxkcy52YWx1ZXMoKSk7XG4gICAgfVxuXG4gICAgcHVibGljIGdldERlZmF1bHRXb3JsZCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGVmYXVsdFdvcmxkID8/IHRoaXMuZ2V0V29ybGRzKClbMF07XG4gICAgfVxuXG4gICAgcHVibGljIGdldEdlbmVyYXRvck1hbmFnZXIoKTogR2VuZXJhdG9yTWFuYWdlciB7XG4gICAgICAgIHJldHVybiB0aGlzLmdlbk1hbmFnZXI7XG4gICAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7OztBQW9CQSxJQUFNLGdCQUFnQjtBQUN0QixJQUFNLHlCQUF5Qjs7OztBQUsvQixJQUFxQixlQUFyQixNQUFxRDtDQUNqRCx5QkFBOEMsSUFBSSxJQUFJO0NBQ3REO0NBQ0E7Q0FDQTtDQUNBLDRCQUFzQyxJQUFJLElBQUk7Q0FFOUMsWUFBbUIsUUFBZ0I7RUFDL0IsS0FBSyxTQUFTO0VBQ2QsS0FBSyxhQUFhLElBQUksK0JBQUEsaUJBQWlCLE1BQU07RUFHN0MsSUFBSSxDQUFDLFFBQUEsUUFBRyxXQUFXLGtCQUFBLFFBQVEsYUFBYSxDQUFDLEdBQ3JDLFFBQUEsUUFBRyxVQUFVLGtCQUFBLFFBQVEsYUFBYSxHQUFHLEVBQUUsV0FBVyxLQUFLLENBQUM7Q0FFaEU7Ozs7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