@jsprismarine/prismarine
Version:
Dedicated Minecraft Bedrock Edition server written in TypeScript
158 lines (157 loc) • 17.4 kB
JavaScript
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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