@jsprismarine/prismarine
Version:
Dedicated Minecraft Bedrock Edition server written in TypeScript
185 lines (184 loc) • 27.4 kB
JavaScript
import Timer from "../utils/Timer.es.js";
import CommandRegisterEvent from "../events/command/CommandRegisterEvent.es.js";
import { Chat } from "../chat/Chat.es.js";
import { Commands_exports } from "./Commands.es.js";
import { CommandRegisterClassMalformedOrMissingError, CommandUnknownCommandError, Error, GenericNamespaceInvalidError } from "@jsprismarine/errors";
import { CommandDispatcher, CommandSyntaxException } from "@jsprismarine/brigadier";
//#region src/command/CommandManager.ts
var CommandManager = class {
commands = /* @__PURE__ */ new Map();
server;
dispatcher;
constructor(server) {
this.server = server;
this.dispatcher = new CommandDispatcher();
}
/**
* On enable hook.
* @group Lifecycle
*/
async enable() {
const timer = new Timer();
const commands = Object.keys(Commands_exports).map((key) => Commands_exports[key]);
await Promise.all(commands.map(async (Command) => {
const command = new Command({});
const event = new CommandRegisterEvent(command);
await this.server.emit("commandRegister", event);
if (event.isCancelled()) return;
try {
await this.registerCommand(command);
} catch (error) {
this.server.getLogger().error(error);
this.server.getLogger().warn(`Failed to register command ${command.id}`);
}
}));
this.server.getLogger().verbose(`Registered §b${this.commands.size}§r commands(s) (took §e${timer.stop()} ms§r)!`);
}
/**
* On disable hook.
* @group Lifecycle
*/
async disable() {
this.commands.clear();
}
/**
* Register a command into command manager by class.
* @param {Command} [command] - The command class to register
*/
async registerCommand(command) {
if (!command || !command.id) throw new CommandRegisterClassMalformedOrMissingError();
if (command.id.split(":").length !== 2) throw new GenericNamespaceInvalidError();
if (!command.register) this.server.getLogger().warn(`Command is missing "register" member. This is unsupported!`);
else await command.register(this.dispatcher);
this.commands.set(command.id, command);
await Promise.all(this.server.getSessionManager().getAllPlayers().map(async (player) => player.getNetworkSession().sendAvailableCommands()));
this.server.getLogger().debug(`Command with id §b${command.id}§r registered`);
}
/**
* Get a registered command by ID.
* @remarks This is case-insensitive, works with or without namespace, and also with aliases.
* @param {string} id - The command ID.
* @returns {Command} The command if found, otherwise undefined.
*/
getCommand(id) {
const command = Array.from(this.commands.values()).find((command) => command.name === id || command.aliases?.includes(id) || command.id === id);
if (!command) throw new CommandUnknownCommandError();
return command;
}
/**
* Get all enabled commands.
*/
getCommands() {
return this.commands;
}
/**
* Get a list of all command variants.
*
* @remarks
* This is EXCLUDING legacy commands.
*/
getCommandsList() {
const parseNode = (node) => {
if (node.getChildrenCount() <= 0) return [{
item: node.getType(),
children: []
}];
const res = Array.from(node.getChildren()).map((node) => parseNode(node)).reverse();
return [node.getCommand() ? {
item: node.getType(),
children: []
} : void 0, ...res.map((children) => ({
item: node.getType(),
children: [...children]
}))].filter((a) => a);
};
const traverse = (node, path = [], result = []) => {
if (!node.children.length) result.push(path.concat(node.item));
for (const child of node.children) traverse(child, path.concat(node.item), result);
return result;
};
const res = Array.from(this.server.getCommandManager().getDispatcher().getRoot().getChildren()).flatMap((command) => {
const branches = [];
if (command.getCommand()) branches.push([]);
Array.from(command.getChildren()).forEach((node) => {
parseNode(node).forEach((branch) => {
branches.push(traverse(branch));
});
});
return branches.map((branch) => [
command.getName(),
command,
branch
]);
}).filter((a) => a);
res.toString = () => {
return `${this.getCommandsList().map((item) => {
if (!item[2].length) return `/${item[0]}`;
return item[2].map((entries) => `/${item[0]} ${entries.flat(Number.POSITIVE_INFINITY).map((argument) => argument.getReadableType?.() ?? argument.constructor.name).join(" ")}`).join(`\n`);
}).join("\n")}`;
};
return res;
}
/**
* Get dispatcher
*/
getDispatcher() {
return this.dispatcher;
}
/**
* Dispatches a command and executes them.
*
* @param sender - the player/console who executed the command
* @param target - the Player/entity/console who should execute the command
* @param input - the command input including arguments
*/
async dispatchCommand(sender, target, input = "") {
try {
if (input.startsWith("/")) input = input.slice(1);
const parsed = this.dispatcher.parse(input.trim(), target);
const id = parsed.getReader().getString().split(" ")[0];
if (!sender.isConsole()) this.server.getLogger().debug(`Entity with §b${sender.getRuntimeId()}§r is dispatching command: ${input} (id: ${id})`, "CommandManager/dispatchCommand");
const command = this.getCommand(id);
if (!this.server.getPermissionManager().can(sender).execute(command.permission)) {
await sender.sendMessage("§cI'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is in error.");
return;
}
let res = [];
if (command.name !== id) {
await this.dispatchCommand(sender, target, input.replace(id, command.name));
return;
}
res = await Promise.all(this.dispatcher.execute(parsed));
if (!sender.getWorld().getGameruleManager().getGamerule("sendCommandFeedback")) return;
await Promise.all(res.map(async (res) => {
const chat = new Chat({
sender: this.server.getConsole(),
message: `§o§7[${target.getName()}: ${res ?? `issued server command: /${input}`}]§r`,
channel: "*.ops"
});
await this.server.getChatManager().send(chat);
}));
} catch (error) {
switch (true) {
case error instanceof CommandSyntaxException:
await sender.sendMessage(`§c${error.getMessage()}`);
return;
case error instanceof CommandUnknownCommandError:
await sender.sendMessage(`§cUnknown command. Type "/help" for help.`);
return;
case error instanceof Error:
await sender.sendMessage(`§c${error.message}`);
return;
default:
this.server.getLogger().error(error);
break;
}
await sender.sendMessage(`§c${error}`);
this.server.getLogger().debug(`Player ${target.getFormattedUsername()} tried to execute ${input}, but it failed with the error: ${error}`, "CommandManager/dispatchCommand");
this.server.getLogger().error(error);
}
}
};
//#endregion
export { CommandManager };
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29tbWFuZE1hbmFnZXIuZXMuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1hbmQvQ29tbWFuZE1hbmFnZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBBcmd1bWVudENvbW1hbmROb2RlIH0gZnJvbSAnQGpzcHJpc21hcmluZS9icmlnYWRpZXInO1xuaW1wb3J0IHsgQ29tbWFuZERpc3BhdGNoZXIsIENvbW1hbmRTeW50YXhFeGNlcHRpb24gfSBmcm9tICdAanNwcmlzbWFyaW5lL2JyaWdhZGllcic7XG5pbXBvcnQge1xuICAgIENvbW1hbmRSZWdpc3RlckNsYXNzTWFsZm9ybWVkT3JNaXNzaW5nRXJyb3IsXG4gICAgQ29tbWFuZFVua25vd25Db21tYW5kRXJyb3IsXG4gICAgRXJyb3IsXG4gICAgR2VuZXJpY05hbWVzcGFjZUludmFsaWRFcnJvclxufSBmcm9tICdAanNwcmlzbWFyaW5lL2Vycm9ycyc7XG5cbmltcG9ydCB0eXBlIHsgQ29tbWFuZCwgQ29tbWFuZEFyZ3VtZW50LCBFbnRpdHksIFBsYXllciwgU2VydmVyLCBTZXJ2aWNlIH0gZnJvbSAnLi4vJztcbmltcG9ydCB7IENoYXQgfSBmcm9tICcuLi8nO1xuaW1wb3J0IENvbW1hbmRSZWdpc3RlckV2ZW50IGZyb20gJy4uL2V2ZW50cy9jb21tYW5kL0NvbW1hbmRSZWdpc3RlckV2ZW50JztcbmltcG9ydCBUaW1lciBmcm9tICcuLi91dGlscy9UaW1lcic7XG5pbXBvcnQgeyBDb21tYW5kcyB9IGZyb20gJy4vJztcblxuZXhwb3J0IGNsYXNzIENvbW1hbmRNYW5hZ2VyIGltcGxlbWVudHMgU2VydmljZSB7XG4gICAgcHJpdmF0ZSByZWFkb25seSBjb21tYW5kczogTWFwPHN0cmluZywgQ29tbWFuZD4gPSBuZXcgTWFwKCk7XG4gICAgcHJpdmF0ZSByZWFkb25seSBzZXJ2ZXI6IFNlcnZlcjtcbiAgICBwcml2YXRlIGRpc3BhdGNoZXIhOiBDb21tYW5kRGlzcGF0Y2hlcjxQbGF5ZXI+O1xuXG4gICAgcHVibGljIGNvbnN0cnVjdG9yKHNlcnZlcjogU2VydmVyKSB7XG4gICAgICAgIHRoaXMuc2VydmVyID0gc2VydmVyO1xuICAgICAgICB0aGlzLmRpc3BhdGNoZXIgPSBuZXcgQ29tbWFuZERpc3BhdGNoZXIoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBPbiBlbmFibGUgaG9vay5cbiAgICAgKiBAZ3JvdXAgTGlmZWN5Y2xlXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIGVuYWJsZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgdGltZXIgPSBuZXcgVGltZXIoKTtcblxuICAgICAgICBjb25zdCBjb21tYW5kcyA9IE9iamVjdC5rZXlzKENvbW1hbmRzKS5tYXAoKGtleSkgPT4gKENvbW1hbmRzIGFzIGFueSlba2V5XSBhcyB0eXBlb2YgQ29tbWFuZCk7XG5cbiAgICAgICAgLy8gUmVnaXN0ZXIganNwcmlzbWFyaW5lIGNvbW1hbmRzXG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICAgICAgY29tbWFuZHMubWFwKGFzeW5jIChDb21tYW5kKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgY29tbWFuZDogQ29tbWFuZCA9IG5ldyBDb21tYW5kKHt9IGFzIGFueSk7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBldmVudCA9IG5ldyBDb21tYW5kUmVnaXN0ZXJFdmVudChjb21tYW5kKTtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnNlcnZlci5lbWl0KCdjb21tYW5kUmVnaXN0ZXInLCBldmVudCk7XG4gICAgICAgICAgICAgICAgaWYgKGV2ZW50LmlzQ2FuY2VsbGVkKCkpIHJldHVybjtcblxuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucmVnaXN0ZXJDb21tYW5kKGNvbW1hbmQpO1xuICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2VydmVyLmdldExvZ2dlcigpLmVycm9yKGVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXJ2ZXIuZ2V0TG9nZ2VyKCkud2FybihgRmFpbGVkIHRvIHJlZ2lzdGVyIGNvbW1hbmQgJHtjb21tYW5kLmlkfWApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5zZXJ2ZXJcbiAgICAgICAgICAgIC5nZXRMb2dnZXIoKVxuICAgICAgICAgICAgLnZlcmJvc2UoYFJlZ2lzdGVyZWQgwqdiJHt0aGlzLmNvbW1hbmRzLnNpemV9wqdyIGNvbW1hbmRzKHMpICh0b29rIMKnZSR7dGltZXIuc3RvcCgpfSBtc8KncikhYCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogT24gZGlzYWJsZSBob29rLlxuICAgICAqIEBncm91cCBMaWZlY3ljbGVcbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgZGlzYWJsZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdGhpcy5jb21tYW5kcy5jbGVhcigpO1xuICAgICAgICAvLyBUT0RPOiBjbGVhciBjb21tYW5kcyBpbiBkaXNwYXRjaGVyXG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVnaXN0ZXIgYSBjb21tYW5kIGludG8gY29tbWFuZCBtYW5hZ2VyIGJ5IGNsYXNzLlxuICAgICAqIEBwYXJhbSB7Q29tbWFuZH0gW2NvbW1hbmRdIC0gVGhlIGNvbW1hbmQgY2xhc3MgdG8gcmVnaXN0ZXJcbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgcmVnaXN0ZXJDb21tYW5kKGNvbW1hbmQ/OiBDb21tYW5kKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICghY29tbWFuZCB8fCAhY29tbWFuZC5pZCkgdGhyb3cgbmV3IENvbW1hbmRSZWdpc3RlckNsYXNzTWFsZm9ybWVkT3JNaXNzaW5nRXJyb3IoKTtcbiAgICAgICAgaWYgKGNvbW1hbmQuaWQuc3BsaXQoJzonKS5sZW5ndGggIT09IDIpIHRocm93IG5ldyBHZW5lcmljTmFtZXNwYWNlSW52YWxpZEVycm9yKCk7XG5cbiAgICAgICAgaWYgKCEoY29tbWFuZCBhcyBhbnkpLnJlZ2lzdGVyKVxuICAgICAgICAgICAgdGhpcy5zZXJ2ZXIuZ2V0TG9nZ2VyKCkud2FybihgQ29tbWFuZCBpcyBtaXNzaW5nIFwicmVnaXN0ZXJcIiBtZW1iZXIuIFRoaXMgaXMgdW5zdXBwb3J0ZWQhYCk7XG4gICAgICAgIGVsc2UgYXdhaXQgY29tbWFuZC5yZWdpc3Rlcih0aGlzLmRpc3BhdGNoZXIpO1xuICAgICAgICB0aGlzLmNvbW1hbmRzLnNldChjb21tYW5kLmlkLCBjb21tYW5kKTtcblxuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgICAgIHRoaXMuc2VydmVyXG4gICAgICAgICAgICAgICAgLmdldFNlc3Npb25NYW5hZ2VyKClcbiAgICAgICAgICAgICAgICAuZ2V0QWxsUGxheWVycygpXG4gICAgICAgICAgICAgICAgLm1hcChhc3luYyAocGxheWVyKSA9PiBwbGF5ZXIuZ2V0TmV0d29ya1Nlc3Npb24oKS5zZW5kQXZhaWxhYmxlQ29tbWFuZHMoKSlcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLnNlcnZlci5nZXRMb2dnZXIoKS5kZWJ1ZyhgQ29tbWFuZCB3aXRoIGlkIMKnYiR7Y29tbWFuZC5pZH3Cp3IgcmVnaXN0ZXJlZGApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCBhIHJlZ2lzdGVyZWQgY29tbWFuZCBieSBJRC5cbiAgICAgKiBAcmVtYXJrcyBUaGlzIGlzIGNhc2UtaW5zZW5zaXRpdmUsIHdvcmtzIHdpdGggb3Igd2l0aG91dCBuYW1lc3BhY2UsIGFuZCBhbHNvIHdpdGggYWxpYXNlcy5cbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gaWQgLSBUaGUgY29tbWFuZCBJRC5cbiAgICAgKiBAcmV0dXJucyB7Q29tbWFuZH0gVGhlIGNvbW1hbmQgaWYgZm91bmQsIG90aGVyd2lzZSB1bmRlZmluZWQuXG4gICAgICovXG4gICAgcHVibGljIGdldENvbW1hbmQoaWQ6IHN0cmluZyk6IENvbW1hbmQge1xuICAgICAgICBjb25zdCBjb21tYW5kID0gQXJyYXkuZnJvbSh0aGlzLmNvbW1hbmRzLnZhbHVlcygpKS5maW5kKFxuICAgICAgICAgICAgKGNvbW1hbmQpID0+XG4gICAgICAgICAgICAgICAgLy8gQ2hlY2sgaWYgaXQgbWF0Y2hlcyBJRCB3aXRob3V0IG5hbWVzcGFjZS5cbiAgICAgICAgICAgICAgICBjb21tYW5kLm5hbWUgPT09IGlkIHx8XG4gICAgICAgICAgICAgICAgLy8gQ2hlY2sgaWYgaXQncyBhbiBhbGlhcy5cbiAgICAgICAgICAgICAgICBjb21tYW5kLmFsaWFzZXM/LmluY2x1ZGVzKGlkKSB8fFxuICAgICAgICAgICAgICAgIC8vIExhc3QgY2hlY2sgaWYgaXQncyB0aGUgd2hvbGUgSUQgKHRoaXMgaXMgdW5jb21tb24gc28sXG4gICAgICAgICAgICAgICAgLy8gIGl0J3MgbGFzdCB0byBhdm9pZCB0aGUgbW9zdCBjaGVja3MpLlxuICAgICAgICAgICAgICAgIGNvbW1hbmQuaWQgPT09IGlkXG4gICAgICAgICk7XG5cbiAgICAgICAgaWYgKCFjb21tYW5kKSB0aHJvdyBuZXcgQ29tbWFuZFVua25vd25Db21tYW5kRXJyb3IoKTtcbiAgICAgICAgcmV0dXJuIGNvbW1hbmQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGFsbCBlbmFibGVkIGNvbW1hbmRzLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRDb21tYW5kcygpOiBNYXA8c3RyaW5nLCBDb21tYW5kPiB7XG4gICAgICAgIHJldHVybiB0aGlzLmNvbW1hbmRzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCBhIGxpc3Qgb2YgYWxsIGNvbW1hbmQgdmFyaWFudHMuXG4gICAgICpcbiAgICAgKiBAcmVtYXJrc1xuICAgICAqIFRoaXMgaXMgRVhDTFVESU5HIGxlZ2FjeSBjb21tYW5kcy5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0Q29tbWFuZHNMaXN0KCk6IEFycmF5PFtzdHJpbmcsIC8qIENvbW1hbmROb2RlPFBsYXllcj4gKi8gYW55LCBDb21tYW5kQXJndW1lbnRbXVtdXT4ge1xuICAgICAgICBjb25zdCBwYXJzZU5vZGUgPSAobm9kZTogLyogQ29tbWFuZE5vZGU8UGxheWVyPiAqLyBhbnkpOiBhbnlbXSA9PiB7XG4gICAgICAgICAgICBpZiAobm9kZS5nZXRDaGlsZHJlbkNvdW50KCkgPD0gMCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGl0ZW06IChub2RlIGFzIEFyZ3VtZW50Q29tbWFuZE5vZGU8YW55LCBhbnk+KS5nZXRUeXBlKCksXG4gICAgICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbjogW11cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIF07XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0IHJlcyA9IEFycmF5LmZyb20obm9kZS5nZXRDaGlsZHJlbigpKVxuICAgICAgICAgICAgICAgIC5tYXAoKG5vZGUpID0+IHBhcnNlTm9kZShub2RlKSlcbiAgICAgICAgICAgICAgICAucmV2ZXJzZSgpO1xuXG4gICAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgICAgIG5vZGUuZ2V0Q29tbWFuZCgpXG4gICAgICAgICAgICAgICAgICAgID8ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBpdGVtOiAobm9kZSBhcyBBcmd1bWVudENvbW1hbmROb2RlPGFueSwgYW55PikuZ2V0VHlwZSgpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBjaGlsZHJlbjogW11cbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIC4uLnJlcy5tYXAoKGNoaWxkcmVuOiBhbnkpID0+ICh7XG4gICAgICAgICAgICAgICAgICAgIGl0ZW06IChub2RlIGFzIEFyZ3VtZW50Q29tbWFuZE5vZGU8YW55LCBhbnk+KS5nZXRUeXBlKCksXG4gICAgICAgICAgICAgICAgICAgIGNoaWxkcmVuOiBbLi4uY2hpbGRyZW5dXG4gICAgICAgICAgICAgICAgfSkpXG4gICAgICAgICAgICBdLmZpbHRlcigoYSkgPT4gYSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgY29uc3QgdHJhdmVyc2UgPSAobm9kZTogYW55LCBwYXRoOiBhbnlbXSA9IFtdLCByZXN1bHQ6IGFueVtdID0gW10pID0+IHtcbiAgICAgICAgICAgIGlmICghbm9kZS5jaGlsZHJlbi5sZW5ndGgpIHJlc3VsdC5wdXNoKHBhdGguY29uY2F0KG5vZGUuaXRlbSkpO1xuICAgICAgICAgICAgZm9yIChjb25zdCBjaGlsZCBvZiBub2RlLmNoaWxkcmVuKSB0cmF2ZXJzZShjaGlsZCwgcGF0aC5jb25jYXQobm9kZS5pdGVtKSwgcmVzdWx0KTtcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH07XG5cbiAgICAgICAgY29uc3QgcmVzID0gQXJyYXkuZnJvbSh0aGlzLnNlcnZlci5nZXRDb21tYW5kTWFuYWdlcigpLmdldERpc3BhdGNoZXIoKS5nZXRSb290KCkuZ2V0Q2hpbGRyZW4oKSlcbiAgICAgICAgICAgIC5mbGF0TWFwKChjb21tYW5kKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgYnJhbmNoZXM6IGFueVtdID0gW107XG4gICAgICAgICAgICAgICAgaWYgKGNvbW1hbmQuZ2V0Q29tbWFuZCgpKSBicmFuY2hlcy5wdXNoKFtdKTtcblxuICAgICAgICAgICAgICAgIEFycmF5LmZyb20oY29tbWFuZC5nZXRDaGlsZHJlbigpKS5mb3JFYWNoKChub2RlKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHBhcnNlZCA9IHBhcnNlTm9kZShub2RlKTtcbiAgICAgICAgICAgICAgICAgICAgcGFyc2VkLmZvckVhY2goKGJyYW5jaCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJhbmNoZXMucHVzaCh0cmF2ZXJzZShicmFuY2gpKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gYnJhbmNoZXMubWFwKChicmFuY2gpID0+IFtjb21tYW5kLmdldE5hbWUoKSwgY29tbWFuZCwgYnJhbmNoXSk7XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLmZpbHRlcigoYSkgPT4gYSBhcyBhbnkpO1xuXG4gICAgICAgIHJlcy50b1N0cmluZyA9ICgpID0+IHtcbiAgICAgICAgICAgIHJldHVybiBgJHt0aGlzLmdldENvbW1hbmRzTGlzdCgpXG4gICAgICAgICAgICAgICAgLm1hcCgoaXRlbSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIWl0ZW1bMl0ubGVuZ3RoKSByZXR1cm4gYC8ke2l0ZW1bMF19YDtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGl0ZW1bMl1cbiAgICAgICAgICAgICAgICAgICAgICAgIC5tYXAoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKGVudHJpZXMpID0+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGAvJHtpdGVtWzBdfSAke2VudHJpZXNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5mbGF0KE51bWJlci5QT1NJVElWRV9JTkZJTklUWSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5tYXAoKGFyZ3VtZW50OiBhbnkpID0+IGFyZ3VtZW50LmdldFJlYWRhYmxlVHlwZT8uKCkgPz8gYXJndW1lbnQuY29uc3RydWN0b3IubmFtZSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5qb2luKCcgJyl9YFxuICAgICAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgICAgICAgLmpvaW4oYFxcbmApO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmpvaW4oJ1xcbicpfWA7XG4gICAgICAgIH07XG4gICAgICAgIHJldHVybiByZXMgYXMgYW55O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCBkaXNwYXRjaGVyXG4gICAgICovXG4gICAgcHVibGljIGdldERpc3BhdGNoZXIoKTogQ29tbWFuZERpc3BhdGNoZXI8UGxheWVyPiB7XG4gICAgICAgIHJldHVybiB0aGlzLmRpc3BhdGNoZXI7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRGlzcGF0Y2hlcyBhIGNvbW1hbmQgYW5kIGV4ZWN1dGVzIHRoZW0uXG4gICAgICpcbiAgICAgKiBAcGFyYW0gc2VuZGVyIC0gdGhlIHBsYXllci9jb25zb2xlIHdobyBleGVjdXRlZCB0aGUgY29tbWFuZFxuICAgICAqIEBwYXJhbSB0YXJnZXQgLSB0aGUgUGxheWVyL2VudGl0eS9jb25zb2xlIHdobyBzaG91bGQgZXhlY3V0ZSB0aGUgY29tbWFuZFxuICAgICAqIEBwYXJhbSBpbnB1dCAtIHRoZSBjb21tYW5kIGlucHV0IGluY2x1ZGluZyBhcmd1bWVudHNcbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgZGlzcGF0Y2hDb21tYW5kKHNlbmRlcjogUGxheWVyLCB0YXJnZXQ6IEVudGl0eSB8IFBsYXllciwgaW5wdXQgPSAnJykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgaWYgKGlucHV0LnN0YXJ0c1dpdGgoJy8nKSkgaW5wdXQgPSBpbnB1dC5zbGljZSgxKTtcblxuICAgICAgICAgICAgY29uc3QgcGFyc2VkID0gdGhpcy5kaXNwYXRjaGVyLnBhcnNlKGlucHV0LnRyaW0oKSwgdGFyZ2V0IGFzIFBsYXllcik7XG4gICAgICAgICAgICBjb25zdCBpZCA9IHBhcnNlZC5nZXRSZWFkZXIoKS5nZXRTdHJpbmcoKS5zcGxpdCgnICcpWzBdITtcblxuICAgICAgICAgICAgaWYgKCFzZW5kZXIuaXNDb25zb2xlKCkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNlcnZlclxuICAgICAgICAgICAgICAgICAgICAuZ2V0TG9nZ2VyKClcbiAgICAgICAgICAgICAgICAgICAgLmRlYnVnKFxuICAgICAgICAgICAgICAgICAgICAgICAgYEVudGl0eSB3aXRoIMKnYiR7c2VuZGVyLmdldFJ1bnRpbWVJZCgpfcKnciBpcyBkaXNwYXRjaGluZyBjb21tYW5kOiAke2lucHV0fSAoaWQ6ICR7aWR9KWAsXG4gICAgICAgICAgICAgICAgICAgICAgICAnQ29tbWFuZE1hbmFnZXIvZGlzcGF0Y2hDb21tYW5kJ1xuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBHZXQgY29tbWFuZCBmcm9tIHBhcnNlZCBzdHJpbmcuXG4gICAgICAgICAgICBjb25zdCBjb21tYW5kID0gdGhpcy5nZXRDb21tYW5kKGlkKTtcblxuICAgICAgICAgICAgLy8gVmFsaWRhdGUgcGVybWlzc2lvbnMuXG4gICAgICAgICAgICBpZiAoIXRoaXMuc2VydmVyLmdldFBlcm1pc3Npb25NYW5hZ2VyKCkuY2FuKHNlbmRlcikuZXhlY3V0ZShjb21tYW5kLnBlcm1pc3Npb24pKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgc2VuZGVyLnNlbmRNZXNzYWdlKFxuICAgICAgICAgICAgICAgICAgICBcIsKnY0knbSBzb3JyeSwgYnV0IHlvdSBkbyBub3QgaGF2ZSBwZXJtaXNzaW9uIHRvIHBlcmZvcm0gdGhpcyBjb21tYW5kLiBcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICAnUGxlYXNlIGNvbnRhY3QgdGhlIHNlcnZlciBhZG1pbmlzdHJhdG9ycyBpZiB5b3UgYmVsaWV2ZSB0aGF0IHRoaXMgaXMgaW4gZXJyb3IuJ1xuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsZXQgcmVzOiBzdHJpbmdbXSA9IFtdO1xuICAgICAgICAgICAgLy8gSGFuZGxlIGFsaWFzZXMgYW5kIElEcy5cbiAgICAgICAgICAgIGlmIChjb21tYW5kLm5hbWUgIT09IGlkKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5kaXNwYXRjaENvbW1hbmQoc2VuZGVyLCB0YXJnZXQsIGlucHV0LnJlcGxhY2UoaWQsIGNvbW1hbmQubmFtZSkpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmVzID0gYXdhaXQgUHJvbWlzZS5hbGwodGhpcy5kaXNwYXRjaGVyLmV4ZWN1dGUocGFyc2VkKSk7XG5cbiAgICAgICAgICAgIGNvbnN0IGZlZWRiYWNrID0gKHNlbmRlciBhcyBhbnkgYXMgRW50aXR5KVxuICAgICAgICAgICAgICAgIC5nZXRXb3JsZCgpXG4gICAgICAgICAgICAgICAgLmdldEdhbWVydWxlTWFuYWdlcigpXG4gICAgICAgICAgICAgICAgLmdldEdhbWVydWxlKCdzZW5kQ29tbWFuZEZlZWRiYWNrJyk7XG5cbiAgICAgICAgICAgIC8vIE1ha2Ugc3VyZSB3ZSBkb24ndCBzZW5kIGZlZWRiYWNrIGlmIHNlbmRDb21tYW5kRmVlZGJhY2sgaXMgc2V0IHRvIGZhbHNlXG4gICAgICAgICAgICBpZiAoIWZlZWRiYWNrKSByZXR1cm47XG5cbiAgICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICAgICAgICAgIHJlcy5tYXAoYXN5bmMgKHJlczogYW55KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGNoYXQgPSBuZXcgQ2hhdCh7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZW5kZXI6IHRoaXMuc2VydmVyLmdldENvbnNvbGUoKSEsXG4gICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBgwqdvwqc3WyR7dGFyZ2V0LmdldE5hbWUoKX06ICR7cmVzID8/IGBpc3N1ZWQgc2VydmVyIGNvbW1hbmQ6IC8ke2lucHV0fWB9XcKncmAsXG4gICAgICAgICAgICAgICAgICAgICAgICBjaGFubmVsOiAnKi5vcHMnXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIFRPRE86IHNob3VsZCB0aGlzIGJlIGJyb2FkY2FzdGVkIHRvIHRoZSBleGVjdXRlcj9cbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5zZXJ2ZXIuZ2V0Q2hhdE1hbmFnZXIoKS5zZW5kKGNoYXQpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICApO1xuICAgICAgICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgICAgICAgICAgc3dpdGNoICh0cnVlKSB7XG4gICAgICAgICAgICAgICAgY2FzZSBlcnJvciBpbnN0YW5jZW9mIENvbW1hbmRTeW50YXhFeGNlcHRpb246XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHNlbmRlci5zZW5kTWVzc2FnZShgwqdjJHtlcnJvci5nZXRNZXNzYWdlKCl9YCk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICBjYXNlIGVycm9yIGluc3RhbmNlb2YgQ29tbWFuZFVua25vd25Db21tYW5kRXJyb3I6XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHNlbmRlci5zZW5kTWVzc2FnZShgwqdjVW5rbm93biBjb21tYW5kLiBUeXBlIFwiL2hlbHBcIiBmb3IgaGVscC5gKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIGNhc2UgZXJyb3IgaW5zdGFuY2VvZiBFcnJvcjpcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgc2VuZGVyLnNlbmRNZXNzYWdlKGDCp2Mke2Vycm9yLm1lc3NhZ2V9YCk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgICAgICB0aGlzLnNlcnZlci5nZXRMb2dnZXIoKS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBhd2FpdCBzZW5kZXIuc2VuZE1lc3NhZ2UoYMKnYyR7ZXJyb3J9YCk7XG4gICAgICAgICAgICB0aGlzLnNlcnZlclxuICAgICAgICAgICAgICAgIC5nZXRMb2dnZXIoKVxuICAgICAgICAgICAgICAgIC5kZWJ1ZyhcbiAgICAgICAgICAgICAgICAgICAgYFBsYXllciAke3RhcmdldC5nZXRGb3JtYXR0ZWRVc2VybmFtZSgpfSB0cmllZCB0byBleGVjdXRlICR7aW5wdXR9LCBidXQgaXQgZmFpbGVkIHdpdGggdGhlIGVycm9yOiAke2Vycm9yfWAsXG4gICAgICAgICAgICAgICAgICAgICdDb21tYW5kTWFuYWdlci9kaXNwYXRjaENvbW1hbmQnXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHRoaXMuc2VydmVyLmdldExvZ2dlcigpLmVycm9yKGVycm9yKTtcbiAgICAgICAgfVxuICAgIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQWVBLElBQWEsaUJBQWIsTUFBK0M7Q0FDM0MsMkJBQWtELElBQUksSUFBSTtDQUMxRDtDQUNBO0NBRUEsWUFBbUIsUUFBZ0I7RUFDL0IsS0FBSyxTQUFTO0VBQ2QsS0FBSyxhQUFhLElBQUksa0JBQWtCO0NBQzVDOzs7OztDQU1BLE1BQWEsU0FBd0I7RUFDakMsTUFBTSxRQUFRLElBQUksTUFBTTtFQUV4QixNQUFNLFdBQVcsT0FBTyxLQUFLLGdCQUFRLEVBQUUsS0FBSyxRQUFTLGlCQUFpQixJQUFzQjtFQUc1RixNQUFNLFFBQVEsSUFDVixTQUFTLElBQUksT0FBTyxZQUFZO0dBQzVCLE1BQU0sVUFBbUIsSUFBSSxRQUFRLENBQUMsQ0FBUTtHQUU5QyxNQUFNLFFBQVEsSUFBSSxxQkFBcUIsT0FBTztHQUM5QyxNQUFNLEtBQUssT0FBTyxLQUFLLG1CQUFtQixLQUFLO0dBQy9DLElBQUksTUFBTSxZQUFZLEdBQUc7R0FFekIsSUFBSTtJ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