@jsprismarine/prismarine
Version:
Dedicated Minecraft Bedrock Edition server written in TypeScript
180 lines (173 loc) • 20.9 kB
JavaScript
;
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
const utils_cwd = require('../utils/cwd.cjs.cjs');
require('@jsprismarine/nbt');
require('@jsprismarine/bedrock-data');
require('@jsprismarine/jsbinaryutils');
require('zlib');
require('@jsprismarine/math');
const world_GeneratorManager = require('./GeneratorManager.cjs.cjs');
const world_World = require('./World.cjs.cjs');
const world_providers_anvil_Anvil = require('./providers/anvil/Anvil.cjs.cjs');
const world_providers_filesystem_Filesystem = require('./providers/filesystem/Filesystem.cjs.cjs');
const fs = require('node:fs');
const _interopDefault = e => e && e.__esModule ? e : { default: e };
const fs__default = /*#__PURE__*/_interopDefault(fs);
const WORLDS_FOLDER = "worlds";
const DEFAULT_WORLD_PROVIDER = "Filesystem";
class WorldManager {
worlds = /* @__PURE__ */ new Map();
defaultWorld;
genManager;
server;
providers = /* @__PURE__ */ new Map();
// TODO: this should be a manager
constructor(server) {
this.server = server;
this.genManager = new world_GeneratorManager.GeneratorManager(server);
if (!fs__default.default.existsSync(utils_cwd.withCwd(WORLDS_FOLDER))) {
fs__default.default.mkdirSync(utils_cwd.withCwd(WORLDS_FOLDER), { recursive: true });
}
}
/**
* On enable hook, enables the manager and load all worlds.
* @group Lifecycle
*/
async enable() {
this.addProvider("Anvil", world_providers_anvil_Anvil.default);
this.addProvider("Filesystem", 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 = 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 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) {
const world = Array.from(this.worlds.values()).find(
(world2) => world2.getName().toLowerCase() === folderName.toLowerCase()
);
if (world) 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;
}
}
exports.default = WorldManager;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiV29ybGRNYW5hZ2VyLmNqcy5janMiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93b3JsZC9Xb3JsZE1hbmFnZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBTZXJ2ZXIsIFNlcnZpY2UgfSBmcm9tICcuLi8nO1xuaW1wb3J0IHsgd2l0aEN3ZCB9IGZyb20gJy4uL3V0aWxzL2N3ZCc7XG5pbXBvcnQgeyBHZW5lcmF0b3JNYW5hZ2VyIH0gZnJvbSAnLi8nO1xuaW1wb3J0IHsgV29ybGQgfSBmcm9tICcuL1dvcmxkJztcbmltcG9ydCB0eXBlIFByb3ZpZGVyIGZyb20gJy4vcHJvdmlkZXJzL1Byb3ZpZGVyJztcblxuaW1wb3J0IEFudmlsIGZyb20gJy4vcHJvdmlkZXJzL2FudmlsL0FudmlsJztcbmltcG9ydCBGaWxlc3lzdGVtIGZyb20gJy4vcHJvdmlkZXJzL2ZpbGVzeXN0ZW0vRmlsZXN5c3RlbSc7XG5cbmltcG9ydCBmcyBmcm9tICdub2RlOmZzJztcblxuLyoqXG4gKiBTdGFuZGFyZCB3b3JsZCBkYXRhLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFdvcmxkRGF0YSB7XG4gICAgc2VlZDogbnVtYmVyO1xuICAgIHByb3ZpZGVyPzogc3RyaW5nO1xuICAgIGdlbmVyYXRvcj86IHN0cmluZztcbn1cblxuY29uc3QgV09STERTX0ZPTERFUiA9ICd3b3JsZHMnO1xuY29uc3QgREVGQVVMVF9XT1JMRF9QUk9WSURFUiA9ICdGaWxlc3lzdGVtJztcblxuLyoqXG4gKiBUaGUgd29ybGQgbWFuYWdlciBpcyByZXNwb25zaWJsZSBsZXZlbCBsb2FkaW5nLCB1bmxvYWRpbmcsIGFuZCBnZW5lcmFsIGxldmVsIG1hbmFnZW1lbnQuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFdvcmxkTWFuYWdlciBpbXBsZW1lbnRzIFNlcnZpY2Uge1xuICAgIHByaXZhdGUgcmVhZG9ubHkgd29ybGRzOiBNYXA8c3RyaW5nLCBXb3JsZD4gPSBuZXcgTWFwKCkgYXMgTWFwPHN0cmluZywgV29ybGQ+O1xuICAgIHByaXZhdGUgZGVmYXVsdFdvcmxkOiBXb3JsZCB8IHVuZGVmaW5lZDtcbiAgICBwcml2YXRlIHJlYWRvbmx5IGdlbk1hbmFnZXI6IEdlbmVyYXRvck1hbmFnZXI7XG4gICAgcHJpdmF0ZSByZWFkb25seSBzZXJ2ZXI6IFNlcnZlcjtcbiAgICBwcml2YXRlIHByb3ZpZGVyczogTWFwPHN0cmluZywgYW55PiA9IG5ldyBNYXAoKSBhcyBNYXA8c3RyaW5nLCBhbnk+OyAvLyBUT0RPOiB0aGlzIHNob3VsZCBiZSBhIG1hbmFnZXJcblxuICAgIHB1YmxpYyBjb25zdHJ1Y3RvcihzZXJ2ZXI6IFNlcnZlcikge1xuICAgICAgICB0aGlzLnNlcnZlciA9IHNlcnZlcjtcbiAgICAgICAgdGhpcy5nZW5NYW5hZ2VyID0gbmV3IEdlbmVyYXRvck1hbmFnZXIoc2VydmVyKTtcblxuICAgICAgICAvLyBDcmVhdGUgdGhlIHdvcmxkcyBkaXJlY3RvcnkgaWYgaXQgZG9lc24ndCBleGlzdC5cbiAgICAgICAgaWYgKCFmcy5leGlzdHNTeW5jKHdpdGhDd2QoV09STERTX0ZPTERFUikpKSB7XG4gICAgICAgICAgICBmcy5ta2RpclN5bmMod2l0aEN3ZChXT1JMRFNfRk9MREVSKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBPbiBlbmFibGUgaG9vaywgZW5hYmxlcyB0aGUgbWFuYWdlciBhbmQgbG9hZCBhbGwgd29ybGRzLlxuICAgICAqIEBncm91cCBMaWZlY3ljbGVcbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgZW5hYmxlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB0aGlzLmFkZFByb3ZpZGVyKCdBbnZpbCcsIEFudmlsKTtcbiAgICAgICAgdGhpcy5hZGRQcm92aWRlcignRmlsZXN5c3RlbScsIEZpbGVzeXN0ZW0pO1xuXG4gICAgICAgIGNvbnN0IGRlZmF1bHRXb3JsZCA9IHRoaXMuc2VydmVyLmdldENvbmZpZygpLmdldExldmVsTmFtZSgpO1xuICAgICAgICBpZiAoIWRlZmF1bHRXb3JsZCkge1xuICAgICAgICAgICAgdGhpcy5zZXJ2ZXIuZ2V0TG9nZ2VyKCkud2FybihgSW52YWxpZCB3b3JsZCFgKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHdvcmxkRGF0YSA9IHRoaXMuc2VydmVyLmdldENvbmZpZygpLmdldFdvcmxkcygpW2RlZmF1bHRXb3JsZF07XG4gICAgICAgIGlmICghd29ybGREYXRhKSB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgbGV2ZWwtbmFtZWApO1xuXG4gICAgICAgIGF3YWl0IHRoaXMubG9hZFdvcmxkKHdvcmxkRGF0YSwgZGVmYXVsdFdvcmxkKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBPbiBkaXNhYmxlIGhvb2suXG4gICAgICpcbiAgICAgKiBTaWduaWZpZXMgdGhhdCB0aGUgbWFuYWdlciBpcyBiZWluZyBkaXNhYmxlZCBhbmQgYWxsIHdvcmxkcyBzaG91bGQgYmUgdW5sb2FkZWQuXG4gICAgICogQGdyb3VwIExpZmVjeWNsZVxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBkaXNhYmxlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbCh0aGlzLmdldFdvcmxkcygpLm1hcChhc3luYyAod29ybGQpID0+IHRoaXMudW5sb2FkV29ybGQod29ybGQuZ2V0TmFtZSgpKSkpO1xuICAgICAgICB0aGlzLnByb3ZpZGVycy5jbGVhcigpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFkZCBhIHByb3ZpZGVyIHRvIHRoZSBpbnRlcm5hbCBwcm92aWRlcnMgbWFwLlxuICAgICAqXG4gICAgICogQHBhcmFtIG5hbWUgLSB0aGUgbmFtZSBvZiB0aGUgcHJvdmlkZXIgQ0FTRSBTRU5TSVRJVkVcbiAgICAgKiBAcGFyYW0gcHJvdmlkZXIgLSB0aGUgcHJvdmlkZXJcbiAgICAgKi9cbiAgICBwdWJsaWMgYWRkUHJvdmlkZXIobmFtZTogc3RyaW5nLCBwcm92aWRlcjogYW55KSB7XG4gICAgICAgIHRoaXMucHJvdmlkZXJzLnNldChuYW1lLCBwcm92aWRlcik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlIGEgcHJvdmlkZXIgZnJvbSB0aGUgaW50ZXJuYWwgcHJvdmlkZXJzIG1hcC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBuYW1lIC0gdGhlIG5hbWUgb2YgdGhlIHByb3ZpZGVyIENBU0UgU0VOU0lUSVZFXG4gICAgICovXG4gICAgcHVibGljIHJlbW92ZVByb3ZpZGVyKG5hbWU6IHN0cmluZykge1xuICAgICAgICB0aGlzLnByb3ZpZGVycy5kZWxldGUobmFtZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGFsbCBwcm92aWRlcnMuXG4gICAgICovXG4gICAgcHVibGljIGdldFByb3ZpZGVycygpOiBNYXA8c3RyaW5nLCBQcm92aWRlcj4ge1xuICAgICAgICByZXR1cm4gdGhpcy5wcm92aWRlcnMgYXMgTWFwPHN0cmluZywgUHJvdmlkZXI+O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNhdmUgdGhlIHdvcmxkIHRvIGRpc2suXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIHNhdmUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMuc2VydmVyLmdldExvZ2dlcigpLmluZm8oJ1NhdmluZyB3b3JsZHMnKTtcbiAgICAgICAgZm9yIChjb25zdCB3b3JsZCBvZiB0aGlzLmdldFdvcmxkcygpKSB7XG4gICAgICAgICAgICBhd2FpdCB3b3JsZC5zYXZlKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBMb2FkIGEgd29ybGRcbiAgICAgKlxuICAgICAqIEBwYXJhbSB3b3JsZERhdGEgLSB0aGUgd29ybGQgZGF0YSBpbmNsdWRpbmcgcHJvdmlkZXIga2V5LCBnZW5lcmF0b3JcbiAgICAgKiBAcGFyYW0gZm9sZGVyTmFtZSAtIHRoZSBuYW1lIG9mIHRoZSBmb2xkZXIgY29udGFpbmluZyB0aGUgd29ybGRcbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgbG9hZFdvcmxkKHdvcmxkRGF0YTogV29ybGREYXRhLCBmb2xkZXJOYW1lOiBzdHJpbmcpOiBQcm9taXNlPFdvcmxkPiB7XG4gICAgICAgIGlmICghKHdvcmxkRGF0YSBhcyBhbnkpKSB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgd29ybGQgZGF0YScpO1xuXG4gICAgICAgIGlmICh0aGlzLmlzV29ybGRMb2FkZWQoZm9sZGVyTmFtZSkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgV29ybGQgJHtmb2xkZXJOYW1lfSBoYXMgYWxyZWFkeSBiZWVuIGxvYWRlZGApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgbGV2ZWxQYXRoID0gd2l0aEN3ZChXT1JMRFNfRk9MREVSLCBmb2xkZXJOYW1lKTtcbiAgICAgICAgY29uc3QgcHJvdmlkZXIgPSB0aGlzLnByb3ZpZGVycy5nZXQod29ybGREYXRhLnByb3ZpZGVyID8/IERFRkFVTFRfV09STERfUFJPVklERVIpO1xuICAgICAgICBjb25zdCBnZW5lcmF0b3IgPSB0aGlzLmdldEdlbmVyYXRvck1hbmFnZXIoKS5nZXRHZW5lcmF0b3Iod29ybGREYXRhLmdlbmVyYXRvciA/PyAnRmxhdCcpO1xuXG4gICAgICAgIGlmICghcHJvdmlkZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgaW52YWxpZCBwcm92aWRlciB3aXRoIGlkICR7d29ybGREYXRhLnByb3ZpZGVyfWApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgd29ybGQgPSBuZXcgV29ybGQoe1xuICAgICAgICAgICAgbmFtZTogZm9sZGVyTmFtZSxcbiAgICAgICAgICAgIHBhdGg6IGxldmVsUGF0aCxcbiAgICAgICAgICAgIHNlcnZlcjogdGhpcy5zZXJ2ZXIsXG4gICAgICAgICAgICBwcm92aWRlcjogbmV3IHByb3ZpZGVyKGxldmVsUGF0aCwgdGhpcy5zZXJ2ZXIpLFxuXG4gICAgICAgICAgICBzZWVkOiB3b3JsZERhdGEuc2VlZCxcbiAgICAgICAgICAgIGdlbmVyYXRvcixcbiAgICAgICAgICAgIGNvbmZpZzogd29ybGREYXRhXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLndvcmxkcy5zZXQod29ybGQuZ2V0VVVJRCgpLCB3b3JsZCk7XG5cbiAgICAgICAgLy8gRmlyc3QgbGV2ZWwgdG8gYmUgbG9hZGVkIGlzIGFsc28gdGhlIGRlZmF1bHQgb25lXG4gICAgICAgIGlmICghdGhpcy5kZWZhdWx0V29ybGQpIHtcbiAgICAgICAgICAgIHRoaXMuZGVmYXVsdFdvcmxkID0gdGhpcy53b3JsZHMuZ2V0KHdvcmxkLmdldFVVSUQoKSkhO1xuICAgICAgICAgICAgdGhpcy5zZXJ2ZXIuZ2V0TG9nZ2VyKCkuaW5mbyhgTG9hZGluZyAke3dvcmxkLmdldEZvcm1hdHRlZE5hbWUoKX0gYXMgZGVmYXVsdCB3b3JsZCFgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGF3YWl0IHdvcmxkLmVuYWJsZSgpO1xuICAgICAgICB0aGlzLnNlcnZlci5nZXRMb2dnZXIoKS52ZXJib3NlKGBXb3JsZCAke3dvcmxkLmdldEZvcm1hdHRlZE5hbWUoKX0gc3VjY2Vzc2Z1bGx5IGxvYWRlZCFgKTtcblxuICAgICAgICByZXR1cm4gd29ybGQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVW5sb2FkcyBhIGxldmVsIGJ5IGl0cyBmb2xkZXIgbmFtZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgdW5sb2FkV29ybGQoZm9sZGVyTmFtZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICghdGhpcy5pc1dvcmxkTG9hZGVkKGZvbGRlck5hbWUpKSB7XG4gICAgICAgICAgICB0aGlzLnNlcnZlci5nZXRMb2dnZXIoKS5lcnJvcihgQ2Fubm90IHVubG9hZCBhIG5vdCBsb2FkZWQgd29ybGQgd2l0aCBuYW1lIMKnYiR7Zm9sZGVyTmFtZX1gKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHdvcmxkID0gdGhpcy5nZXRXb3JsZEJ5TmFtZShmb2xkZXJOYW1lKTtcbiAgICAgICAgaWYgKCF3b3JsZCkge1xuICAgICAgICAgICAgdGhpcy5zZXJ2ZXIuZ2V0TG9nZ2VyKCkuZXJyb3IoYENhbm5vdCB1bmxvYWQgd29ybGQgJHtmb2xkZXJOYW1lfWApO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgYXdhaXQgd29ybGQuZGlzYWJsZSgpO1xuICAgICAgICB0aGlzLndvcmxkcy5kZWxldGUod29ybGQuZ2V0VVVJRCgpKTtcbiAgICAgICAgdGhpcy5zZXJ2ZXIuZ2V0TG9nZ2VyKCkudmVyYm9zZShgU3VjY2Vzc2Z1bGx5IHVubG9hZGVkIHdvcmxkICR7d29ybGQuZ2V0Rm9ybWF0dGVkTmFtZSgpfSFgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHdoYXRldmVyIHRoZSB3b3JsZCBpcyBsb2FkZWQgb3Igbm90LlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSB0cnVlIGlmIHRoZSB3b3JsZCBpcyBsb2FkZWQsIGZhbHNlIG90aGVyd2lzZVxuICAgICAqL1xuICAgIHB1YmxpYyBpc1dvcmxkTG9hZGVkKGZvbGRlck5hbWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgICAgICBjb25zdCB3b3JsZCA9IEFycmF5LmZyb20odGhpcy53b3JsZHMudmFsdWVzKCkpLmZpbmQoXG4gICAgICAgICAgICAod29ybGQpID0+IHdvcmxkLmdldE5hbWUoKS50b0xvd2VyQ2FzZSgpID09PSBmb2xkZXJOYW1lLnRvTG93ZXJDYXNlKClcbiAgICAgICAgKTtcblxuICAgICAgICBpZiAod29ybGQpIHJldHVybiB0cnVlO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhIHdvcmxkIGJ5IGl0cyBmb2xkZXIgbmFtZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0V29ybGRCeU5hbWUoZm9sZGVyTmFtZTogc3RyaW5nKTogV29ybGQgfCBudWxsIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0V29ybGRzKCkuZmluZCgod29ybGQpID0+IHdvcmxkLmdldE5hbWUoKS50b0xvd2VyQ2FzZSgpID09PSBmb2xkZXJOYW1lLnRvTG93ZXJDYXNlKCkpID8/IG51bGw7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhbiBhcnJheSB3aXRoIGFsbCB3b3JsZHMuXG4gICAgICovXG4gICAgcHVibGljIGdldFdvcmxkcygpOiBXb3JsZFtdIHtcbiAgICAgICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy53b3JsZHMudmFsdWVzKCkpO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXREZWZhdWx0V29ybGQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmRlZmF1bHRXb3JsZCA/PyB0aGlzLmdldFdvcmxkcygpWzBdO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRHZW5lcmF0b3JNYW5hZ2VyKCk6IEdlbmVyYXRvck1hbmFnZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5nZW5NYW5hZ2VyO1xuICAgIH1cbn1cbiJdLCJuYW1lcyI6WyJHZW5lcmF0b3JNYW5hZ2VyIiwiZnMiLCJ3aXRoQ3dkIiwiQW52aWwiLCJGaWxlc3lzdGVtIiwiV29ybGQiLCJ3b3JsZCJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFvQkEsTUFBTSxhQUFnQixHQUFBLFFBQUE7QUFDdEIsTUFBTSxzQkFBeUIsR0FBQSxZQUFBO0FBSy9CLE1BQXFCLFlBQWdDLENBQUE7QUFBQSxFQUNoQyxNQUFBLHVCQUFpQyxHQUFJLEVBQUE7QUFBQSxFQUM5QyxZQUFBO0FBQUEsRUFDUyxVQUFBO0FBQUEsRUFDQSxNQUFBO0FBQUEsRUFDVCxTQUFBLHVCQUFrQyxHQUFJLEVBQUE7QUFBQTtBQUFBLEVBRXZDLFlBQVksTUFBZ0IsRUFBQTtBQUMvQixJQUFBLElBQUEsQ0FBSyxN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