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