UNPKG

@jsprismarine/prismarine

Version:

Dedicated Minecraft Bedrock Edition server written in TypeScript

394 lines (393 loc) 38.3 kB
import { Position } from "../world/Position.es.js"; import AddActorPacket from "../network/packet/AddActorPacket.es.js"; import MoveActorAbsolutePacket from "../network/packet/MoveActorAbsolutePacket.es.js"; import RemoveActorPacket from "../network/packet/RemoveActorPacket.es.js"; import TextType from "../network/type/TextType.es.js"; import UUID from "../utils/UUID.es.js"; import { Attributes } from "./Attribute.es.js"; import { Metadata, MetadataFlag } from "./Metadata.es.js"; import { Vector3 } from "@jsprismarine/math"; //#region src/entity/Entity.ts /** * Entity-like class. * @class * @internal */ var EntityLike = class extends Position { uuid; runtimeId; server; pitch; yaw; headYaw; /** * EntityLike constructor. * @param {object} options - The entity-like options. * @param {string} options.uuid - The entity's runtime id. * @param {bigint} options.runtimeId - The entity's runtime id. * @param {Server} options.server - The server instance. * @param {World} [options.world] - The world the entity belongs to. * @param {number} [options.pitch=0] - The pitch. * @param {number} [options.yaw=0] - The yaw. * @param {number} [options.headYaw=0] - The head yaw. * @returns {EntityLike} The entity-like instance. */ constructor({ uuid, runtimeId, pitch = 0, yaw = 0, headYaw = 0, ...options }) { super(0, 0, 0, options.world); this.uuid = uuid ?? UUID.randomString(); this.runtimeId = runtimeId; this.server = options.server; this.pitch = pitch; this.yaw = yaw; this.headYaw = headYaw; } /** * Get the entity's runtime id. * @returns {bigint} The entity's runtime id. */ getRuntimeId() { return this.runtimeId; } /** * Get the server instance. * @returns {Server} The server instance. */ getServer() { return this.server; } /** * Get the entity's position. * @returns {Vector3} The entity's position. * @example * ```typescript * const position = entity.getPosition(); * ``` */ getPosition() { return new Vector3(this.getX(), this.getY(), this.getZ()); } /** * Returns the nearest entity from the current entity. * @todo Customizable radius * @param {Entity[]} [entities=this.getWorld().getEntities()] - The entities to compare the distance between. * @returns {Entity[]} The nearest entity. * @example * ```typescript * const nearestEntity = entity.getNearestEntity(); * console.log('Nearest entity:', nearestEntity); * ``` */ getNearestEntity(entities = this.getWorld().getEntities()) { const position = new Vector3(this.getX(), this.getY(), this.getZ()); const distance = (a, b) => Math.hypot(b.getX() - a.getX(), b.getY() - a.getY(), b.getZ() - a.getZ()); const closest = (target, points, eps = 1e-5) => { const distances = points.map((e) => distance(target, new Vector3(e.getX(), e.getY(), e.getZ()))); const closest = Math.min(...distances); return points.find((_e, i) => distances[i] - closest < eps); }; return [closest(position, entities.filter((entity) => entity.getRuntimeId() !== this.runtimeId))]; } }; /** * The base class for all entities including `Player`. * @class * @public */ var Entity = class Entity extends EntityLike { /** * The global runtime id counter. * @internal */ static runtimeIdCount = 0n; /** * The entity's namespace ID. */ static MOB_ID = "jsprismarine:unknown_entity"; /** * Get the entity type. * @returns {string} The entity's namespace ID. * @example * ```typescript * const entityType = entity.getType(); * console.log(`Entity type: ${entityType}`); * ``` */ getType() { return this.constructor.MOB_ID; } /** * Entity metadata. */ metadata = new Metadata(); /** * Entity attributes. */ attributes = new Attributes(); /** * Entity constructor. * @param {object} options - The entity options. * @param {World} options.world - The world the entity belongs to. * @param {Server} options.server - The server instance. * @param {string} [options.uuid] - The entity's UUID. * @returns {Entity} The entity instance. * @example * ```typescript * const entity = new Entity({ * world: server.getWorldManager().getDefaultWorld(), * server * }); * ``` */ constructor({ world, ...options }) { Entity.runtimeIdCount += 1n; super({ world, ...options, runtimeId: Entity.runtimeIdCount }); if (world) super.setWorld(world); } get [Symbol.toStringTag]() { return `Entity(${this.toString()})`; } /** * Convert to a string representation. * @returns {string} The string. * ```typescript * console.log(entity.toString()); * ``` */ toString() { return `uuid: §a${this.getUUID()}§r, id: §a${this.getRuntimeId()}§r, name: §b${this.getName()}§r, type: §b${this.getType()}§r, ${super.toString()}`; } /** * Get the entity's runtime id. * @returns {bigint} The entity's runtime id. * @example * ```typescript * const entityId = entity.getRuntimeId(); * console.log(entityId); // Ex. Output: 1n * ``` */ getRuntimeId() { return this.runtimeId; } /** * Get the entity's UUID. * @returns {string} The entity's UUID. * ```typescript * console.log(entity.getUUID()); * ``` */ getUUID() { return this.uuid; } /** * Fired every tick from the event subscription in the constructor. * @param {number} _tick - The current world-tick. * @returns {Promise<void>} A promise that resolves when the update is complete. * @example * ```typescript * entity.update(10); * ``` */ async update(_tick) {} /** * Get the server instance. * @returns {Server} The server instance. * @example * ```typescript * const server = entity.getServer(); * // Do things with the server. * ``` */ getServer() { return this.server; } /** * Spawn the entity. * @todo `motion`, `pitch` & `yaw` is unimplemented. * @param {Player} [player] - The player to send the packet to. * @returns {Promise<void>} A promise that resolves when the entity is spawned. */ async sendSpawn(player) { const players = player ? [player] : this.getWorld().getPlayers(); const packet = new AddActorPacket(); packet.runtimeEntityId = this.getRuntimeId(); packet.type = this.constructor.MOB_ID; packet.position = this.getPosition(); packet.motion = new Vector3(0, 0, 0); packet.pitch = this.pitch; packet.yaw = this.yaw; packet.headYaw = this.headYaw; packet.metadata = this.metadata; await Promise.all(players.map(async (p) => p.getNetworkSession().send(packet))); } /** * Despawn the entity. * @param {Player} [player] - The player to send the packet to, if not specified, all players in the world will receive the packet. * @returns {Promise<void>} A promise that resolves when the entity is despawned. */ async sendDespawn(player) { const players = player ? [player] : this.getWorld().getPlayers(); const packet = new RemoveActorPacket(); packet.uniqueEntityId = this.runtimeId; await Promise.all(players.map(async (player) => player.getNetworkSession().send(packet))); } /** * Send the position to all the players in the same world. * @returns {Promise<void>} A promise that resolves when the position is sent. */ async sendPosition() { await Promise.all(this.getWorld().getPlayers().map((target) => { const packet = new MoveActorAbsolutePacket(); packet.runtimeEntityId = this.runtimeId; packet.position = this.getPosition(); return target.getNetworkSession().send(packet); })); } /** * Send a message to an entity. * @remarks This will silently fail on non-client-controlled entities. * @param {string} message - The message. * @param {TextType} [type=TextType.Raw] - The text type. * @example Send "Hello World!" to a client: * ```typescript * entity.sendMessage('Hello World!'); * ``` */ sendMessage(message, type = TextType.Raw) { this.server.getLogger().warn(`Entity/sendMessage is not implemented: (message: ${message}, type: ${type})`); } /** * Set the `x` position. * @param {number} x - The `x` coordinate. * @param {boolean} [suppress=false] - If true, the client won't be notified about the position change. * @returns {Promise<void>} A promise that resolves when the x position is set. * @example * ```typescript * await entity.setX(10); * ``` * @remarks This method will also send the position update to the client if `suppress` is `false`. */ async setX(x, suppress = false) { super.setX.bind(this)(x); if (suppress && !this.isPlayer()) await this.sendPosition(); } /** * Set the `y` position. * @param {number} y - The `y` coordinate. * @param {boolean} [suppress=false] - If true, the client won't be notified about the position change. * @returns {Promise<void>} A promise that resolves when the y position is set. * @example * ```typescript * await entity.setY(10); * ``` * @remarks This method will also send the position update to the client if `suppress` is `false`. */ async setY(y, suppress = false) { super.setY.bind(this)(y); if (suppress && !this.isPlayer()) await this.sendPosition(); } /** * Set the `z` position. * @param {number} z - The `z` coordinate. * @param {boolean} [suppress=false] - If true, the client won't be notified about the position change. * @returns {Promise<void>} A promise that resolves when the z position is set. * @example * ```typescript * await entity.setZ(10); * ``` * @remarks This method will also send the position update to the client if `suppress` is `false`. */ async setZ(z, suppress = false) { super.setZ.bind(this)(z); if (suppress && !this.isPlayer()) await this.sendPosition(); } /** * Set the entity's position and notify the clients. * @param {object} options - The position options. * @param {Vector3} options.position - The position. * @param {number} [options.pitch] - The pitch. * @param {number} [options.yaw] - The yaw. * @param {number} [options.headYaw] - The head yaw. * @returns {Promise<void>} A promise that resolves when the position is set. */ async setPosition({ position, pitch = this.pitch, yaw = this.yaw, headYaw = this.headYaw }) { this.pitch = pitch; this.yaw = yaw; this.headYaw = headYaw; await super.setX(position.getX()); await super.setY(position.getY()); await super.setZ(position.getZ()); await this.sendPosition(); } /** * Check if the entity is a player. * @returns {boolean} `true` if the entity is player-controlled, otherwise `false`. * @example * ```typescript * if (entity.isPlayer()) { * console.log('Entity is a player'); * } else { * console.log('Entity is not a player'); * } * ``` */ isPlayer() { return false; } /** * Check if the entity is a console instance. * @returns {boolean} `true` if the entity is console-controlled, otherwise `false`. * @example * ```typescript * if (entity.isConsole()) { * console.log('Entity is a console'); * } else { * console.log('Entity is not a console'); * } * ``` */ isConsole() { return this.getRuntimeId() <= 0n; } /** * Get the entity's (potentially custom) name. * @returns {string} The entity's name without formatting (usually prefix & suffix). * @example * ```typescript * const name = entity.getName(); * console.log(`Entity name: ${name}`); * ``` */ getName() { return this.getFormattedUsername(); } /** * Set the entity's name. * @param {string} name - The name. * @example * ```typescript * entity.setName('Mr. Sheep'); * ``` */ setName(name) { this.metadata.setNameTag(name); } /** * Get the entity's formatted name. * @returns {string} The entity's formatted name (including prefix & suffix). * @example * ```typescript * const formattedName = entity.getFormattedUsername(); * console.log(`Entity formatted name: ${formattedName}`); // Entity formatted name: Sheep * ``` */ getFormattedUsername() { return this.metadata.getString(MetadataFlag.NAMETAG) || (this.constructor?.MOB_ID || "Unknown Entity").split(":")[1].replaceAll("_", " ").split(" ").map((word) => word[0].toUpperCase() + word.slice(1, word.length)).join(" "); } }; //#endregion export { Entity, EntityLike }; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRW50aXR5LmVzLmpzIiwibmFtZXMiOltdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9lbnRpdHkvRW50aXR5LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFZlY3RvcjMgfSBmcm9tICdAanNwcmlzbWFyaW5lL21hdGgnO1xuaW1wb3J0IHR5cGUgUGxheWVyIGZyb20gJy4uL1BsYXllcic7XG5pbXBvcnQgdHlwZSBTZXJ2ZXIgZnJvbSAnLi4vU2VydmVyJztcbmltcG9ydCBBZGRBY3RvclBhY2tldCBmcm9tICcuLi9uZXR3b3JrL3BhY2tldC9BZGRBY3RvclBhY2tldCc7XG5pbXBvcnQgTW92ZUFjdG9yQWJzb2x1dGVQYWNrZXQgZnJvbSAnLi4vbmV0d29yay9wYWNrZXQvTW92ZUFjdG9yQWJzb2x1dGVQYWNrZXQnO1xuaW1wb3J0IFJlbW92ZUFjdG9yUGFja2V0IGZyb20gJy4uL25ldHdvcmsvcGFja2V0L1JlbW92ZUFjdG9yUGFja2V0JztcbmltcG9ydCBUZXh0VHlwZSBmcm9tICcuLi9uZXR3b3JrL3R5cGUvVGV4dFR5cGUnO1xuaW1wb3J0IFVVSUQgZnJvbSAnLi4vdXRpbHMvVVVJRCc7XG5pbXBvcnQgeyBQb3NpdGlvbiB9IGZyb20gJy4uL3dvcmxkL1Bvc2l0aW9uJztcbmltcG9ydCB0eXBlIHsgV29ybGQgfSBmcm9tICcuLi93b3JsZC9Xb3JsZCc7XG5pbXBvcnQgeyBBdHRyaWJ1dGVzIH0gZnJvbSAnLi9BdHRyaWJ1dGUnO1xuaW1wb3J0IHsgTWV0YWRhdGEsIE1ldGFkYXRhRmxhZyB9IGZyb20gJy4vTWV0YWRhdGEnO1xuXG4vKipcbiAqIEVudGl0eS1saWtlIGNsYXNzLlxuICogQGNsYXNzXG4gKiBAaW50ZXJuYWxcbiAqL1xuZXhwb3J0IGNsYXNzIEVudGl0eUxpa2UgZXh0ZW5kcyBQb3NpdGlvbiB7XG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IHV1aWQ6IHN0cmluZztcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgcnVudGltZUlkOiBiaWdpbnQ7XG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IHNlcnZlcjogU2VydmVyO1xuXG4gICAgcHVibGljIHBpdGNoOiBudW1iZXI7XG4gICAgcHVibGljIHlhdzogbnVtYmVyO1xuICAgIHB1YmxpYyBoZWFkWWF3OiBudW1iZXI7XG5cbiAgICAvKipcbiAgICAgKiBFbnRpdHlMaWtlIGNvbnN0cnVjdG9yLlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIC0gVGhlIGVudGl0eS1saWtlIG9wdGlvbnMuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IG9wdGlvbnMudXVpZCAtIFRoZSBlbnRpdHkncyBydW50aW1lIGlkLlxuICAgICAqIEBwYXJhbSB7YmlnaW50fSBvcHRpb25zLnJ1bnRpbWVJZCAtIFRoZSBlbnRpdHkncyBydW50aW1lIGlkLlxuICAgICAqIEBwYXJhbSB7U2VydmVyfSBvcHRpb25zLnNlcnZlciAtIFRoZSBzZXJ2ZXIgaW5zdGFuY2UuXG4gICAgICogQHBhcmFtIHtXb3JsZH0gW29wdGlvbnMud29ybGRdIC0gVGhlIHdvcmxkIHRoZSBlbnRpdHkgYmVsb25ncyB0by5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gW29wdGlvbnMucGl0Y2g9MF0gLSBUaGUgcGl0Y2guXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IFtvcHRpb25zLnlhdz0wXSAtIFRoZSB5YXcuXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IFtvcHRpb25zLmhlYWRZYXc9MF0gLSBUaGUgaGVhZCB5YXcuXG4gICAgICogQHJldHVybnMge0VudGl0eUxpa2V9IFRoZSBlbnRpdHktbGlrZSBpbnN0YW5jZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgY29uc3RydWN0b3Ioe1xuICAgICAgICB1dWlkLFxuICAgICAgICBydW50aW1lSWQsXG4gICAgICAgIHBpdGNoID0gMCxcbiAgICAgICAgeWF3ID0gMCxcbiAgICAgICAgaGVhZFlhdyA9IDAsXG4gICAgICAgIC4uLm9wdGlvbnNcbiAgICB9OiB7XG4gICAgICAgIHV1aWQ/OiBzdHJpbmc7XG4gICAgICAgIHJ1bnRpbWVJZDogYmlnaW50O1xuICAgICAgICBwaXRjaD86IG51bWJlcjtcbiAgICAgICAgeWF3PzogbnVtYmVyO1xuICAgICAgICBoZWFkWWF3PzogbnVtYmVyO1xuICAgICAgICBzZXJ2ZXI6IFNlcnZlcjtcbiAgICAgICAgd29ybGQ6IFdvcmxkO1xuICAgIH0pIHtcbiAgICAgICAgc3VwZXIoMCwgMCwgMCwgb3B0aW9ucy53b3JsZCk7IC8vIFRPRE9cblxuICAgICAgICB0aGlzLnV1aWQgPSB1dWlkID8/IFVVSUQucmFuZG9tU3RyaW5nKCk7XG4gICAgICAgIHRoaXMucnVudGltZUlkID0gcnVudGltZUlkO1xuICAgICAgICB0aGlzLnNlcnZlciA9IG9wdGlvbnMuc2VydmVyO1xuXG4gICAgICAgIHRoaXMucGl0Y2ggPSBwaXRjaDtcbiAgICAgICAgdGhpcy55YXcgPSB5YXc7XG4gICAgICAgIHRoaXMuaGVhZFlhdyA9IGhlYWRZYXc7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IHRoZSBlbnRpdHkncyBydW50aW1lIGlkLlxuICAgICAqIEByZXR1cm5zIHtiaWdpbnR9IFRoZSBlbnRpdHkncyBydW50aW1lIGlkLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRSdW50aW1lSWQoKTogYmlnaW50IHtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVudGltZUlkO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCB0aGUgc2VydmVyIGluc3RhbmNlLlxuICAgICAqIEByZXR1cm5zIHtTZXJ2ZXJ9IFRoZSBzZXJ2ZXIgaW5zdGFuY2UuXG4gICAgICovXG4gICAgcHVibGljIGdldFNlcnZlcigpOiBTZXJ2ZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5zZXJ2ZXI7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IHRoZSBlbnRpdHkncyBwb3NpdGlvbi5cbiAgICAgKiBAcmV0dXJucyB7VmVjdG9yM30gVGhlIGVudGl0eSdzIHBvc2l0aW9uLlxuICAgICAqIEBleGFtcGxlXG4gICAgICogYGBgdHlwZXNjcmlwdFxuICAgICAqIGNvbnN0IHBvc2l0aW9uID0gZW50aXR5LmdldFBvc2l0aW9uKCk7XG4gICAgICogYGBgXG4gICAgICovXG4gICAgcHVibGljIGdldFBvc2l0aW9uKCk6IFZlY3RvcjMge1xuICAgICAgICByZXR1cm4gbmV3IFZlY3RvcjModGhpcy5nZXRYKCksIHRoaXMuZ2V0WSgpLCB0aGlzLmdldFooKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgbmVhcmVzdCBlbnRpdHkgZnJvbSB0aGUgY3VycmVudCBlbnRpdHkuXG4gICAgICogQHRvZG8gQ3VzdG9taXphYmxlIHJhZGl1c1xuICAgICAqIEBwYXJhbSB7RW50aXR5W119IFtlbnRpdGllcz10aGlzLmdldFdvcmxkKCkuZ2V0RW50aXRpZXMoKV0gLSBUaGUgZW50aXRpZXMgdG8gY29tcGFyZSB0aGUgZGlzdGFuY2UgYmV0d2Vlbi5cbiAgICAgKiBAcmV0dXJucyB7RW50aXR5W119IFRoZSBuZWFyZXN0IGVudGl0eS5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiBjb25zdCBuZWFyZXN0RW50aXR5ID0gZW50aXR5LmdldE5lYXJlc3RFbnRpdHkoKTtcbiAgICAgKiBjb25zb2xlLmxvZygnTmVhcmVzdCBlbnRpdHk6JywgbmVhcmVzdEVudGl0eSk7XG4gICAgICogYGBgXG4gICAgICovXG4gICAgcHVibGljIGdldE5lYXJlc3RFbnRpdHkoZW50aXRpZXM6IEVudGl0eVtdID0gdGhpcy5nZXRXb3JsZCgpLmdldEVudGl0aWVzKCkpOiBFbnRpdHlbXSB7XG4gICAgICAgIGNvbnN0IHBvc2l0aW9uID0gbmV3IFZlY3RvcjModGhpcy5nZXRYKCksIHRoaXMuZ2V0WSgpLCB0aGlzLmdldFooKSk7XG4gICAgICAgIGNvbnN0IGRpc3RhbmNlID0gKGE6IFZlY3RvcjMsIGI6IFZlY3RvcjMpID0+XG4gICAgICAgICAgICBNYXRoLmh5cG90KGIuZ2V0WCgpIC0gYS5nZXRYKCksIGIuZ2V0WSgpIC0gYS5nZXRZKCksIGIuZ2V0WigpIC0gYS5nZXRaKCkpO1xuXG4gICAgICAgIGNvbnN0IGNsb3Nlc3QgPSAodGFyZ2V0OiBWZWN0b3IzLCBwb2ludHM6IEVudGl0eVtdLCBlcHMgPSAwLjAwMDAxKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBkaXN0YW5jZXMgPSBwb2ludHMubWFwKChlKSA9PiBkaXN0YW5jZSh0YXJnZXQsIG5ldyBWZWN0b3IzKGUuZ2V0WCgpLCBlLmdldFkoKSwgZS5nZXRaKCkpKSk7XG4gICAgICAgICAgICBjb25zdCBjbG9zZXN0ID0gTWF0aC5taW4oLi4uZGlzdGFuY2VzKTtcbiAgICAgICAgICAgIHJldHVybiBwb2ludHMuZmluZCgoX2UsIGkpID0+IGRpc3RhbmNlc1tpXSEgLSBjbG9zZXN0IDwgZXBzKSE7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIGNsb3Nlc3QoXG4gICAgICAgICAgICAgICAgcG9zaXRpb24sXG4gICAgICAgICAgICAgICAgZW50aXRpZXMuZmlsdGVyKChlbnRpdHkpID0+IGVudGl0eS5nZXRSdW50aW1lSWQoKSAhPT0gdGhpcy5ydW50aW1lSWQpXG4gICAgICAgICAgICApXG4gICAgICAgIF07XG4gICAgfVxufVxuXG4vKipcbiAqIFRoZSBiYXNlIGNsYXNzIGZvciBhbGwgZW50aXRpZXMgaW5jbHVkaW5nIGBQbGF5ZXJgLlxuICogQGNsYXNzXG4gKiBAcHVibGljXG4gKi9cbmV4cG9ydCBjbGFzcyBFbnRpdHkgZXh0ZW5kcyBFbnRpdHlMaWtlIHtcbiAgICAvKipcbiAgICAgKiBUaGUgZ2xvYmFsIHJ1bnRpbWUgaWQgY291bnRlci5cbiAgICAgKiBAaW50ZXJuYWxcbiAgICAgKi9cbiAgICBwdWJsaWMgc3RhdGljIHJ1bnRpbWVJZENvdW50ID0gMG47XG5cbiAgICAvKipcbiAgICAgKiBUaGUgZW50aXR5J3MgbmFtZXNwYWNlIElELlxuICAgICAqL1xuICAgIHByb3RlY3RlZCBzdGF0aWMgTU9CX0lEOiBzdHJpbmcgPSAnanNwcmlzbWFyaW5lOnVua25vd25fZW50aXR5JztcblxuICAgIC8qKlxuICAgICAqIEdldCB0aGUgZW50aXR5IHR5cGUuXG4gICAgICogQHJldHVybnMge3N0cmluZ30gVGhlIGVudGl0eSdzIG5hbWVzcGFjZSBJRC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiBjb25zdCBlbnRpdHlUeXBlID0gZW50aXR5LmdldFR5cGUoKTtcbiAgICAgKiBjb25zb2xlLmxvZyhgRW50aXR5IHR5cGU6ICR7ZW50aXR5VHlwZX1gKTtcbiAgICAgKiBgYGBcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0VHlwZSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gKHRoaXMuY29uc3RydWN0b3IgYXMgYW55KS5NT0JfSUQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRW50aXR5IG1ldGFkYXRhLlxuICAgICAqL1xuICAgIHB1YmxpYyByZWFkb25seSBtZXRhZGF0YSA9IG5ldyBNZXRhZGF0YSgpO1xuXG4gICAgLyoqXG4gICAgICogRW50aXR5IGF0dHJpYnV0ZXMuXG4gICAgICovXG4gICAgcHVibGljIHJlYWRvbmx5IGF0dHJpYnV0ZXMgPSBuZXcgQXR0cmlidXRlcygpO1xuXG4gICAgLyoqXG4gICAgICogRW50aXR5IGNvbnN0cnVjdG9yLlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIC0gVGhlIGVudGl0eSBvcHRpb25zLlxuICAgICAqIEBwYXJhbSB7V29ybGR9IG9wdGlvbnMud29ybGQgLSBUaGUgd29ybGQgdGhlIGVudGl0eSBiZWxvbmdzIHRvLlxuICAgICAqIEBwYXJhbSB7U2VydmVyfSBvcHRpb25zLnNlcnZlciAtIFRoZSBzZXJ2ZXIgaW5zdGFuY2UuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IFtvcHRpb25zLnV1aWRdIC0gVGhlIGVudGl0eSdzIFVVSUQuXG4gICAgICogQHJldHVybnMge0VudGl0eX0gVGhlIGVudGl0eSBpbnN0YW5jZS5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiBjb25zdCBlbnRpdHkgPSBuZXcgRW50aXR5KHtcbiAgICAgKiAgICAgd29ybGQ6IHNlcnZlci5nZXRXb3JsZE1hbmFnZXIoKS5nZXREZWZhdWx0V29ybGQoKSxcbiAgICAgKiAgICAgc2VydmVyXG4gICAgICogfSk7XG4gICAgICogYGBgXG4gICAgICovXG4gICAgcHVibGljIGNvbnN0cnVjdG9yKHsgd29ybGQsIC4uLm9wdGlvbnMgfTogT21pdDxDb25zdHJ1Y3RvclBhcmFtZXRlcnM8dHlwZW9mIEVudGl0eUxpa2U+WzBdLCAncnVudGltZUlkJz4pIHtcbiAgICAgICAgRW50aXR5LnJ1bnRpbWVJZENvdW50ICs9IDFuO1xuICAgICAgICBzdXBlcih7XG4gICAgICAgICAgICB3b3JsZCxcbiAgICAgICAgICAgIC4uLm9wdGlvbnMsXG4gICAgICAgICAgICBydW50aW1lSWQ6IEVudGl0eS5ydW50aW1lSWRDb3VudFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVubmVjZXNzYXJ5LWNvbmRpdGlvblxuICAgICAgICBpZiAod29ybGQpIHN1cGVyLnNldFdvcmxkKHdvcmxkKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IFtTeW1ib2wudG9TdHJpbmdUYWddKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiBgRW50aXR5KCR7dGhpcy50b1N0cmluZygpfSlgO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENvbnZlcnQgdG8gYSBzdHJpbmcgcmVwcmVzZW50YXRpb24uXG4gICAgICogQHJldHVybnMge3N0cmluZ30gVGhlIHN0cmluZy5cbiAgICAgKiBgYGB0eXBlc2NyaXB0XG4gICAgICogY29uc29sZS5sb2coZW50aXR5LnRvU3RyaW5nKCkpO1xuICAgICAqIGBgYFxuICAgICAqL1xuICAgIHB1YmxpYyB0b1N0cmluZygpIHtcbiAgICAgICAgcmV0dXJuIGB1dWlkOiDCp2Eke3RoaXMuZ2V0VVVJRCgpfcKnciwgaWQ6IMKnYSR7dGhpcy5nZXRSdW50aW1lSWQoKX3Cp3IsIG5hbWU6IMKnYiR7dGhpcy5nZXROYW1lKCl9wqdyLCB0eXBlOiDCp2Ike3RoaXMuZ2V0VHlwZSgpfcKnciwgJHtzdXBlci50b1N0cmluZygpfWA7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IHRoZSBlbnRpdHkncyBydW50aW1lIGlkLlxuICAgICAqIEByZXR1cm5zIHtiaWdpbnR9IFRoZSBlbnRpdHkncyBydW50aW1lIGlkLlxuICAgICAqIEBleGFtcGxlXG4gICAgICogYGBgdHlwZXNjcmlwdFxuICAgICAqIGNvbnN0IGVudGl0eUlkID0gZW50aXR5LmdldFJ1bnRpbWVJZCgpO1xuICAgICAqIGNvbnNvbGUubG9nKGVudGl0eUlkKTsgLy8gRXguIE91dHB1dDogMW5cbiAgICAgKiBgYGBcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0UnVudGltZUlkKCk6IGJpZ2ludCB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1bnRpbWVJZDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgdGhlIGVudGl0eSdzIFVVSUQuXG4gICAgICogQHJldHVybnMge3N0cmluZ30gVGhlIGVudGl0eSdzIFVVSUQuXG4gICAgICogYGBgdHlwZXNjcmlwdFxuICAgICAqIGNvbnNvbGUubG9nKGVudGl0eS5nZXRVVUlEKCkpO1xuICAgICAqIGBgYFxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRVVUlEKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiB0aGlzLnV1aWQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRmlyZWQgZXZlcnkgdGljayBmcm9tIHRoZSBldmVudCBzdWJzY3JpcHRpb24gaW4gdGhlIGNvbnN0cnVjdG9yLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBfdGljayAtIFRoZSBjdXJyZW50IHdvcmxkLXRpY2suXG4gICAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIHVwZGF0ZSBpcyBjb21wbGV0ZS5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiBlbnRpdHkudXBkYXRlKDEwKTtcbiAgICAgKiBgYGBcbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgdXBkYXRlKF90aWNrOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHt9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgdGhlIHNlcnZlciBpbnN0YW5jZS5cbiAgICAgKiBAcmV0dXJucyB7U2VydmVyfSBUaGUgc2VydmVyIGluc3RhbmNlLlxuICAgICAqIEBleGFtcGxlXG4gICAgICogYGBgdHlwZXNjcmlwdFxuICAgICAqIGNvbnN0IHNlcnZlciA9IGVudGl0eS5nZXRTZXJ2ZXIoKTtcbiAgICAgKiAvLyBEbyB0aGluZ3Mgd2l0aCB0aGUgc2VydmVyLlxuICAgICAqIGBgYFxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRTZXJ2ZXIoKTogU2VydmVyIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc2VydmVyO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNwYXduIHRoZSBlbnRpdHkuXG4gICAgICogQHRvZG8gYG1vdGlvbmAsIGBwaXRjaGAgJiBgeWF3YCBpcyB1bmltcGxlbWVudGVkLlxuICAgICAqIEBwYXJhbSB7UGxheWVyfSBbcGxheWVyXSAtIFRoZSBwbGF5ZXIgdG8gc2VuZCB0aGUgcGFja2V0IHRvLlxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBlbnRpdHkgaXMgc3Bhd25lZC5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgc2VuZFNwYXduKHBsYXllcj86IFBsYXllcik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBwbGF5ZXJzOiBQbGF5ZXJbXSA9IHBsYXllciA/IFtwbGF5ZXJdIDogdGhpcy5nZXRXb3JsZCgpLmdldFBsYXllcnMoKTtcblxuICAgICAgICBjb25zdCBwYWNrZXQgPSBuZXcgQWRkQWN0b3JQYWNrZXQoKTtcbiAgICAgICAgcGFja2V0LnJ1bnRpbWVFbnRpdHlJZCA9IHRoaXMuZ2V0UnVudGltZUlkKCk7XG4gICAgICAgIHBhY2tldC50eXBlID0gKHRoaXMuY29uc3RydWN0b3IgYXMgYW55KS5NT0JfSUQ7IC8vIFRPRE9cbiAgICAgICAgcGFja2V0LnBvc2l0aW9uID0gdGhpcy5nZXRQb3NpdGlvbigpO1xuICAgICAgICBwYWNrZXQubW90aW9uID0gbmV3IFZlY3RvcjMoMCwgMCwgMCk7IC8vIFRPRE86IG1vdGlvblxuICAgICAgICBwYWNrZXQucGl0Y2ggPSB0aGlzLnBpdGNoO1xuICAgICAgICBwYWNrZXQueWF3ID0gdGhpcy55YXc7XG4gICAgICAgIHBhY2tldC5oZWFkWWF3ID0gdGhpcy5oZWFkWWF3O1xuICAgICAgICBwYWNrZXQubWV0YWRhdGEgPSB0aGlzLm1ldGFkYXRhO1xuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChwbGF5ZXJzLm1hcChhc3luYyAocCkgPT4gcC5nZXROZXR3b3JrU2Vzc2lvbigpLnNlbmQocGFja2V0KSkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIERlc3Bhd24gdGhlIGVudGl0eS5cbiAgICAgKiBAcGFyYW0ge1BsYXllcn0gW3BsYXllcl0gLSBUaGUgcGxheWVyIHRvIHNlbmQgdGhlIHBhY2tldCB0bywgaWYgbm90IHNwZWNpZmllZCwgYWxsIHBsYXllcnMgaW4gdGhlIHdvcmxkIHdpbGwgcmVjZWl2ZSB0aGUgcGFja2V0LlxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBlbnRpdHkgaXMgZGVzcGF3bmVkLlxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBzZW5kRGVzcGF3bihwbGF5ZXI/OiBQbGF5ZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgcGxheWVyczogUGxheWVyW10gPSBwbGF5ZXIgPyBbcGxheWVyXSA6IHRoaXMuZ2V0V29ybGQoKS5nZXRQbGF5ZXJzKCk7XG5cbiAgICAgICAgY29uc3QgcGFja2V0ID0gbmV3IFJlbW92ZUFjdG9yUGFja2V0KCk7XG4gICAgICAgIHBhY2tldC51bmlxdWVFbnRpdHlJZCA9IHRoaXMucnVudGltZUlkO1xuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChwbGF5ZXJzLm1hcChhc3luYyAocGxheWVyKSA9PiBwbGF5ZXIuZ2V0TmV0d29ya1Nlc3Npb24oKS5zZW5kKHBhY2tldCkpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZW5kIHRoZSBwb3NpdGlvbiB0byBhbGwgdGhlIHBsYXllcnMgaW4gdGhlIHNhbWUgd29ybGQuXG4gICAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIHBvc2l0aW9uIGlzIHNlbnQuXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIHNlbmRQb3NpdGlvbigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgICAgICB0aGlzLmdldFdvcmxkKClcbiAgICAgICAgICAgICAgICAuZ2V0UGxheWVycygpXG4gICAgICAgICAgICAgICAgLm1hcCgodGFyZ2V0KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHBhY2tldCA9IG5ldyBNb3ZlQWN0b3JBYnNvbHV0ZVBhY2tldCgpO1xuICAgICAgICAgICAgICAgICAgICBwYWNrZXQucnVudGltZUVudGl0eUlkID0gdGhpcy5ydW50aW1lSWQ7XG4gICAgICAgICAgICAgICAgICAgIHBhY2tldC5wb3NpdGlvbiA9IHRoaXMuZ2V0UG9zaXRpb24oKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRhcmdldC5nZXROZXR3b3JrU2Vzc2lvbigpLnNlbmQocGFja2V0KTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNlbmQgYSBtZXNzYWdlIHRvIGFuIGVudGl0eS5cbiAgICAgKiBAcmVtYXJrcyBUaGlzIHdpbGwgc2lsZW50bHkgZmFpbCBvbiBub24tY2xpZW50LWNvbnRyb2xsZWQgZW50aXRpZXMuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2UgLSBUaGUgbWVzc2FnZS5cbiAgICAgKiBAcGFyYW0ge1RleHRUeXBlfSBbdHlwZT1UZXh0VHlwZS5SYXddIC0gVGhlIHRleHQgdHlwZS5cbiAgICAgKiBAZXhhbXBsZSBTZW5kIFwiSGVsbG8gV29ybGQhXCIgdG8gYSBjbGllbnQ6XG4gICAgICogYGBgdHlwZXNjcmlwdFxuICAgICAqIGVudGl0eS5zZW5kTWVzc2FnZSgnSGVsbG8gV29ybGQhJyk7XG4gICAgICogYGBgXG4gICAgICovXG4gICAgcHVibGljIHNlbmRNZXNzYWdlKG1lc3NhZ2U6IHN0cmluZywgdHlwZTogVGV4dFR5cGUgPSBUZXh0VHlwZS5SYXcpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5zZXJ2ZXIuZ2V0TG9nZ2VyKCkud2FybihgRW50aXR5L3NlbmRNZXNzYWdlIGlzIG5vdCBpbXBsZW1lbnRlZDogKG1lc3NhZ2U6ICR7bWVzc2FnZX0sIHR5cGU6ICR7dHlwZX0pYCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0IHRoZSBgeGAgcG9zaXRpb24uXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHggLSBUaGUgYHhgIGNvb3JkaW5hdGUuXG4gICAgICogQHBhcmFtIHtib29sZWFufSBbc3VwcHJlc3M9ZmFsc2VdIC0gSWYgdHJ1ZSwgdGhlIGNsaWVudCB3b24ndCBiZSBub3RpZmllZCBhYm91dCB0aGUgcG9zaXRpb24gY2hhbmdlLlxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSB4IHBvc2l0aW9uIGlzIHNldC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiBhd2FpdCBlbnRpdHkuc2V0WCgxMCk7XG4gICAgICogYGBgXG4gICAgICogQHJlbWFya3MgVGhpcyBtZXRob2Qgd2lsbCBhbHNvIHNlbmQgdGhlIHBvc2l0aW9uIHVwZGF0ZSB0byB0aGUgY2xpZW50IGlmIGBzdXBwcmVzc2AgaXMgYGZhbHNlYC5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgc2V0WCh4OiBudW1iZXIsIHN1cHByZXNzID0gZmFsc2UpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgc3VwZXIuc2V0WC5iaW5kKHRoaXMpKHgpO1xuICAgICAgICBpZiAoc3VwcHJlc3MgJiYgIXRoaXMuaXNQbGF5ZXIoKSkgYXdhaXQgdGhpcy5zZW5kUG9zaXRpb24oKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXQgdGhlIGB5YCBwb3NpdGlvbi5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0geSAtIFRoZSBgeWAgY29vcmRpbmF0ZS5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtzdXBwcmVzcz1mYWxzZV0gLSBJZiB0cnVlLCB0aGUgY2xpZW50IHdvbid0IGJlIG5vdGlmaWVkIGFib3V0IHRoZSBwb3NpdGlvbiBjaGFuZ2UuXG4gICAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIHkgcG9zaXRpb24gaXMgc2V0LlxuICAgICAqIEBleGFtcGxlXG4gICAgICogYGBgdHlwZXNjcmlwdFxuICAgICAqIGF3YWl0IGVudGl0eS5zZXRZKDEwKTtcbiAgICAgKiBgYGBcbiAgICAgKiBAcmVtYXJrcyBUaGlzIG1ldGhvZCB3aWxsIGFsc28gc2VuZCB0aGUgcG9zaXRpb24gdXBkYXRlIHRvIHRoZSBjbGllbnQgaWYgYHN1cHByZXNzYCBpcyBgZmFsc2VgLlxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBzZXRZKHk6IG51bWJlciwgc3VwcHJlc3MgPSBmYWxzZSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBzdXBlci5zZXRZLmJpbmQodGhpcykoeSk7XG4gICAgICAgIGlmIChzdXBwcmVzcyAmJiAhdGhpcy5pc1BsYXllcigpKSBhd2FpdCB0aGlzLnNlbmRQb3NpdGlvbigpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCB0aGUgYHpgIHBvc2l0aW9uLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB6IC0gVGhlIGB6YCBjb29yZGluYXRlLlxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW3N1cHByZXNzPWZhbHNlXSAtIElmIHRydWUsIHRoZSBjbGllbnQgd29uJ3QgYmUgbm90aWZpZWQgYWJvdXQgdGhlIHBvc2l0aW9uIGNoYW5nZS5cbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgeiBwb3NpdGlvbiBpcyBzZXQuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKiBgYGB0eXBlc2NyaXB0XG4gICAgICogYXdhaXQgZW50aXR5LnNldFooMTApO1xuICAgICAqIGBgYFxuICAgICAqIEByZW1hcmtzIFRoaXMgbWV0aG9kIHdpbGwgYWxzbyBzZW5kIHRoZSBwb3NpdGlvbiB1cGRhdGUgdG8gdGhlIGNsaWVudCBpZiBgc3VwcHJlc3NgIGlzIGBmYWxzZWAuXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIHNldFooejogbnVtYmVyLCBzdXBwcmVzcyA9IGZhbHNlKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHN1cGVyLnNldFouYmluZCh0aGlzKSh6KTtcbiAgICAgICAgaWYgKHN1cHByZXNzICYmICF0aGlzLmlzUGxheWVyKCkpIGF3YWl0IHRoaXMuc2VuZFBvc2l0aW9uKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0IHRoZSBlbnRpdHkncyBwb3NpdGlvbiBhbmQgbm90aWZ5IHRoZSBjbGllbnRzLlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIC0gVGhlIHBvc2l0aW9uIG9wdGlvbnMuXG4gICAgICogQHBhcmFtIHtWZWN0b3IzfSBvcHRpb25zLnBvc2l0aW9uIC0gVGhlIHBvc2l0aW9uLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0aW9ucy5waXRjaF0gLSBUaGUgcGl0Y2guXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IFtvcHRpb25zLnlhd10gLSBUaGUgeWF3LlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0aW9ucy5oZWFkWWF3XSAtIFRoZSBoZWFkIHlhdy5cbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgcG9zaXRpb24gaXMgc2V0LlxuICAgICAqL1xuICAgIHB1YmxpYyBhc3luYyBzZXRQb3NpdGlvbih7XG4gICAgICAgIHBvc2l0aW9uLFxuICAgICAgICBwaXRjaCA9IHRoaXMucGl0Y2gsXG4gICAgICAgIHlhdyA9IHRoaXMueWF3LFxuICAgICAgICBoZWFkWWF3ID0gdGhpcy5oZWFkWWF3XG4gICAgfToge1xuICAgICAgICBwb3NpdGlvbjogVmVjdG9yMztcbiAgICAgICAgcGl0Y2g/OiBudW1iZXI7XG4gICAgICAgIHlhdz86IG51bWJlcjtcbiAgICAgICAgaGVhZFlhdz86IG51bWJlcjtcbiAgICB9KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMucGl0Y2ggPSBwaXRjaDtcbiAgICAgICAgdGhpcy55YXcgPSB5YXc7XG4gICAgICAgIHRoaXMuaGVhZFlhdyA9IGhlYWRZYXc7XG5cbiAgICAgICAgYXdhaXQgc3VwZXIuc2V0WChwb3NpdGlvbi5nZXRYKCkpO1xuICAgICAgICBhd2FpdCBzdXBlci5zZXRZKHBvc2l0aW9uLmdldFkoKSk7XG4gICAgICAgIGF3YWl0IHN1cGVyLnNldFoocG9zaXRpb24uZ2V0WigpKTtcblxuICAgICAgICBhd2FpdCB0aGlzLnNlbmRQb3NpdGlvbigpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrIGlmIHRoZSBlbnRpdHkgaXMgYSBwbGF5ZXIuXG4gICAgICogQHJldHVybnMge2Jvb2xlYW59IGB0cnVlYCBpZiB0aGUgZW50aXR5IGlzIHBsYXllci1jb250cm9sbGVkLCBvdGhlcndpc2UgYGZhbHNlYC5cbiAgICAgKiBAZXhhbXBsZVxuICAgICAqIGBgYHR5cGVzY3JpcHRcbiAgICAgKiBpZiAoZW50aXR5LmlzUGxheWVyKCkpIHtcbiAgICAgKiAgICAgY29uc29sZS5sb2coJ0VudGl0eSBpcyBhIHBsYXllcicpO1xuICAgICAqIH0gZWxzZSB7XG4gICAgICogICAgIGNvbnNvbGUubG9nKCdFbnRpdHkgaXMgbm90IGEgcGxheWVyJyk7XG4gICAgICogfVxuICAgICAqIGBgYFxuICAgICAqL1xuICAgIHB1YmxpYyBpc1BsYXllcigpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrIGlmIHRoZSBlbnRpdHkgaXMgYSBjb25zb2xlIGluc3RhbmNlLlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSBgdHJ1ZWAgaWYgdGhlIGVudGl0eSBpcyBjb25zb2xlLWNvbnRyb2xsZWQsIG90aGVyd2lzZSBgZmFsc2VgLlxuICAgICAqIEBleGFtcGxlXG4gICAgICogYGBgdHlwZXNjcmlwdFxuICAgICAqIGlmIChlbnRpdHkuaXNDb25zb2xlKCkpIHtcbiAgICAgKiAgICAgY29uc29sZS5sb2coJ0VudGl0eSBpcyBhIGNvbnNvbGUnKTtcbiAgICAgKiB9IGVsc2Uge1xuICAgICAqICAgICBjb25zb2xlLmxvZygnRW50aXR5IGlzIG5vdCBhIGNvbnNvbGUnKTtcbiAgICAgKiB9XG4gICAgICogYGBgXG4gICAgICovXG4gICAgcHVibGljIGlzQ29uc29sZSgpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0UnVudGltZUlkKCkgPD0gMG47XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IHRoZSBlbnRpdHkncyAocG90ZW50aWFsbHkgY3VzdG9tKSBuYW1lLlxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBlbnRpdHkncyBuYW1lIHdpdGhvdXQgZm9ybWF0dGluZyAodXN1YWxseSBwcmVmaXggJiBzdWZmaXgpLlxuICAgICAqIEBleGFtcGxlXG4gICAgICogYGBgdHlwZXNjcmlwdFxuICAgICAqIGNvbnN0IG5hbWUgPSBlbnRpdHkuZ2V0TmFtZSgpO1xuICAgICAqIGNvbnNvbGUubG9nKGBFbnRpdHkgbmFtZTogJHtuYW1lfWApO1xuICAgICAqIGBgYFxuICAgICAqL1xuICAgIHB1YmxpYyBnZXROYW1lKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldEZvcm1hdHRlZFVzZXJuYW1lKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0IHRoZSBlbnRpdHkncyBuYW1lLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gVGhlIG5hbWUuXG4gICAgICogQGV4YW1wbGVcbiAgICAgKiBgYGB0eXBlc2NyaXB0XG4gICAgICogZW50aXR5LnNldE5hbWUoJ01yLiBTaGVlcCcpO1xuICAgICAqIGBgYFxuICAgICAqL1xuICAgIHB1YmxpYyBzZXROYW1lKG5hbWU6IHN0cmluZyk6IHZvaWQge1xuICAgICAgICB0aGlzLm1ldGFkYXRhLnNldE5hbWVUYWcobmFtZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IHRoZSBlbnRpdHkncyBmb3JtYXR0ZWQgbmFtZS5cbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZW50aXR5J3MgZm9ybWF0dGVkIG5hbWUgKGluY2x1ZGluZyBwcmVmaXggJiBzdWZmaXgpLlxuICAgICAqIEBleGFtcGxlXG4gICAgICogYGBgdHlwZXNjcmlwdFxuICAgICAqIGNvbnN0IGZvcm1hdHRlZE5hbWUgPSBlbnRpdHkuZ2V0Rm9ybWF0dGVkVXNlcm5hbWUoKTtcbiAgICAgKiBjb25zb2xlLmxvZyhgRW50aXR5IGZvcm1hdHRlZCBuYW1lOiAke2Zvcm1hdHRlZE5hbWV9YCk7IC8vIEVudGl0eSBmb3JtYXR0ZWQgbmFtZTogU2hlZXBcbiAgICAgKiBgYGBcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0Rm9ybWF0dGVkVXNlcm5hbWUoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgIHRoaXMubWV0YWRhdGEuZ2V0U3RyaW5nKE1ldGFkYXRhRmxhZy5OQU1FVEFHKSB8fFxuICAgICAgICAgICAgLy8gUmVwbGFjZSBhbGwgJ18nIHdpdGggYSAnICcgYW5kIGNhcGl0YWxpemUgZWFjaCB3b3JkIGFmdGVyd2FyZHMsXG4gICAgICAgICAgICAvLyBzaG91bGQgcHJvYmFibHkgYmUgcmVwbGFjZWQgd2l0aCByZWdleC5cbiAgICAgICAgICAgICgoKHRoaXMuY29uc3RydWN0b3IgYXMgYW55KT8uTU9CX0lEIGFzIHN0cmluZykgfHwgJ1Vua25vd24gRW50aXR5JylcbiAgICAgICAgICAgICAgICAuc3BsaXQoJzonKVsxXSFcbiAgICAgICAgICAgICAgICAucmVwbGFjZUFsbCgnXycsICcgJylcbiAgICAgICAgICAgICAgICAuc3BsaXQoJyAnKVxuICAgICAgICAgICAgICAgIC5tYXAoKHdvcmQpID0+IHdvcmRbMF0hLnRvVXBwZXJDYXNlKCkgKyB3b3JkLnNsaWNlKDEsIHdvcmQubGVuZ3RoKSlcbiAgICAgICAgICAgICAgICAuam9pbignICcpXG4gICAgICAgICk7XG4gICAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7QUFrQkEsSUFBYSxhQUFiLGNBQWdDLFNBQVM7Q0FDckM7Q0FDQTtDQUNBO0NBRUE7Q0FDQTtDQUNBOzs7Ozs7Ozs7Ozs7O0NBY0EsWUFBbUIsRUFDZixNQUNBLFdBQ0EsUUFBUSxHQUNSLE1BQU0sR0FDTixVQUFVLEdBQ1YsR0FBRyxXQVNKO0VBQ0MsTUFBTSxHQUFHLEdBQUcsR0FBRyxRQUFRLEtBQUs7RUFFNUIsS0FBSyxPQUFPLFFBQVEsS0FBSyxhQUFhO0VBQ3RDLEtBQUssWUFBWTtFQUNqQixLQUFLLFNBQVMsUUFBUTtFQUV0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