820 lines
128 KiB
JavaScript
820 lines
128 KiB
JavaScript
/******************************************************************************
|
|
* Spine Runtimes License Agreement
|
|
* Last updated April 5, 2025. Replaces all prior versions.
|
|
*
|
|
* Copyright (c) 2013-2025, Esoteric Software LLC
|
|
*
|
|
* Integration of the Spine Runtimes into software or otherwise creating
|
|
* derivative works of the Spine Runtimes is permitted under the terms and
|
|
* conditions of Section 2 of the Spine Editor License Agreement:
|
|
* http://esotericsoftware.com/spine-editor-license
|
|
*
|
|
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
|
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
|
* "Products"), provided that each user of the Products must obtain their own
|
|
* Spine Editor license and redistribution of the Products in any form must
|
|
* include this license and copyright notice.
|
|
*
|
|
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
|
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*****************************************************************************/
|
|
import { AnimationState, AnimationStateData, AtlasAttachmentLoader, ClippingAttachment, Color, MeshAttachment, Physics, Pool, RegionAttachment, Skeleton, SkeletonBinary, SkeletonClipping, SkeletonData, SkeletonJson, Skin, Utils, Vector2, } from "@esotericsoftware/spine-core";
|
|
import { SlotMesh } from "./SlotMesh.js";
|
|
import { DarkSlotMesh } from "./DarkSlotMesh.js";
|
|
import { Assets } from "@pixi/assets";
|
|
import { Point } from "@pixi/core";
|
|
import { Ticker } from "@pixi/core";
|
|
import { Bounds, Container } from "@pixi/display";
|
|
import { Graphics } from "@pixi/graphics";
|
|
import "@pixi/events";
|
|
;
|
|
/** A bounds provider that provides a fixed size given by the user. */
|
|
export class AABBRectangleBoundsProvider {
|
|
x;
|
|
y;
|
|
width;
|
|
height;
|
|
constructor(x, y, width, height) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.width = width;
|
|
this.height = height;
|
|
}
|
|
calculateBounds() {
|
|
return { x: this.x, y: this.y, width: this.width, height: this.height };
|
|
}
|
|
}
|
|
/** A bounds provider that calculates the bounding box from the setup pose. */
|
|
export class SetupPoseBoundsProvider {
|
|
clipping;
|
|
/**
|
|
* @param clipping If true, clipping attachments are used to compute the bounds. False, by default.
|
|
*/
|
|
constructor(clipping = false) {
|
|
this.clipping = clipping;
|
|
}
|
|
calculateBounds(gameObject) {
|
|
if (!gameObject.skeleton)
|
|
return { x: 0, y: 0, width: 0, height: 0 };
|
|
// Make a copy of animation state and skeleton as this might be called while
|
|
// the skeleton in the GameObject has already been heavily modified. We can not
|
|
// reconstruct that state.
|
|
const skeleton = new Skeleton(gameObject.skeleton.data);
|
|
skeleton.setToSetupPose();
|
|
skeleton.updateWorldTransform(Physics.update);
|
|
const bounds = skeleton.getBoundsRect(this.clipping ? new SkeletonClipping() : undefined);
|
|
return bounds.width == Number.NEGATIVE_INFINITY
|
|
? { x: 0, y: 0, width: 0, height: 0 }
|
|
: bounds;
|
|
}
|
|
}
|
|
/** A bounds provider that calculates the bounding box by taking the maximumg bounding box for a combination of skins and specific animation. */
|
|
export class SkinsAndAnimationBoundsProvider {
|
|
animation;
|
|
skins;
|
|
timeStep;
|
|
clipping;
|
|
/**
|
|
* @param animation The animation to use for calculating the bounds. If null, the setup pose is used.
|
|
* @param skins The skins to use for calculating the bounds. If empty, the default skin is used.
|
|
* @param timeStep The time step to use for calculating the bounds. A smaller time step means more precision, but slower calculation.
|
|
* @param clipping If true, clipping attachments are used to compute the bounds. False, by default.
|
|
*/
|
|
constructor(animation, skins = [], timeStep = 0.05, clipping = false) {
|
|
this.animation = animation;
|
|
this.skins = skins;
|
|
this.timeStep = timeStep;
|
|
this.clipping = clipping;
|
|
}
|
|
calculateBounds(gameObject) {
|
|
if (!gameObject.skeleton || !gameObject.state)
|
|
return { x: 0, y: 0, width: 0, height: 0 };
|
|
// Make a copy of animation state and skeleton as this might be called while
|
|
// the skeleton in the GameObject has already been heavily modified. We can not
|
|
// reconstruct that state.
|
|
const animationState = new AnimationState(gameObject.state.data);
|
|
const skeleton = new Skeleton(gameObject.skeleton.data);
|
|
const clipper = this.clipping ? new SkeletonClipping() : undefined;
|
|
const data = skeleton.data;
|
|
if (this.skins.length > 0) {
|
|
let customSkin = new Skin("custom-skin");
|
|
for (const skinName of this.skins) {
|
|
const skin = data.findSkin(skinName);
|
|
if (skin == null)
|
|
continue;
|
|
customSkin.addSkin(skin);
|
|
}
|
|
skeleton.setSkin(customSkin);
|
|
}
|
|
skeleton.setToSetupPose();
|
|
const animation = this.animation != null ? data.findAnimation(this.animation) : null;
|
|
if (animation == null) {
|
|
skeleton.updateWorldTransform(Physics.update);
|
|
const bounds = skeleton.getBoundsRect(clipper);
|
|
return bounds.width == Number.NEGATIVE_INFINITY
|
|
? { x: 0, y: 0, width: 0, height: 0 }
|
|
: bounds;
|
|
}
|
|
else {
|
|
let minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY;
|
|
animationState.clearTracks();
|
|
animationState.setAnimationWith(0, animation, false);
|
|
const steps = Math.max(animation.duration / this.timeStep, 1.0);
|
|
for (let i = 0; i < steps; i++) {
|
|
const delta = i > 0 ? this.timeStep : 0;
|
|
animationState.update(delta);
|
|
animationState.apply(skeleton);
|
|
skeleton.update(delta);
|
|
skeleton.updateWorldTransform(Physics.update);
|
|
const bounds = skeleton.getBoundsRect(clipper);
|
|
minX = Math.min(minX, bounds.x);
|
|
minY = Math.min(minY, bounds.y);
|
|
maxX = Math.max(maxX, bounds.x + bounds.width);
|
|
maxY = Math.max(maxY, bounds.y + bounds.height);
|
|
}
|
|
const bounds = {
|
|
x: minX,
|
|
y: minY,
|
|
width: maxX - minX,
|
|
height: maxY - minY,
|
|
};
|
|
return bounds.width == Number.NEGATIVE_INFINITY
|
|
? { x: 0, y: 0, width: 0, height: 0 }
|
|
: bounds;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* The class to instantiate a {@link Spine} game object in Pixi.
|
|
* The static method {@link Spine.from} should be used to instantiate a Spine game object.
|
|
*/
|
|
export class Spine extends Container {
|
|
/** The skeleton for this Spine game object. */
|
|
skeleton;
|
|
/** The animation state for this Spine game object. */
|
|
state;
|
|
darkTint = false;
|
|
hasNeverUpdated = true;
|
|
_debug = undefined;
|
|
get debug() {
|
|
return this._debug;
|
|
}
|
|
/** Pass a {@link SpineDebugRenderer} or create your own {@link ISpineDebugRenderer} to render bones, meshes, ...
|
|
* @example spineGO.debug = new SpineDebugRenderer();
|
|
*/
|
|
set debug(value) {
|
|
if (this._debug) {
|
|
this._debug.unregisterSpine(this);
|
|
}
|
|
if (value) {
|
|
value.registerSpine(this);
|
|
}
|
|
this._debug = value;
|
|
}
|
|
slotMeshFactory = () => new SlotMesh();
|
|
beforeUpdateWorldTransforms = () => { };
|
|
afterUpdateWorldTransforms = () => { };
|
|
_autoUpdate = false;
|
|
_ticker = Ticker.shared;
|
|
get autoUpdate() {
|
|
return this._autoUpdate;
|
|
}
|
|
/** When `true`, the Spine AnimationState and the Skeleton will be automatically updated using the {@link ticker}. */
|
|
set autoUpdate(value) {
|
|
if (value && !this._autoUpdate) {
|
|
this._ticker.add(this.internalUpdate, this);
|
|
}
|
|
else if (!value && this._autoUpdate) {
|
|
this._ticker.remove(this.internalUpdate, this);
|
|
}
|
|
this._autoUpdate = value;
|
|
}
|
|
/** The ticker to use when {@link autoUpdate} is `true`. Defaults to {@link Ticker.shared}. */
|
|
get ticker() {
|
|
return this._ticker;
|
|
}
|
|
/** Sets the ticker to use when {@link autoUpdate} is `true`. If `autoUpdate` is already `true`, the update callback will be moved from the old ticker to the new one. */
|
|
set ticker(value) {
|
|
value = value ?? Ticker.shared;
|
|
if (this._ticker === value)
|
|
return;
|
|
if (this._autoUpdate) {
|
|
this._ticker.remove(this.internalUpdate, this);
|
|
value.add(this.internalUpdate, this);
|
|
}
|
|
this._ticker = value;
|
|
}
|
|
meshesCache = new Map();
|
|
static vectorAux = new Vector2();
|
|
static clipper = new SkeletonClipping();
|
|
static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0];
|
|
static VERTEX_SIZE = 2 + 2 + 4;
|
|
static DARK_VERTEX_SIZE = 2 + 2 + 4 + 4;
|
|
lightColor = new Color();
|
|
darkColor = new Color();
|
|
_boundsProvider;
|
|
/** The bounds provider to use. If undefined the bounds will be dynamic, calculated when requested and based on the current frame. */
|
|
get boundsProvider() {
|
|
return this._boundsProvider;
|
|
}
|
|
set boundsProvider(value) {
|
|
this._boundsProvider = value;
|
|
if (value) {
|
|
this._boundsSpineID = -1;
|
|
this._boundsSpineDirty = true;
|
|
this.interactiveChildren = false;
|
|
}
|
|
else {
|
|
this.interactiveChildren = true;
|
|
this.hitArea = null;
|
|
}
|
|
if (!this.hasNeverUpdated) {
|
|
this.calculateBounds();
|
|
}
|
|
}
|
|
_boundsPoint = new Point();
|
|
_boundsSpineID = -1;
|
|
_boundsSpineDirty = true;
|
|
constructor(options, oldOptions) {
|
|
if (options instanceof SkeletonData) {
|
|
options = {
|
|
...oldOptions,
|
|
skeletonData: options,
|
|
};
|
|
}
|
|
else if (oldOptions) {
|
|
throw new Error("You cannot use options and oldOptions together.");
|
|
}
|
|
super();
|
|
const skeletonData = options instanceof SkeletonData ? options : options.skeletonData;
|
|
this.skeleton = new Skeleton(skeletonData);
|
|
const animData = new AnimationStateData(skeletonData);
|
|
this.state = new AnimationState(animData);
|
|
// dark tint can be enabled by options, otherwise is enable if at least one slot has tint black
|
|
if (options?.darkTint !== undefined || oldOptions?.slotMeshFactory === undefined) {
|
|
this.darkTint = options?.darkTint === undefined
|
|
? this.skeleton.slots.some(slot => !!slot.data.darkColor)
|
|
: options?.darkTint;
|
|
if (this.darkTint)
|
|
this.slotMeshFactory = () => new DarkSlotMesh();
|
|
}
|
|
else {
|
|
this.initializeMeshFactory(oldOptions?.slotMeshFactory);
|
|
}
|
|
if (options?.ticker)
|
|
this._ticker = options.ticker;
|
|
this.autoUpdate = options?.autoUpdate ?? true;
|
|
this.boundsProvider = options.boundsProvider;
|
|
}
|
|
/*
|
|
* @deprecated Remove when slotMeshFactory options is removed
|
|
*/
|
|
initializeMeshFactory(slotMeshFactory) {
|
|
if (slotMeshFactory) {
|
|
this.slotMeshFactory = slotMeshFactory;
|
|
const tempSlotMeshFactory = this.slotMeshFactory();
|
|
if (tempSlotMeshFactory instanceof DarkSlotMesh)
|
|
this.darkTint = true;
|
|
tempSlotMeshFactory.destroy();
|
|
}
|
|
else {
|
|
for (let i = 0; i < this.skeleton.slots.length; i++) {
|
|
if (this.skeleton.slots[i].data.darkColor) {
|
|
this.slotMeshFactory = () => new DarkSlotMesh();
|
|
this.darkTint = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/** If {@link Spine.autoUpdate} is `false`, this method allows to update the AnimationState and the Skeleton with the given delta. */
|
|
update(deltaSeconds) {
|
|
this.internalUpdate(0, deltaSeconds);
|
|
}
|
|
internalUpdate(_deltaFrame, deltaSeconds) {
|
|
this.hasNeverUpdated = false;
|
|
// Because reasons, pixi uses deltaFrames at 60fps. We ignore the default deltaFrames and use the deltaSeconds from pixi ticker.
|
|
const delta = deltaSeconds ?? this._ticker.deltaMS / 1000;
|
|
this.state.update(delta);
|
|
this.state.apply(this.skeleton);
|
|
this.beforeUpdateWorldTransforms(this);
|
|
this.skeleton.update(delta);
|
|
this.skeleton.updateWorldTransform(Physics.update);
|
|
this.afterUpdateWorldTransforms(this);
|
|
}
|
|
/** Render the meshes based on the current skeleton state, render debug information, then call {@link Container.updateTransform}. */
|
|
updateTransform() {
|
|
this.renderMeshes();
|
|
this.sortChildren();
|
|
this.debug?.renderDebug(this);
|
|
super.updateTransform();
|
|
}
|
|
/** Destroy Spine game object elements, then call the {@link Container.destroy} with the given options */
|
|
destroy(options) {
|
|
if (this.autoUpdate)
|
|
this.autoUpdate = false;
|
|
this._ticker = null;
|
|
for (const [, mesh] of this.meshesCache) {
|
|
mesh?.destroy();
|
|
}
|
|
this.state.clearListeners();
|
|
this.debug = undefined;
|
|
this.meshesCache.clear();
|
|
this.slotsObject.clear();
|
|
for (let maskKey in this.clippingSlotToPixiMasks) {
|
|
const maskObj = this.clippingSlotToPixiMasks[maskKey];
|
|
maskObj.mask?.destroy();
|
|
delete this.clippingSlotToPixiMasks[maskKey];
|
|
}
|
|
super.destroy(options);
|
|
}
|
|
resetMeshes() {
|
|
for (const [, mesh] of this.meshesCache) {
|
|
mesh.zIndex = -1;
|
|
mesh.visible = false;
|
|
}
|
|
}
|
|
_calculateBounds() {
|
|
if (this.hasNeverUpdated) {
|
|
this.internalUpdate(0, 0);
|
|
this.renderMeshes();
|
|
}
|
|
}
|
|
/**
|
|
* Check the existence of a mesh for the given slot.
|
|
* If you want to manually handle which meshes go on which slot and how you cache, overwrite this method.
|
|
*/
|
|
hasMeshForSlot(slot) {
|
|
return this.meshesCache.has(slot);
|
|
}
|
|
/**
|
|
* Search the mesh corresponding to the given slot or create it, if it does not exists.
|
|
* If you want to manually handle which meshes go on which slot and how you cache, overwrite this method.
|
|
*/
|
|
getMeshForSlot(slot) {
|
|
if (!this.hasMeshForSlot(slot)) {
|
|
let mesh = this.slotMeshFactory();
|
|
this.addChild(mesh);
|
|
this.meshesCache.set(slot, mesh);
|
|
return mesh;
|
|
}
|
|
else {
|
|
let mesh = this.meshesCache.get(slot);
|
|
mesh.visible = true;
|
|
return mesh;
|
|
}
|
|
}
|
|
slotsObject = new Map();
|
|
getSlotFromRef(slotRef) {
|
|
let slot;
|
|
if (typeof slotRef === 'number')
|
|
slot = this.skeleton.slots[slotRef];
|
|
else if (typeof slotRef === 'string')
|
|
slot = this.skeleton.findSlot(slotRef);
|
|
else
|
|
slot = slotRef;
|
|
if (!slot)
|
|
throw new Error(`No slot found with the given slot reference: ${slotRef}`);
|
|
return slot;
|
|
}
|
|
/**
|
|
* Add a pixi Container as a child of the Spine object.
|
|
* The Container will be rendered coherently with the draw order of the slot.
|
|
* If an attachment is active on the slot, the pixi Container will be rendered on top of it.
|
|
* If the Container is already attached to the given slot, nothing will happen.
|
|
* If the Container is already attached to another slot, it will be removed from that slot
|
|
* before adding it to the given one.
|
|
* If another Container is already attached to this slot, the old one will be removed from this
|
|
* slot before adding it to the current one.
|
|
* @param slotRef - The slot index, or the slot name, or the Slot where the pixi object will be added to.
|
|
* @param pixiObject - The pixi Container to add.
|
|
* @param options - Optional settings for the attachment.
|
|
* @param options.followAttachmentTimeline - If true, the attachment will follow the slot's attachment timeline.
|
|
* @param options.followSlotColor - If true, the container tint will follow the skeleton and slot colors.
|
|
*/
|
|
addSlotObject(slotRef, pixiObject, options) {
|
|
let slot = this.getSlotFromRef(slotRef);
|
|
const oldPixiObject = this.slotsObject.get(slot)?.container;
|
|
if (oldPixiObject && oldPixiObject === pixiObject)
|
|
return;
|
|
// search if the pixiObject was already in another slotObject
|
|
for (const [otherSlot, { container: oldPixiObjectAnotherSlot }] of this.slotsObject) {
|
|
if (otherSlot !== slot && oldPixiObjectAnotherSlot === pixiObject) {
|
|
this.removeSlotObject(otherSlot, pixiObject);
|
|
break;
|
|
}
|
|
}
|
|
if (oldPixiObject)
|
|
this.removeChild(oldPixiObject);
|
|
this.slotsObject.set(slot, {
|
|
container: pixiObject,
|
|
followAttachmentTimeline: options?.followAttachmentTimeline || false,
|
|
followSlotColor: options?.followSlotColor || false,
|
|
});
|
|
this.addChild(pixiObject);
|
|
}
|
|
/**
|
|
* Return the Container connected to the given slot, if any.
|
|
* Otherwise return undefined
|
|
* @param pixiObject - The slot index, or the slot name, or the Slot to get the Container from.
|
|
* @returns a Container if any, undefined otherwise.
|
|
*/
|
|
getSlotObject(slotRef) {
|
|
const element = this.slotsObject.get(this.getSlotFromRef(slotRef));
|
|
return element ? element.container : undefined;
|
|
}
|
|
/**
|
|
* Remove a slot object from the given slot.
|
|
* If `pixiObject` is passed and attached to the given slot, remove it from the slot.
|
|
* If `pixiObject` is not passed and the given slot has an attached Container, remove it from the slot.
|
|
* @param slotRef - The slot index, or the slot name, or the Slot where the pixi object will be remove from.
|
|
* @param pixiObject - Optional, The pixi Container to remove.
|
|
*/
|
|
removeSlotObject(slotRef, pixiObject) {
|
|
let slot = this.getSlotFromRef(slotRef);
|
|
let slotObject = this.slotsObject.get(slot)?.container;
|
|
if (!slotObject)
|
|
return;
|
|
// if pixiObject is passed, remove only if it is equal to the given one
|
|
if (pixiObject && pixiObject !== slotObject)
|
|
return;
|
|
this.removeChild(slotObject);
|
|
this.slotsObject.delete(slot);
|
|
}
|
|
/**
|
|
* Removes all PixiJS containers attached to any slot.
|
|
*/
|
|
removeSlotObjects() {
|
|
for (const [, slotObject] of this.slotsObject) {
|
|
slotObject.container.removeFromParent();
|
|
}
|
|
this.slotsObject.clear();
|
|
}
|
|
verticesCache = Utils.newFloatArray(1024);
|
|
clippingSlotToPixiMasks = {};
|
|
updateSlotObject(element, slot, zIndex) {
|
|
const { container: slotObject, followAttachmentTimeline } = element;
|
|
const followAttachmentValue = followAttachmentTimeline ? Boolean(slot.attachment) : true;
|
|
slotObject.visible = this.skeleton.drawOrder.includes(slot) && followAttachmentValue;
|
|
if (slotObject.visible) {
|
|
let bone = slot.bone;
|
|
const matrix = slotObject.localTransform;
|
|
matrix.a = bone.a;
|
|
matrix.b = bone.c;
|
|
matrix.c = -bone.b;
|
|
matrix.d = -bone.d;
|
|
matrix.tx = bone.worldX;
|
|
matrix.ty = bone.worldY;
|
|
slotObject.transform.setFromMatrix(matrix);
|
|
slotObject.zIndex = zIndex;
|
|
slotObject.alpha = this.skeleton.color.a * slot.color.a;
|
|
if (element.followSlotColor) {
|
|
this.setSlotObjectTint(slotObject, ((255 * this.skeleton.color.r * slot.color.r) << 16) |
|
|
((255 * this.skeleton.color.g * slot.color.g) << 8) |
|
|
(255 * this.skeleton.color.b * slot.color.b));
|
|
}
|
|
}
|
|
}
|
|
setSlotObjectTint(slotObject, tint) {
|
|
const tintable = slotObject;
|
|
if ("tint" in tintable)
|
|
tintable.tint = tint;
|
|
for (const child of tintable.children ?? []) {
|
|
this.setSlotObjectTint(child, tint);
|
|
}
|
|
}
|
|
currentClippingSlot;
|
|
updateAndSetPixiMask(slot, last) {
|
|
// assign/create the currentClippingSlot
|
|
const attachment = slot.attachment;
|
|
if (attachment && attachment instanceof ClippingAttachment) {
|
|
const clip = (this.clippingSlotToPixiMasks[slot.data.name] ||= { slot, vertices: new Array() });
|
|
clip.maskComputed = false;
|
|
this.currentClippingSlot = clip;
|
|
return;
|
|
}
|
|
// assign the currentClippingSlot mask to the slot object
|
|
let currentClippingSlot = this.currentClippingSlot;
|
|
const slotObject = this.slotsObject.get(slot);
|
|
if (currentClippingSlot && slotObject) {
|
|
// create the pixi mask, only the first time and if the clipped slot is the first one clipped by this currentClippingSlot
|
|
let mask = currentClippingSlot.mask;
|
|
if (!mask) {
|
|
mask = maskPool.obtain();
|
|
currentClippingSlot.mask = mask;
|
|
this.addChild(mask);
|
|
}
|
|
// compute the pixi mask polygon, if the clipped slot is the first one clipped by this currentClippingSlot
|
|
if (!currentClippingSlot.maskComputed) {
|
|
let slotClipping = currentClippingSlot.slot;
|
|
let clippingAttachment = slotClipping.attachment;
|
|
currentClippingSlot.maskComputed = true;
|
|
const worldVerticesLength = clippingAttachment.worldVerticesLength;
|
|
const vertices = currentClippingSlot.vertices;
|
|
clippingAttachment.computeWorldVertices(slotClipping, 0, worldVerticesLength, vertices, 0, 2);
|
|
mask.clear().lineStyle(0).beginFill(0x000000).drawPolygon(vertices).endFill();
|
|
}
|
|
slotObject.container.mask = mask;
|
|
}
|
|
else if (slotObject?.container.mask) {
|
|
// remove the mask, if slot object has a mask, but currentClippingSlot is undefined
|
|
slotObject.container.mask = null;
|
|
}
|
|
// if current slot is the ending one of the currentClippingSlot mask, set currentClippingSlot to undefined
|
|
if (currentClippingSlot && currentClippingSlot.slot.attachment.endSlot == slot.data) {
|
|
this.currentClippingSlot = undefined;
|
|
}
|
|
// clean up unused masks
|
|
if (last) {
|
|
for (const key in this.clippingSlotToPixiMasks) {
|
|
const clippingSlotToPixiMask = this.clippingSlotToPixiMasks[key];
|
|
if ((!(clippingSlotToPixiMask.slot.attachment instanceof ClippingAttachment) || !clippingSlotToPixiMask.maskComputed) && clippingSlotToPixiMask.mask) {
|
|
this.removeChild(clippingSlotToPixiMask.mask);
|
|
maskPool.free(clippingSlotToPixiMask.mask);
|
|
clippingSlotToPixiMask.mask = undefined;
|
|
}
|
|
}
|
|
this.currentClippingSlot = undefined;
|
|
}
|
|
}
|
|
/*
|
|
* Colors in pixi are premultiplied.
|
|
* Pixi blending modes are modified to work with premultiplied colors. We cannot create custom blending modes.
|
|
* Textures are loaded as premultiplied (see assers/atlasLoader.ts: alphaMode: `page.pma ? ALPHA_MODES.PMA : ALPHA_MODES.UNPACK`):
|
|
* - textures non premultiplied are premultiplied on GPU on upload
|
|
* - textures premultiplied are uploaded on GPU as is since they are already premultiplied
|
|
*
|
|
* We need to take this into consideration and calculates final colors for both light and dark color as if textures were always premultiplied.
|
|
* This implies for example that alpha for dark tint is always 1. This is way in DarkTintRenderer we have only the alpha of the light color.
|
|
* If we ever want to load texture as non premultiplied on GPU, we must add a new dark alpha parameter to the TintMaterial and set the alpha.
|
|
*/
|
|
renderMeshes() {
|
|
this.resetMeshes();
|
|
let triangles = null;
|
|
let uvs = null;
|
|
const drawOrder = this.skeleton.drawOrder;
|
|
for (let i = 0, n = drawOrder.length, slotObjectsCounter = 0; i < n; i++) {
|
|
const slot = drawOrder[i];
|
|
// render pixi object on the current slot on top of the slot attachment
|
|
let pixiObject = this.slotsObject.get(slot);
|
|
let zIndex = i + slotObjectsCounter;
|
|
if (pixiObject) {
|
|
this.updateSlotObject(pixiObject, slot, zIndex + 1);
|
|
slotObjectsCounter++;
|
|
}
|
|
this.updateAndSetPixiMask(slot, i === drawOrder.length - 1);
|
|
const useDarkColor = slot.darkColor != null;
|
|
const vertexSize = Spine.clipper.isClipping() ? 2 : useDarkColor ? Spine.DARK_VERTEX_SIZE : Spine.VERTEX_SIZE;
|
|
if (!slot.bone.active) {
|
|
Spine.clipper.clipEndWithSlot(slot);
|
|
continue;
|
|
}
|
|
const attachment = slot.getAttachment();
|
|
let attachmentColor;
|
|
let texture;
|
|
let numFloats = 0;
|
|
if (attachment instanceof RegionAttachment) {
|
|
const region = attachment;
|
|
attachmentColor = region.color;
|
|
numFloats = vertexSize * 4;
|
|
region.computeWorldVertices(slot, this.verticesCache, 0, vertexSize);
|
|
triangles = Spine.QUAD_TRIANGLES;
|
|
uvs = region.uvs;
|
|
texture = region.region?.texture;
|
|
}
|
|
else if (attachment instanceof MeshAttachment) {
|
|
const mesh = attachment;
|
|
attachmentColor = mesh.color;
|
|
numFloats = (mesh.worldVerticesLength >> 1) * vertexSize;
|
|
if (numFloats > this.verticesCache.length) {
|
|
this.verticesCache = Utils.newFloatArray(numFloats);
|
|
}
|
|
mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, this.verticesCache, 0, vertexSize);
|
|
triangles = mesh.triangles;
|
|
uvs = mesh.uvs;
|
|
texture = mesh.region?.texture;
|
|
}
|
|
else if (attachment instanceof ClippingAttachment) {
|
|
Spine.clipper.clipStart(slot, attachment);
|
|
continue;
|
|
}
|
|
else {
|
|
if (this.hasMeshForSlot(slot)) {
|
|
this.getMeshForSlot(slot).visible = false;
|
|
}
|
|
Spine.clipper.clipEndWithSlot(slot);
|
|
continue;
|
|
}
|
|
if (texture != null) {
|
|
const skeleton = slot.bone.skeleton;
|
|
const skeletonColor = skeleton.color;
|
|
const slotColor = slot.color;
|
|
const alpha = skeletonColor.a * slotColor.a * attachmentColor.a;
|
|
// cannot premultiply the colors because the default mesh renderer already does that
|
|
this.lightColor.set(skeletonColor.r * slotColor.r * attachmentColor.r, skeletonColor.g * slotColor.g * attachmentColor.g, skeletonColor.b * slotColor.b * attachmentColor.b, alpha);
|
|
if (slot.darkColor != null) {
|
|
this.darkColor.set(slot.darkColor.r, slot.darkColor.g, slot.darkColor.b, 1);
|
|
}
|
|
else {
|
|
this.darkColor.set(0, 0, 0, 1);
|
|
}
|
|
let finalVertices;
|
|
let finalVerticesLength;
|
|
let finalIndices;
|
|
let finalIndicesLength;
|
|
if (Spine.clipper.isClipping()) {
|
|
Spine.clipper.clipTriangles(this.verticesCache, triangles, triangles.length, uvs, this.lightColor, this.darkColor, useDarkColor);
|
|
finalVertices = Spine.clipper.clippedVertices;
|
|
finalVerticesLength = finalVertices.length;
|
|
finalIndices = Spine.clipper.clippedTriangles;
|
|
finalIndicesLength = finalIndices.length;
|
|
}
|
|
else {
|
|
const verts = this.verticesCache;
|
|
for (let v = 2, u = 0, n = numFloats; v < n; v += vertexSize, u += 2) {
|
|
let tempV = v;
|
|
verts[tempV++] = this.lightColor.r;
|
|
verts[tempV++] = this.lightColor.g;
|
|
verts[tempV++] = this.lightColor.b;
|
|
verts[tempV++] = this.lightColor.a;
|
|
verts[tempV++] = uvs[u];
|
|
verts[tempV++] = uvs[u + 1];
|
|
if (useDarkColor) {
|
|
verts[tempV++] = this.darkColor.r;
|
|
verts[tempV++] = this.darkColor.g;
|
|
verts[tempV++] = this.darkColor.b;
|
|
verts[tempV++] = this.darkColor.a;
|
|
}
|
|
}
|
|
finalVertices = this.verticesCache;
|
|
finalVerticesLength = numFloats;
|
|
finalIndices = triangles;
|
|
finalIndicesLength = triangles.length;
|
|
}
|
|
if (finalVerticesLength == 0 || finalIndicesLength == 0) {
|
|
Spine.clipper.clipEndWithSlot(slot);
|
|
continue;
|
|
}
|
|
const mesh = this.getMeshForSlot(slot);
|
|
mesh.renderable = true;
|
|
mesh.zIndex = zIndex;
|
|
mesh.updateFromSpineData(texture, slot.data.blendMode, slot.data.name, finalVertices, finalVerticesLength, finalIndices, finalIndicesLength, useDarkColor);
|
|
}
|
|
Spine.clipper.clipEndWithSlot(slot);
|
|
}
|
|
Spine.clipper.clipEnd();
|
|
}
|
|
calculateBounds() {
|
|
if (!this._boundsProvider) {
|
|
super.calculateBounds();
|
|
return;
|
|
}
|
|
const transform = this.transform;
|
|
if (this._boundsSpineID === transform._worldID)
|
|
return;
|
|
this.updateBounds();
|
|
const bounds = this._localBounds;
|
|
const p = this._boundsPoint;
|
|
p.set(bounds.minX, bounds.minY);
|
|
transform.worldTransform.apply(p, p);
|
|
this._bounds.minX = p.x;
|
|
this._bounds.minY = p.y;
|
|
p.set(bounds.maxX, bounds.maxY);
|
|
transform.worldTransform.apply(p, p);
|
|
this._bounds.maxX = p.x;
|
|
this._bounds.maxY = p.y;
|
|
}
|
|
updateBounds() {
|
|
if (!this._boundsProvider || !this._boundsSpineDirty)
|
|
return;
|
|
this._boundsSpineDirty = false;
|
|
if (!this._localBounds) {
|
|
this._localBounds = new Bounds();
|
|
}
|
|
const boundsSpine = this._boundsProvider.calculateBounds(this);
|
|
const bounds = this._localBounds;
|
|
bounds.clear();
|
|
bounds.minX = boundsSpine.x;
|
|
bounds.minY = boundsSpine.y;
|
|
bounds.maxX = boundsSpine.x + boundsSpine.width;
|
|
bounds.maxY = boundsSpine.y + boundsSpine.height;
|
|
this.hitArea = this._localBounds.getRectangle();
|
|
}
|
|
/**
|
|
* Set the position of the bone given in input through a {@link IPointData}.
|
|
* @param bone: the bone name or the bone instance to set the position
|
|
* @param outPos: the new position of the bone.
|
|
* @throws {Error}: if the given bone is not found in the skeleton, an error is thrown
|
|
*/
|
|
setBonePosition(bone, position) {
|
|
const boneAux = bone;
|
|
if (typeof bone === "string") {
|
|
bone = this.skeleton.findBone(bone);
|
|
}
|
|
if (!bone)
|
|
throw Error(`Cannot set bone position, bone ${String(boneAux)} not found`);
|
|
Spine.vectorAux.set(position.x, position.y);
|
|
if (bone.parent) {
|
|
const aux = bone.parent.worldToLocal(Spine.vectorAux);
|
|
bone.x = aux.x;
|
|
bone.y = aux.y;
|
|
}
|
|
else {
|
|
bone.x = Spine.vectorAux.x;
|
|
bone.y = Spine.vectorAux.y;
|
|
}
|
|
}
|
|
/**
|
|
* Return the position of the bone given in input into an {@link IPointData}.
|
|
* @param bone: the bone name or the bone instance to get the position from
|
|
* @param outPos: an optional {@link IPointData} to use to return the bone position, rathern than instantiating a new object.
|
|
* @returns {IPointData | undefined}: the position of the bone, or undefined if no matching bone is found in the skeleton
|
|
*/
|
|
getBonePosition(bone, outPos) {
|
|
const boneAux = bone;
|
|
if (typeof bone === "string") {
|
|
bone = this.skeleton.findBone(bone);
|
|
}
|
|
if (!bone) {
|
|
console.error(`Cannot get bone position! Bone ${String(boneAux)} not found`);
|
|
return outPos;
|
|
}
|
|
if (!outPos) {
|
|
outPos = { x: 0, y: 0 };
|
|
}
|
|
outPos.x = bone.worldX;
|
|
outPos.y = bone.worldY;
|
|
return outPos;
|
|
}
|
|
/** Converts a point from the skeleton coordinate system to the Pixi world coordinate system. */
|
|
skeletonToPixiWorldCoordinates(point) {
|
|
this.worldTransform.apply(point, point);
|
|
}
|
|
/** Converts a point from the Pixi world coordinate system to the skeleton coordinate system. */
|
|
pixiWorldCoordinatesToSkeleton(point) {
|
|
this.worldTransform.applyInverse(point, point);
|
|
}
|
|
/** Converts a point from the Pixi world coordinate system to the bone's local coordinate system. */
|
|
pixiWorldCoordinatesToBone(point, bone) {
|
|
this.pixiWorldCoordinatesToSkeleton(point);
|
|
if (bone.parent) {
|
|
bone.parent.worldToLocal(point);
|
|
}
|
|
else {
|
|
bone.worldToLocal(point);
|
|
}
|
|
}
|
|
/** A cache containing skeleton data and atlases already loaded by {@link Spine.from}. */
|
|
static skeletonCache = Object.create(null);
|
|
static from(paramOne, atlasAssetName, options) {
|
|
if (typeof paramOne === "string") {
|
|
return Spine.oldFrom(paramOne, atlasAssetName, options);
|
|
}
|
|
const { skeleton, atlas, scale = 1, darkTint, autoUpdate, boundsProvider, ticker } = paramOne;
|
|
const cacheKey = `${skeleton}-${atlas}-${scale}`;
|
|
let skeletonData = Spine.skeletonCache[cacheKey];
|
|
if (!skeletonData) {
|
|
const skeletonAsset = Assets.get(skeleton);
|
|
const atlasAsset = Assets.get(atlas);
|
|
const attachmentLoader = new AtlasAttachmentLoader(atlasAsset);
|
|
let parser = skeletonAsset instanceof Uint8Array ? new SkeletonBinary(attachmentLoader) : new SkeletonJson(attachmentLoader);
|
|
parser.scale = scale;
|
|
skeletonData = parser.readSkeletonData(skeletonAsset);
|
|
Spine.skeletonCache[cacheKey] = skeletonData;
|
|
}
|
|
return new Spine({ skeletonData, darkTint, autoUpdate, boundsProvider, ticker });
|
|
}
|
|
static oldFrom(skeletonAssetName, atlasAssetName, options) {
|
|
const cacheKey = `${skeletonAssetName}-${atlasAssetName}-${options?.scale ?? 1}`;
|
|
let skeletonData = Spine.skeletonCache[cacheKey];
|
|
if (skeletonData) {
|
|
return new Spine(skeletonData, options);
|
|
}
|
|
const skeletonAsset = Assets.get(skeletonAssetName);
|
|
const atlasAsset = Assets.get(atlasAssetName);
|
|
const attachmentLoader = new AtlasAttachmentLoader(atlasAsset);
|
|
let parser = skeletonAsset instanceof Uint8Array ? new SkeletonBinary(attachmentLoader) : new SkeletonJson(attachmentLoader);
|
|
parser.scale = options?.scale ?? 1;
|
|
skeletonData = parser.readSkeletonData(skeletonAsset);
|
|
Spine.skeletonCache[cacheKey] = skeletonData;
|
|
return new this(skeletonData, options);
|
|
}
|
|
get tint() {
|
|
return this.skeleton.color.toRgb888();
|
|
}
|
|
set tint(value) {
|
|
Color.rgb888ToColor(this.skeleton.color, value);
|
|
}
|
|
}
|
|
;
|
|
const maskPool = new Pool(() => new Graphics);
|
|
Skeleton.yDown = true;
|
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU3BpbmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvU3BpbmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsrRUEyQitFO0FBRy9FLE9BQU8sRUFDTixjQUFjLEVBQ2Qsa0JBQWtCLEVBQ2xCLHFCQUFxQixFQUNyQixrQkFBa0IsRUFDbEIsS0FBSyxFQUNMLGNBQWMsRUFDZCxPQUFPLEVBQ1AsSUFBSSxFQUNKLGdCQUFnQixFQUNoQixRQUFRLEVBQ1IsY0FBYyxFQUNkLGdCQUFnQixFQUNoQixZQUFZLEVBQ1osWUFBWSxFQUNaLElBQUksRUFDSixLQUFLLEVBQ0wsT0FBTyxHQUNQLE1BQU0sOEJBQThCLENBQUM7QUFFdEMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFFakQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUN0QyxPQUFPLEVBQWMsS0FBSyxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQy9DLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFcEMsT0FBTyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDbEQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzFDLE9BQU8sY0FBYyxDQUFDO0FBZ0RyQixDQUFDO0FBMENGLHNFQUFzRTtBQUN0RSxNQUFNLE9BQU8sMkJBQTJCO0lBRTlCO0lBQ0E7SUFDQTtJQUNBO0lBSlQsWUFDUyxDQUFTLEVBQ1QsQ0FBUyxFQUNULEtBQWEsRUFDYixNQUFjO1FBSGQsTUFBQyxHQUFELENBQUMsQ0FBUTtRQUNULE1BQUMsR0FBRCxDQUFDLENBQVE7UUFDVCxVQUFLLEdBQUwsS0FBSyxDQUFRO1FBQ2IsV0FBTSxHQUFOLE1BQU0sQ0FBUTtJQUNuQixD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QWUsY0FBYyxDQUFDLENBQUM7UUFDNUQsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLHFCQUFxQixDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQy9ELElBQUksTUFBTSxHQUFHLGFBQWEsWUFBWSxVQUFVLENBQUMsQ0FBQyxDQUFDLElBQUksY0FBYyxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksWUFBWSxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDN0gsTUFBTSxDQUFDLEtBQUssR0FBRyxPQUFPLEVBQUUsS0FBSyxJQUFJLENBQUMsQ0FBQztRQUNuQyxZQUFZLEdBQUcsTUFBTSxDQUFDLGdCQUFnQixDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQ3RELEtBQUssQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLEdBQUcsWUFBWSxDQUFDO1FBQzdDLE9BQU8sSUFBSSxJQUFJLENBQUMsWUFBWSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQ3hDLENBQUM7SUFFRCxJQUFXLElBQUk7UUFDZCxPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQ3ZDLENBQUM7SUFDRCxJQUFXLElBQUksQ0FBRSxLQUFhO1FBQzdCLEtBQUssQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDakQsQ0FBQzs7QUFRRCxDQUFDO0FBRUYsTUFBTSxRQUFRLEdBQUcsSUFBSSxJQUFJLENBQVcsR0FBRyxFQUFFLENBQUMsSUFBSSxRQUFRLENBQUMsQ0FBQztBQUV4RCxRQUFRLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcbiAqIFNwaW5lIFJ1bnRpbWVzIExpY2Vuc2UgQWdyZWVtZW50XG4gKiBMYXN0IHVwZGF0ZWQgQXByaWwgNSwgMjAyNS4gUmVwbGFjZXMgYWxsIHByaW9yIHZlcnNpb25zLlxuICpcbiAqIENvcHlyaWdodCAoYykgMjAxMy0yMDI1LCBFc290ZXJpYyBTb2Z0d2FyZSBMTENcbiAqXG4gKiBJbnRlZ3JhdGlvbiBvZiB0aGUgU3BpbmUgUnVudGltZXMgaW50byBzb2Z0d2FyZSBvciBvdGhlcndpc2UgY3JlYXRpbmdcbiAqIGRlcml2YXRpdmUgd29ya3Mgb2YgdGhlIFNwaW5lIFJ1bnRpbWVzIGlzIHBlcm1pdHRlZCB1bmRlciB0aGUgdGVybXMgYW5kXG4gKiBjb25kaXRpb25zIG9mIFNlY3Rpb24gMiBvZiB0aGUgU3BpbmUgRWRpdG9yIExpY2Vuc2UgQWdyZWVtZW50OlxuICogaHR0cDovL2Vzb3Rlcmljc29mdHdhcmUuY29tL3NwaW5lLWVkaXRvci1saWNlbnNlXG4gKlxuICogT3RoZXJ3aXNlLCBpdCBpcyBwZXJtaXR0ZWQgdG8gaW50ZWdyYXRlIHRoZSBTcGluZSBSdW50aW1lcyBpbnRvIHNvZnR3YXJlXG4gKiBvciBvdGhlcndpc2UgY3JlYXRlIGRlcml2YXRpdmUgd29ya3Mgb2YgdGhlIFNwaW5lIFJ1bnRpbWVzIChjb2xsZWN0aXZlbHksXG4gKiBcIlByb2R1Y3RzXCIpLCBwcm92aWRlZCB0aGF0IGVhY2ggdXNlciBvZiB0aGUgUHJvZHVjdHMgbXVzdCBvYnRhaW4gdGhlaXIgb3duXG4gKiBTcGluZSBFZGl0b3IgbGljZW5zZSBhbmQgcmVkaXN0cmlidXRpb24gb2YgdGhlIFByb2R1Y3RzIGluIGFueSBmb3JtIG11c3RcbiAqIGluY2x1ZGUgdGhpcyBsaWNlbnNlIGFuZCBjb3B5cmlnaHQgbm90aWNlLlxuICpcbiAqIFRIRSBTUElORSBSVU5USU1FUyBBUkUgUFJPVklERUQgQlkgRVNPVEVSSUMgU09GVFdBUkUgTExDIFwiQVMgSVNcIiBBTkQgQU5ZXG4gKiBFWFBSRVNTIE9SIElNUExJRUQgV0FSUkFOVElFUywgSU5DTFVESU5HLCBCVVQgTk9UIExJTUlURUQgVE8sIFRIRSBJTVBMSUVEXG4gKiBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSBBTkQgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQVJFXG4gKiBESVNDTEFJTUVELiBJTiBOTyBFVkVOVCBTSEFMTCBFU09URVJJQyBTT0ZUV0FSRSBMTEMgQkUgTElBQkxFIEZPUiBBTllcbiAqIERJUkVDVCwgSU5ESVJFQ1QsIElOQ0lERU5UQUwsIFNQRUNJQUwsIEVYRU1QTEFSWSwgT1IgQ09OU0VRVUVOVElBTCBEQU1BR0VTXG4gKiAoSU5DTFVESU5HLCBCVVQgTk9UIExJTUlURUQgVE8sIFBST0NVUkVNRU5UIE9GIFNVQlNUSVRVVEUgR09PRFMgT1IgU0VSVklDRVMsXG4gKiBCVVNJTkVTUyBJTlRFUlJVUFRJT04sIE9SIExPU1MgT0YgVVNFLCBEQVRBLCBPUiBQUk9GSVRTKSBIT1dFVkVSIENBVVNFRCBBTkRcbiAqIE9OIEFOWSBUSEVPUlkgT0YgTElBQklMSVRZLCBXSEVUSEVSIElOIENPTlRSQUNULCBTVFJJQ1QgTElBQklMSVRZLCBPUiBUT1JUXG4gKiAoSU5DTFVESU5HIE5FR0xJR0VOQ0UgT1IgT1RIRVJXSVNFKSBBUklTSU5HIElOIEFOWSBXQVkgT1VUIE9GIFRIRSBVU0UgT0ZcbiAqIFRIRSBTUElORSBSVU5USU1FUywgRVZFTiBJRiBBRFZJU0VEIE9GIFRIRSBQT1NTSUJJTElUWSBPRiBTVUNIIERBTUFHRS5cbiAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHR5cGUgeyBCbGVuZE1vZGUsIEJvbmUsIEV2ZW50LCBOdW1iZXJBcnJheUxpa2UsIFNsb3QsIFRleHR1cmVBdGxhcywgVHJhY2tFbnRyeSB9IGZyb20gXCJAZXNvdGVyaWNzb2Z0d2FyZS9zcGluZS1jb3JlXCI7XG5pbXBvcnQge1xuXHRBbmltYXRpb25TdGF0ZSxcblx0QW5pbWF0aW9uU3RhdGVEYXRhLFxuXHRBdGxhc0F0dGFjaG1lbnRMb2FkZXIsXG5cdENsaXBwaW5nQXR0YWNobWVudCxcblx0Q29sb3IsXG5cdE1lc2hBdHRhY2htZW50LFxuXHRQaHlzaWNzLFxuXHRQb29sLFxuXHRSZWdpb25BdHRhY2htZW50LFxuXHRTa2VsZXRvbixcblx0U2tlbGV0b25CaW5hcnksXG5cdFNrZWxldG9uQ2xpcHBpbmcsXG5cdFNrZWxldG9uRGF0YSxcblx0U2tlbGV0b25Kc29uLFxuXHRTa2luLFxuXHRVdGlscyxcblx0VmVjdG9yMixcbn0gZnJvbSBcIkBlc290ZXJpY3NvZnR3YXJlL3NwaW5lLWNvcmVcIjtcbmltcG9ydCB0eXBlIHsgU3BpbmVUZXh0dXJlIH0gZnJvbSBcIi4vU3BpbmVUZXh0dXJlLmpzXCI7XG5pbXBvcnQgeyBTbG90TWVzaCB9IGZyb20gXCIuL1Nsb3RNZXNoLmpzXCI7XG5pbXBvcnQgeyBEYXJrU2xvdE1lc2ggfSBmcm9tIFwiLi9EYXJrU2xvdE1lc2guanNcIjtcbmltcG9ydCB0eXBlIHsgSVNwaW5lRGVidWdSZW5kZXJlciwgU3BpbmVEZWJ1Z1JlbmRlcmVyIH0gZnJvbSBcIi4vU3BpbmVEZWJ1Z1JlbmRlcmVyLmpzXCI7XG5pbXBvcnQgeyBBc3NldHMgfSBmcm9tIFwiQHBpeGkvYXNzZXRzXCI7XG5pbXBvcnQgeyBJUG9pbnREYXRhLCBQb2ludCB9IGZyb20gXCJAcGl4aS9jb3JlXCI7XG5pbXBvcnQgeyBUaWNrZXIgfSBmcm9tIFwiQHBpeGkvY29yZVwiO1xuaW1wb3J0IHR5cGUgeyBJRGVzdHJveU9wdGlvbnMsIERpc3BsYXlPYmplY3QgfSBmcm9tIFwiQHBpeGkvZGlzcGxheVwiO1xuaW1wb3J0IHsgQm91bmRzLCBDb250YWluZXIgfSBmcm9tIFwiQHBpeGkvZGlzcGxheVwiO1xuaW1wb3J0IHsgR3JhcGhpY3MgfSBmcm9tIFwiQHBpeGkvZ3JhcGhpY3NcIjtcbmltcG9ydCBcIkBwaXhpL2V2ZW50c1wiO1xuXG4vKipcbiAqIEBkZXByZWNhdGVkIFVzZSBTcGluZUZyb21PcHRpb25zIGFuZCBTcGluZU9wdGlvbnMuXG4gKiBPcHRpb25zIHRvIGNvbmZpZ3VyZSBhIHtAbGluayBTcGluZX0gZ2FtZSBvYmplY3QuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSVNwaW5lT3B0aW9ucyB7XG5cdC8qKiAgU2V0IHRoZSB7QGxpbmsgU3BpbmUuYXV0b1VwZGF0ZX0gdmFsdWUuIElmIG9taXR0ZWQsIGl0IGlzIHNldCB0byBgdHJ1ZWAuICovXG5cdGF1dG9VcGRhdGU/OiBib29sZWFuO1xuXHQvKiogIFRoZSB2YWx1ZSBwYXNzZWQgdG8gdGhlIHNrZWxldG9uIHJlYWRlci4gSWYgb21pdHRlZCwgMSBpcyBwYXNzZWQuIFNlZSB7QGxpbmsgU2tlbGV0b25CaW5hcnkuc2NhbGV9IGZvciBkZXRhaWxzLiAqL1xuXHRzY2FsZT86IG51bWJlcjtcblx0LyoqXG5cdCAqIEBkZXByZWNhdGVkIFVzZSBkYXJrVGludCBvcHRpb24gaW5zdGVhZC5cblx0ICogQSBmYWN0b3J5IHRvIG92ZXJyaWRlIHRoZSBkZWZhdWx0IG9uZXMgdG8gcmVuZGVyIFNwaW5lIG1lc2hlcyAoe0BsaW5rIERhcmtTbG90TWVzaH0gb3Ige0BsaW5rIFNsb3RNZXNofSkuXG5cdCAqIElmIG9taXR0ZWQsIGEgZmFjdG9yeSByZXR1cm5pbmcgYSAoe0BsaW5rIERhcmtTbG90TWVzaH0gb3Ige0BsaW5rIFNsb3RNZXNofSkgd2lsbCBiZSB1c2VkIGRlcGVuZGluZyBvbiB0aGUgcHJlc2VuY2Ugb2Zcblx0ICogYSBkYXJrIHRpbnQgbWVzaCBpbiB0aGUgc2tlbGV0b24uXG5cdCAqICovXG5cdHNsb3RNZXNoRmFjdG9yeT86ICgpID0+IElTbG90TWVzaDtcbn1cblxuLyoqXG4gKiBPcHRpb25zIHRvIGNyZWF0ZSBhIHtAbGluayBTcGluZX0gdXNpbmcge0BsaW5rIFNwaW5lLmZyb219LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFNwaW5lRnJvbU9wdGlvbnMge1xuXHQvKiogdGhlIGFzc2V0IG5hbWUgZm9yIHRoZSBza2VsZXRvbiBgLnNrZWxgIG9yIGAuanNvbmAgZmlsZSBwcmV2aW91c2x5IGxvYWRlZCBpbnRvIHRoZSBBc3NldHMgKi9cblx0c2tlbGV0b246IHN0cmluZztcblxuXHQvKiogdGhlIGFzc2V0IG5hbWUgZm9yIHRoZSBhdGxhcyBmaWxlIHByZXZpb3VzbHkgbG9hZGVkIGludG8gdGhlIEFzc2V0cyAqL1xuXHRhdGxhczogc3RyaW5nO1xuXG5cdC8qKiAgVGhlIHZhbHVlIHBhc3NlZCB0byB0aGUgc2tlbGV0b24gcmVhZGVyLiBJZiBvbWl0dGVkLCAxIGlzIHBhc3NlZC4gU2VlIHtAbGluayBTa2VsZXRvbkJpbmFyeS5zY2FsZX0gZm9yIGRldGFpbHMuICovXG5cdHNjYWxlPzogbnVtYmVyO1xuXG5cdC8qKiAgU2V0IHRoZSB7QGxpbmsgU3BpbmUuYXV0b1VwZGF0ZX0gdmFsdWUuIElmIG9taXR0ZWQsIGl0IGlzIHNldCB0byBgdHJ1ZWAuICovXG5cdGF1dG9VcGRhdGU/OiBib29sZWFuO1xuXG5cdC8qKlxuXHQgKiBJZiBgdHJ1ZWAsIHVzZSB0aGUgZGFyayB0aW50IHJlbmRlcmVyIHRvIHJlbmRlciB0aGUgc2tlbGV0b25cblx0ICogSWYgYGZhbHNlYCwgdXNlIHRoZSBkZWZhdWx0IHBpeGkgcmVuZGVyZXIgdG8gcmVuZGVyIHRoZSBza2VsZXRvblxuXHQgKiBJZiBgdW5kZWZpbmVkYCwgdXNlIHRoZSBkYXJrIHRpbnQgcmVuZGVyZXIgaWYgYXQgbGVhc3Qgb25lIHNsb3QgaGFzIHRpbnQgYmxhY2tcblx0ICovXG5cdGRhcmtUaW50PzogYm9vbGVhbjtcblxuXHQvKiogVGhlIGJvdW5kcyBwcm92aWRlciB0byB1c2UuIElmIHVuZGVmaW5lZCB0aGUgYm91bmRzIHdpbGwgYmUgZHluYW1pYywgY2FsY3VsYXRlZCB3aGVuIHJlcXVlc3RlZCBhbmQgYmFzZWQgb24gdGhlIGN1cnJlbnQgZnJhbWUuICovXG5cdGJvdW5kc1Byb3ZpZGVyPzogU3BpbmVCb3VuZHNQcm92aWRlcixcblxuXHQvKiogVGhlIHRpY2tlciB0byB1c2Ugd2hlbiB7QGxpbmsgYXV0b1VwZGF0ZX0gaXMgYHRydWVgLiBEZWZhdWx0cyB0byB7QGxpbmsgVGlja2VyLnNoYXJlZH0uICovXG5cdHRpY2tlcj86IFRpY2tlcixcbn07XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3BpbmVPcHRpb25zIHtcblx0LyoqIHRoZSB7QGxpbmsgU2tlbGV0b25EYXRhfSB1c2VkIHRvIGluc3RhbnRpYXRlIHRoZSBza2VsZXRvbiAqL1xuXHRza2VsZXRvbkRhdGE6IFNrZWxldG9uRGF0YTtcblxuXHQvKiogIFNlZSB7QGxpbmsgU3BpbmVGcm9tT3B0aW9ucy5hdXRvVXBkYXRlfS4gKi9cblx0YXV0b1VwZGF0ZT86IGJvb2xlYW47XG5cblx0LyoqICBTZWUge0BsaW5rIFNwaW5lRnJvbU9wdGlvbnMuZGFya1RpbnR9LiAqL1xuXHRkYXJrVGludD86IGJvb2xlYW47XG5cblx0LyoqICBTZWUge0BsaW5rIFNwaW5lRnJvbU9wdGlvbnMuYm91bmRzUHJvdmlkZXJ9LiAqL1xuXHRib3VuZHNQcm92aWRlcj86IFNwaW5lQm91bmRzUHJvdmlkZXIsXG5cblx0LyoqIFNlZSB7QGxpbmsgU3BpbmVGcm9tT3B0aW9ucy50aWNrZXJ9LiAqL1xuXHR0aWNrZXI/OiBUaWNrZXIsXG59XG5cbi8qKlxuICogQW5pbWF0aW9uU3RhdGVMaXN0ZW5lciB7QGxpbmsgaHR0cHM6Ly9lbi5lc290ZXJpY3NvZnR3YXJlLmNvbS9zcGluZS1hcGktcmVmZXJlbmNlI0FuaW1hdGlvblN0YXRlTGlzdGVuZXIgZXZlbnRzfSBleHBvc2VkIGZvciBQaXhpLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFNwaW5lRXZlbnRzIHtcblx0Y29tcGxldGU6IFt0cmFja0VudHJ5OiBUcmFja0VudHJ5XTtcblx0ZGlzcG9zZTogW3RyYWNrRW50cnk6IFRyYWNrRW50cnldO1xuXHRlbmQ6IFt0cmFja0VudHJ5OiBUcmFja0VudHJ5XTtcblx0ZXZlbnQ6IFt0cmFja0VudHJ5OiBUcmFja0VudHJ5LCBldmVudDogRXZlbnRdO1xuXHRpbnRlcnJ1cHQ6IFt0cmFja0VudHJ5OiBUcmFja0VudHJ5XTtcblx0c3RhcnQ6IFt0cmFja0VudHJ5OiBUcmFja0VudHJ5XTtcbn1cblxuLyoqIEEgYm91bmRzIHByb3ZpZGVyIGNhbGN1bGF0ZXMgdGhlIGJvdW5kaW5nIGJveCBmb3IgYSBza2VsZXRvbiwgd2hpY2ggaXMgdGhlbiBhc3NpZ25lZCBhcyB0aGUgc2l6ZSBvZiB0aGUgU3BpbmVHYW1lT2JqZWN0LiAqL1xuZXhwb3J0IGludGVyZmFjZSBTcGluZUJvdW5kc1Byb3ZpZGVyIHtcblx0LyoqIFJldHVybnMgdGhlIGJvdW5kaW5nIGJveCBmb3IgdGhlIHNrZWxldG9uLCBpbiBza2VsZXRvbiBzcGFjZS4gKi9cblx0Y2FsY3VsYXRlQm91bmRzIChnYW1lT2JqZWN0OiBTcGluZSk6IHtcblx0XHR4OiBudW1iZXI7XG5cdFx0eTogbnVtYmVyO1xuXHRcdHdpZHRoOiBudW1iZXI7XG5cdFx0aGVpZ2h0OiBudW1iZXI7XG5cdH07XG59XG5cbi8qKiBBIGJvdW5kcyBwcm92aWRlciB0aGF0IHByb3ZpZGVzIGEgZml4ZWQgc2l6ZSBnaXZlbiBieSB0aGUgdXNlci4gKi9cbmV4cG9ydCBjbGFzcyBBQUJCUmVjdGFuZ2xlQm91bmRzUHJvdmlkZXIgaW1wbGVtZW50cyBTcGluZUJvdW5kc1Byb3ZpZGVyIHtcblx0Y29uc3RydWN0b3IgKFxuXHRcdHByaXZhdGUgeDogbnVtYmVyLFxuXHRcdHByaXZhdGUgeTogbnVtYmVyLFxuXHRcdHByaXZhdGUgd2lkdGg6IG51bWJlcixcblx0XHRwcml2YXRlIGhlaWdodDogbnVtYmVyLFxuXHQpIHsgfVxuXHRjYWxjdWxhdGVCb3VuZHMgKCkge1xuXHRcdHJldHVybiB7IHg6IHRoaXMueCwgeTogdGhpcy55LCB3aWR0aDogdGhpcy53aWR0aCwgaGVpZ2h0OiB0aGlzLmhlaWdodCB9O1xuXHR9XG59XG5cbi8qKiBBIGJvdW5kcyBwcm92aWRlciB0aGF0IGNhbGN1bGF0ZXMgdGhlIGJvdW5kaW5nIGJveCBmcm9tIHRoZSBzZXR1cCBwb3NlLiAqL1xuZXhwb3J0IGNsYXNzIFNldHVwUG9zZUJvdW5kc1Byb3ZpZGVyIGltcGxlbWVudHMgU3BpbmVCb3VuZHNQcm92aWRlciB7XG5cdC8qKlxuXHQgKiBAcGFyYW0gY2xpcHBpbmcgSWYgdHJ1ZSwgY2xpcHBpbmcgYXR0YWNobWVudHMgYXJlIHVzZWQgdG8gY29tcHV0ZSB0aGUgYm91bmRzLiBGYWxzZSwgYnkgZGVmYXVsdC5cblx0ICovXG5cdGNvbnN0cnVjdG9yIChcblx0XHRwcml2YXRlIGNsaXBwaW5nID0gZmFsc2UsXG5cdCkgeyB9XG5cblx0Y2FsY3VsYXRlQm91bmRzIChnYW1lT2JqZWN0OiBTcGluZSkge1xuXHRcdGlmICghZ2FtZU9iamVjdC5za2VsZXRvbikgcmV0dXJuIHsgeDogMCwgeTogMCwgd2lkdGg6IDAsIGhlaWdodDogMCB9O1xuXHRcdC8vIE1ha2UgYSBjb3B5IG9mIGFuaW1hdGlvbiBzdGF0ZSBhbmQgc2tlbGV0b24gYXMgdGhpcyBtaWdodCBiZSBjYWxsZWQgd2hpbGVcblx0XHQvLyB0aGUgc2tlbGV0b24gaW4gdGhlIEdhbWVPYmplY3QgaGFzIGFscmVhZHkgYmVlbiBoZWF2aWx5IG1vZGlmaWVkLiBXZSBjYW4gbm90XG5cdFx0Ly8gcmVjb25zdHJ1Y3QgdGhhdCBzdGF0ZS5cblx0XHRjb25zdCBza2VsZXRvbiA9IG5ldyBTa2VsZXRvbihnYW1lT2JqZWN0LnNrZWxldG9uLmRhdGEpO1xuXHRcdHNrZWxldG9uLnNldFRvU2V0dXBQb3NlKCk7XG5cdFx0c2tlbGV0b24udXBkYXRlV29ybGRUcmFuc2Zvcm0oUGh5c2ljcy51cGRhdGUpO1xuXHRcdGNvbnN0IGJvdW5kcyA9IHNrZWxldG9uLmdldEJvdW5kc1JlY3QodGhpcy5jbGlwcGluZyA/IG5ldyBTa2VsZXRvbkNsaXBwaW5nKCkgOiB1bmRlZmluZWQpO1xuXHRcdHJldHVybiBib3VuZHMud2lkdGggPT0gTnVtYmVyLk5FR0FUSVZFX0lORklOSVRZXG5cdFx0XHQ/IHsgeDogMCwgeTogMCwgd2lkdGg6IDAsIGhlaWdodDogMCB9XG5cdFx0XHQ6IGJvdW5kcztcblx0fVxufVxuXG4vKiogQSBib3VuZHMgcHJvdmlkZXIgdGhhdCBjYWxjdWxhdGVzIHRoZSBib3VuZGluZyBib3ggYnkgdGFraW5nIHRoZSBtYXhpbXVtZyBib3VuZGluZyBib3ggZm9yIGEgY29tYmluYXRpb24gb2Ygc2tpbnMgYW5kIHNwZWNpZmljIGFuaW1hdGlvbi4gKi9cbmV4cG9ydCBjbGFzcyBTa2luc0FuZEFuaW1hdGlvbkJvdW5kc1Byb3ZpZGVyXG5cdGltcGxlbWVudHMgU3BpbmVCb3VuZHNQcm92aWRlciB7XG5cdC8qKlxuXHQgKiBAcGFyYW0gYW5pbWF0aW9uIFRoZSBhbmltYXRpb24gdG8gdXNlIGZvciBjYWxjdWxhdGluZyB0aGUgYm91bmRzLiBJZiBudWxsLCB0aGUgc2V0dXAgcG9zZSBpcyB1c2VkLlxuXHQgKiBAcGFyYW0gc2tpbnMgVGhlIHNraW5zIHRvIHVzZSBmb3IgY2FsY3VsYXRpbmcgdGhlIGJvdW5kcy4gSWYgZW1wdHksIHRoZSBkZWZhdWx0IHNraW4gaXMgdXNlZC5cblx0ICogQHBhcmFtIHRpbWVTdGVwIFRoZSB0aW1lIHN0ZXAgdG8gdXNlIGZvciBjYWxjdWxhdGluZyB0aGUgYm91bmRzLiBBIHNtYWxsZXIgdGltZSBzdGVwIG1lYW5zIG1vcmUgcHJlY2lzaW9uLCBidXQgc2xvd2VyIGNhbGN1bGF0aW9uLlxuXHQgKiBAcGFyYW0gY2xpcHBpbmcgSWYgdHJ1ZSwgY2xpcHBpbmcgYXR0YWNobWVudHMgYXJlIHVzZWQgdG8gY29tcHV0ZSB0aGUgYm91bmRzLiBGYWxzZSwgYnkgZGVmYXVsdC5cblx0ICovXG5cdGNvbnN0cnVjdG9yIChcblx0XHRwcml2YXRlIGFuaW1hdGlvbjogc3RyaW5nIHwgbnVsbCxcblx0XHRwcml2YXRlIHNraW5zOiBzdHJpbmdbXSA9IFtdLFxuXHRcdHByaXZhdGUgdGltZVN0ZXA6IG51bWJlciA9IDAuMDUsXG5cdFx0cHJpdmF0ZSBjbGlwcGluZyA9IGZhbHNlLFxuXHQpIHsgfVxuXG5cdGNhbGN1bGF0ZUJvdW5kcyAoZ2FtZU9iamVjdDogU3BpbmUpOiB7XG5cdFx0eDogbnVtYmVyO1xuXHRcdHk6IG51bWJlcjtcblx0XHR3aWR0aDogbnVtYmVyO1xuXHRcdGhlaWdodDogbnVtYmVyO1xuXHR9IHtcblx0XHRpZiAoIWdhbWVPYmplY3Quc2tlbGV0b24gfHwgIWdhbWVPYmplY3Quc3RhdGUpXG5cdFx0XHRyZXR1cm4geyB4OiAwLCB5OiAwLCB3aWR0aDogMCwgaGVpZ2h0OiAwIH07XG5cdFx0Ly8gTWFrZSBhIGNvcHkgb2YgYW5pbWF0aW9uIHN0YXRlIGFuZCBza2VsZXRvbiBhcyB0aGlzIG1pZ2h0IGJlIGNhbGxlZCB3aGlsZVxuXHRcdC8vIHRoZSBza2VsZXRvbiBpbiB0aGUgR2FtZU9iamVjdCBoYXMgYWxyZWFkeSBiZWVuIGhlYXZpbHkgbW9kaWZpZWQuIFdlIGNhbiBub3Rcblx0XHQvLyByZWNvbnN0cnVjdCB0aGF0IHN0YXRlLlxuXHRcdGNvbnN0IGFuaW1hdGlvblN0YXRlID0gbmV3IEFuaW1hdGlvblN0YXRlKGdhbWVPYmplY3Quc3RhdGUuZGF0YSk7XG5cdFx0Y29uc3Qgc2tlbGV0b24gPSBuZXcgU2tlbGV0b24oZ2FtZU9iamVjdC5za2VsZXRvbi5kYXRhKTtcblx0XHRjb25zdCBjbGlwcGVyID0gdGhpcy5jbGlwcGluZyA/IG5ldyBTa2VsZXRvbkNsaXBwaW5nKCkgOiB1bmRlZmluZWQ7XG5cdFx0Y29uc3QgZGF0YSA9IHNrZWxldG9uLmRhdGE7XG5cdFx0aWYgKHRoaXMuc2tpbnMubGVuZ3RoID4gMCkge1xuXHRcdFx0bGV0IGN1c3RvbVNraW4gPSBuZXcgU2tpbihcImN1c3RvbS1za2luXCIpO1xuXHRcdFx0Zm9yIChjb25zdCBza2luTmFtZSBvZiB0aGlzLnNraW5zKSB7XG5cdFx0XHRcdGNvbnN0IHNraW4gPSBkYXRhLmZpbmRTa2luKHNraW5OYW1lKTtcblx0XHRcdFx0aWYgKHNraW4gPT0gbnVsbCkgY29udGludWU7XG5cdFx0XHRcdGN1c3RvbVNraW4uYWRkU2tpbihza2luKTtcblx0XHRcdH1cblx0XHRcdHNrZWxldG9uLnNldFNraW4oY3VzdG9tU2tpbik7XG5cdFx0fVxuXHRcdHNrZWxldG9uLnNldFRvU2V0dXBQb3NlKCk7XG5cblx0XHRjb25zdCBhbmltYXRpb24gPSB0aGlzLmFuaW1hdGlvbiAhPSBudWxsID8gZGF0YS5maW5kQW5pbWF0aW9uKHRoaXMuYW5pbWF0aW9uISkgOiBudWxsO1xuXG5cdFx0aWYgKGFuaW1hdGlvbiA9PSBudWxsKSB7XG5cdFx0XHRza2VsZXRvbi51cGRhdGVXb3JsZFRyYW5zZm9ybShQaHlzaWNzLnVwZGF0ZSk7XG5cdFx0XHRjb25zdCBib3VuZHMgPSBza2VsZXRvbi5nZXRCb3VuZHNSZWN0KGNsaXBwZXIpO1xuXHRcdFx0cmV0dXJuIGJvdW5kcy53aWR0aCA9PSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFlcblx0XHRcdFx0PyB7IHg6IDAsIHk6IDAsIHdpZHRoOiAwLCBoZWlnaHQ6IDAgfVxuXHRcdFx0XHQ6IGJvdW5kcztcblx0XHR9IGVsc2Uge1xuXHRcdFx0bGV0IG1pblggPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFksXG5cdFx0XHRcdG1pblkgPSBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFksXG5cdFx0XHRcdG1heFggPSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFksXG5cdFx0XHRcdG1heFkgPSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFk7XG5cdFx0XHRhbmltYXRpb25TdGF0ZS5jbGVhclRyYWNrcygpO1xuXHRcdFx0YW5pbWF0aW9uU3RhdGUuc2V0QW5pbWF0aW9uV2l0aCgwLCBhbmltYXRpb24sIGZhbHNlKTtcblx0XHRcdGNvbnN0IHN0ZXBzID0gTWF0aC5tYXgoYW5pbWF0aW9uLmR1cmF0aW9uIC8gdGhpcy50aW1lU3RlcCwgMS4wKTtcblx0XHRcdGZvciAobGV0IGkgPSAwOyBpIDwgc3RlcHM7IGkrKykge1xuXHRcdFx0XHRjb25zdCBkZWx0YSA9IGkgPiAwID8gdGhpcy50aW1lU3RlcCA6IDA7XG5cdFx0XHRcdGFuaW1hdGlvblN0YXRlLnVwZGF0ZShkZWx0YSk7XG5cdFx0XHRcdGFuaW1hdGlvblN0YXRlLmFwcGx5KHNrZWxldG9uKTtcblx0XHRcdFx0c2tlbGV0b24udXBkYXRlKGRlbHRhKTtcblx0XHRcdFx0c2tlbGV0b24udXBkYXRlV29ybGRUcmFuc2Zvcm0oUGh5c2ljcy51cGRhdGUpO1xuXG5cdFx0XHRcdGNvbnN0IGJvdW5kcyA9IHNrZWxldG9uLmdldEJvdW5kc1JlY3QoY2xpcHBlcik7XG5cdFx0XHRcdG1pblggPSBNYXRoLm1pbihtaW5YLCBib3VuZHMueCk7XG5cdFx0XHRcdG1pblkgPSBNYXRoLm1pbihtaW5ZLCBib3VuZHMueSk7XG5cdFx0XHRcdG1heFggPSBNYXRoLm1heChtYXhYLCBib3VuZHMueCArIGJvdW5kcy53aWR0aCk7XG5cdFx0XHRcdG1heFkgPSBNYXRoLm1heChtYXhZLCBib3VuZHMueSArIGJvdW5kcy5oZWlnaHQpO1xuXHRcdFx0fVxuXHRcdFx0Y29uc3QgYm91bmRzID0ge1xuXHRcdFx0XHR4OiBtaW5YLFxuXHRcdFx0XHR5OiBtaW5ZLFxuXHRcdFx0XHR3aWR0aDogbWF4WCAtIG1pblgsXG5cdFx0XHRcdGhlaWdodDogbWF4WSAtIG1pblksXG5cdFx0XHR9O1xuXHRcdFx0cmV0dXJuIGJvdW5kcy53aWR0aCA9PSBOdW1iZXIuTkVHQVRJVkVfSU5GSU5JVFlcblx0XHRcdFx0PyB7IHg6IDAsIHk6IDAsIHdpZHRoOiAwLCBoZWlnaHQ6IDAgfVxuXHRcdFx0XHQ6IGJvdW5kcztcblx0XHR9XG5cdH1cbn1cblxuLyoqXG4gKiBUaGUgY2xhc3MgdG8gaW5zdGFudGlhdGUgYSB7QGxpbmsgU3BpbmV9IGdhbWUgb2JqZWN0IGluIFBpeGkuXG4gKiBUaGUgc3RhdGljIG1ldGhvZCB7QGxpbmsgU3BpbmUuZnJvbX0gc2hvdWxkIGJlIHVzZWQgdG8gaW5zdGFudGlhdGUgYSBTcGluZSBnYW1lIG9iamVjdC5cbiAqL1xuZXhwb3J0IGNsYXNzIFNwaW5lIGV4dGVuZHMgQ29udGFpbmVyIHtcblx0LyoqIFRoZSBza2VsZXRvbiBmb3IgdGhpcyBTcGluZSBnYW1lIG9iamVjdC4gKi9cblx0cHVibGljIHNrZWxldG9uOiBTa2VsZXRvbjtcblx0LyoqIFRoZSBhbmltYXRpb24gc3RhdGUgZm9yIHRoaXMgU3BpbmUgZ2FtZSBvYmplY3QuICovXG5cdHB1YmxpYyBzdGF0ZTogQW5pbWF0aW9uU3RhdGU7XG5cblx0cHJpdmF0ZSBkYXJrVGludCA9IGZhbHNlO1xuXHRwcml2YXRlIGhhc05ldmVyVXBkYXRlZCA9IHRydWU7XG5cblx0cHJpdmF0ZSBfZGVidWc/OiBJU3BpbmVEZWJ1Z1JlbmRlcmVyIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuXHRwdWJsaWMgZ2V0IGRlYnVnICgpOiBJU3BpbmVEZWJ1Z1JlbmRlcmVyIHwgdW5kZWZpbmVkIHtcblx0XHRyZXR1cm4gdGhpcy5fZGVidWc7XG5cdH1cblx0LyoqIFBhc3MgYSB7QGxpbmsgU3BpbmVEZWJ1Z1JlbmRlcmVyfSBvciBjcmVhdGUgeW91ciBvd24ge0BsaW5rIElTcGluZURlYnVnUmVuZGVyZXJ9IHRvIHJlbmRlciBib25lcywgbWVzaGVzLCAuLi5cblx0ICogQGV4YW1wbGUgc3BpbmVHTy5kZWJ1ZyA9IG5ldyBTcGluZURlYnVnUmVuZGVyZXIoKTtcblx0ICovXG5cdHB1YmxpYyBzZXQgZGVidWcgKHZhbHVlOiBJU3BpbmVEZWJ1Z1JlbmRlcmVyIHwgdW5kZWZpbmVkKSB7XG5cdFx0aWYgKHRoaXMuX2RlYnVnKSB7XG5cdFx0XHR0aGlzLl9kZWJ1Zy51bnJlZ2lzdGVyU3BpbmUodGhpcyk7XG5cdFx0fVxuXHRcdGlmICh2YWx1ZSkge1xuXHRcdFx0dmFsdWUucmVnaXN0ZXJTcGluZSh0aGlzKTtcblx0XHR9XG5cdFx0dGhpcy5fZGVidWcgPSB2YWx1ZTtcblx0fVxuXG5cdHByb3RlY3RlZCBzbG90TWVzaEZhY3Rvcnk6ICgpID0+IElTbG90TWVzaCA9ICgpID0+IG5ldyBTbG90TWVzaCgpO1xuXG5cdGJlZm9yZVVwZGF0ZVdvcmxkVHJhbnNmb3JtczogKG9iamVjdDogU3BpbmUpID0+IHZvaWQgPSAoKSA9PiB7IH07XG5cdGFmdGVyVXBkYXRlV29ybGRUcmFuc2Zvcm1zOiAob2JqZWN0OiBTcGluZSkgPT4gdm9pZCA9ICgpID0+IHsgfTtcblxuXHRwcml2YXRlIF9hdXRvVXBkYXRlOiBib29sZWFuID0gZmFsc2U7XG5cdHByaXZhdGUgX3RpY2tlcjogVGlja2VyID0gVGlja2VyLnNoYXJlZDtcblxuXHRwdWJsaWMgZ2V0IGF1dG9VcGRhdGUgKCk6IGJvb2xlYW4ge1xuXHRcdHJldHVybiB0aGlzLl9hdXRvVXBkYXRlO1xuXHR9XG5cdC8qKiBXaGVuIGB0cnVlYCwgdGhlIFNwaW5lIEFuaW1hdGlvblN0YXRlIGFuZCB0aGUgU2tlbGV0b24gd2lsbCBiZSBhdXRvbWF0aWNhbGx5IHVwZGF0ZWQgdXNpbmcgdGhlIHtAbGluayB0aWNrZXJ9LiAqL1xuXHRwdWJsaWMgc2V0IGF1dG9VcGRhdGUgKHZhbHVlOiBib29sZWFuKSB7XG5cdFx0aWYgKHZhbHVlICYmICF0aGlzLl9hdXRvVXBkYXRlKSB7XG5cdFx0XHR0aGlzLl90aWNrZXIuYWRkKHRoaXMuaW50ZXJuYWxVcGRhdGUsIHRoaXMpO1xuXHRcdH0gZWxzZSBpZiAoIXZhbHVlICYmIHRoaXMuX2F1dG9VcGRhdGUpIHtcblx0XHRcdHRoaXMuX3RpY2tlci5yZW1vdmUodGhpcy5pbnRlcm5hbFVwZGF0ZSwgdGhpcyk7XG5cdFx0fVxuXHRcdHRoaXMuX2F1dG9VcGRhdGUgPSB2YWx1ZTtcblx0fVxuXG5cdC8qKiBUaGUgdGlja2VyIHRvIHVzZSB3aGVuIHtAbGluayBhdXRvVXBkYXRlfSBpcyBgdHJ1ZWAuIERlZmF1bHRzIHRvIHtAbGluayBUaWNrZXIuc2hhcmVkfS4gKi9cblx0cHVibGljIGdldCB0aWNrZXIgKCk6IFRpY2tlciB7XG5cdFx0cmV0dXJuIHRoaXMuX3RpY2tlcjtcblx0fVxuXHQvKiogU2V0cyB0aGUgdGlja2VyIHRvIHVzZSB3aGVuIHtAbGluayBhdXRvVXBkYXRlfSBpcyBgdHJ1ZWAuIElmIGBhdXRvVXBkYXRlYCBpcyBhbHJlYWR5IGB0cnVlYCwgdGhlIHVwZGF0ZSBjYWxsYmFjayB3aWxsIGJlIG1vdmVkIGZyb20gdGhlIG9sZCB0aWNrZXIgdG8gdGhlIG5ldyBvbmUuICovXG5cdHB1YmxpYyBzZXQgdGlja2VyICh2YWx1ZTogVGlja2VyKSB7XG5cdFx0dmFsdWUgPSB2YWx1ZSA/PyBUaWNrZXIuc2hhcmVkO1xuXHRcdGlmICh0aGlzLl90aWNrZXIgPT09IHZhbHVlKSByZXR1cm47XG5cblx0XHRpZiAodGhpcy5fYXV0b1VwZGF0ZSkge1xuXHRcdFx0dGhpcy5fdGlja2VyLnJlbW92ZSh0aGlzLmludGVybmFsVXBkYXRlLCB0aGlzKTtcblx0XHRcdHZhbHVlLmFkZCh0aGlzLmludGVybmFsVXBkYXRlLCB0aGlzKTtcblx0XHR9XG5cblx0XHR0aGlzLl90aWNrZXIgPSB2YWx1ZTtcblx0fVxuXG5cdHByaXZhdGUgbWVzaGVzQ2FjaGUgPSBuZXcgTWFwPFNsb3QsIElTbG90TWVzaD4oKTtcblxuXHRwcml2YXRlIHN0YXRpYyB2ZWN0b3JBdXg6IFZlY3RvcjIgPSBuZXcgVmVjdG9yMigpO1xuXHRwcml2YXRlIHN0YXRpYyBjbGlwcGVyOiBTa2VsZXRvbkNsaXBwaW5nID0gbmV3IFNrZWxldG9uQ2xpcHBpbmcoKTtcblxuXHRwcml2YXRlIHN0YXRpYyBRVUFEX1RSSUFOR0xFUyA9IFswLCAxLCAyLCAyLCAzLCAwXTtcblx0cHJpdmF0ZSBzdGF0aWMgVkVSVEVYX1NJWkUgPSAyICsgMiArIDQ7XG5cdHByaXZhdGUgc3RhdGljIERBUktfVkVSVEVYX1NJWkUgPSAyICsgMiArIDQgKyA0O1xuXG5cdHByaXZhdGUgbGlnaHRDb2xvciA9IG5ldyBDb2xvcigpO1xuXHRwcml2YXRlIGRhcmtDb2xvciA9IG5ldyBDb2xvcigpO1xuXG5cdHByaXZhdGUgX2JvdW5kc1Byb3ZpZGVyPzogU3BpbmVCb3VuZHNQcm92aWRlcjtcblx0LyoqIFRoZSBib3VuZHMgcHJvdmlkZXIgdG8gdXNlLiBJZiB1bmRlZmluZWQgdGhlIGJvdW5kcyB3aWxsIGJlIGR5bmFtaWMsIGNhbGN1bGF0ZWQgd2hlbiByZXF1ZXN0ZWQgYW5kIGJhc2VkIG9uIHRoZSBjdXJyZW50IGZyYW1lLiAqL1xuXHRwdWJsaWMgZ2V0IGJvdW5kc1Byb3ZpZGVyICgpOiBTcGluZUJvdW5kc1Byb3ZpZGVyIHwgdW5kZWZpbmVkIHtcblx0XHRyZXR1cm4gdGhpcy5fYm91bmRzUHJvdmlkZXI7XG5cdH1cblx0cHVibGljIHNldCBib3VuZHNQcm92aWRlciAodmFsdWU6IFNwaW5lQm91bmRzUHJvdmlkZXIgfCB1bmRlZmluZWQpIHtcblx0XHR0aGlzLl9ib3VuZHNQcm92aWRlciA9IHZhbHVlO1xuXHRcdGlmICh2YWx1ZSkge1xuXHRcdFx0dGhpcy5fYm91bmRzU3BpbmVJRCA9IC0xO1xuXHRcdFx0dGhpcy5fYm91bmRzU3BpbmVEaXJ0eSA9IHRydWU7XG5cdFx0XHR0aGlzLmludGVyYWN0aXZlQ2hpbGRyZW4gPSBmYWxzZTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5pbnRlcmFjdGl2ZUNoaWxkcmVuID0gdHJ1ZTtcblx0XHRcdHRoaXMuaGl0QXJlYSA9IG51bGw7XG5cdFx0fVxuXHRcdGlmICghdGhpcy5oYXNOZXZlclVwZGF0ZWQpIHtcblx0XHRcdHRoaXMuY2FsY3VsYXRlQm91bmRzKCk7XG5cdFx0fVxuXHR9XG5cdHByaXZhdGUgX2JvdW5kc1BvaW50ID0gbmV3IFBvaW50KCk7XG5cdHByaXZhdGUgX2JvdW5kc1NwaW5lSUQgPSAtMTtcblx0cHJpdmF0ZSBfYm91bmRzU3BpbmVEaXJ0eSA9IHRydWU7XG5cblx0Y29uc3RydWN0b3IgKG9wdGlvbnM6IFNwaW5lT3B0aW9ucyB8IFNrZWxldG9uRGF0YSwgb2xkT3B0aW9ucz86IElTcGluZU9wdGlvbnMpIHtcblx0XHRpZiAob3B0aW9ucyBpbnN0YW5jZW9mIFNrZWxldG9uRGF0YSkge1xuXHRcdFx0b3B0aW9ucyA9IHtcblx0XHRcdFx0Li4ub2xkT3B0aW9ucyxcblx0XHRcdFx0c2tlbGV0b25EYXRhOiBvcHRpb25zLFxuXHRcdFx0fTtcblx0XHR9IGVsc2UgaWYgKG9sZE9wdGlvbnMpIHtcblx0XHRcdHRocm93IG5ldyBFcnJvcihcIllvdSBjYW5ub3QgdXNlIG9wdGlvbnMgYW5kIG9sZE9wdGlvbnMgdG9nZXRoZXIuXCIpO1xuXHRcdH1cblxuXHRcdHN1cGVyKCk7XG5cblx0XHRjb25zdCBza2VsZXRvbkRhdGEgPSBvcHRpb25zIGluc3RhbmNlb2YgU2tlbGV0b25EYXRhID8gb3B0aW9ucyA6IG9wdGlvbnMuc2tlbGV0b25EYXRhO1xuXG5cdFx0dGhpcy5za2VsZXRvbiA9IG5ldyBTa2VsZXRvbihza2VsZXRvbkRhdGEpO1xuXHRcdGNvbnN0IGFuaW1EYXRhID0gbmV3IEFuaW1hdGlvblN0YXRlRGF0YShza2VsZXRvbkRhdGEpO1xuXHRcdHRoaXMuc3RhdGUgPSBuZXcgQW5pbWF0aW9uU3RhdGUoYW5pbURhdGEpO1xuXG5cdFx0Ly8gZGFyayB0aW50IGNhbiBiZSBlbmFibGVkIGJ5IG9wdGlvbnMsIG90aGVyd2lzZSBpcyBlbmFibGUgaWYgYXQgbGVhc3Qgb25lIHNsb3QgaGFzIHRpbnQgYmxhY2tcblx0XHRpZiAob3B0aW9ucz8uZGFya1RpbnQgIT09IHVuZGVmaW5lZCB8fCBvbGRPcHRpb25zPy5zbG90TWVzaEZhY3RvcnkgPT09IHVuZGVmaW5lZCkge1xuXHRcdFx0dGhpcy5kYXJrVGludCA9IG9wdGlvbnM/LmRhcmtUaW50ID09PSB1bmRlZmluZWRcblx0XHRcdFx0PyB0aGlzLnNrZWxldG9uLnNsb3RzLnNvbWUoc2xvdCA9PiAhIXNsb3QuZGF0YS5kYXJrQ29sb3IpXG5cdFx0XHRcdDogb3B0aW9ucz8uZGFya1RpbnQ7XG5cdFx0XHRpZiAodGhpcy5kYXJrVGludCkgdGhpcy5zbG90TWVzaEZhY3RvcnkgPSAoKSA9PiBuZXcgRGFya1Nsb3RNZXNoKCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuaW5pdGlhbGl6ZU1lc2hGYWN0b3J5KG9sZE9wdGlvbnM/LnNsb3RNZXNoRmFjdG9yeSk7XG5cdFx0fVxuXG5cdFx0aWYgKG9wdGlvbnM/LnRpY2tlcikgdGhpcy5fdGlja2VyID0gb3B0aW9ucy50aWNrZXI7XG5cdFx0dGhpcy5hdXRvVXBkYXRlID0gb3B0aW9ucz8uYXV0b1VwZGF0ZSA/PyB0cnVlO1xuXG5cdFx0dGhpcy5ib3VuZHNQcm92aWRlciA9IG9wdGlvbnMuYm91bmRzUHJvdmlkZXI7XG5cdH1cblxuXHQvKlxuXHQqIEBkZXByZWNhdGVkIFJlbW92ZSB3aGVuIHNsb3RNZXNoRmFjdG9yeSBvcHRpb25zIGlzIHJlbW92ZWRcblx0Ki9cblx0cHJpdmF0ZSBpbml0aWFsaXplTWVzaEZhY3Rvcnk8VCBleHRlbmRzICgpID0+IElTbG90TWVzaD4gKHNsb3RNZXNoRmFjdG9yeT86IFQpIHtcblx0XHRpZiAoc2xvdE1lc2hGYWN0b3J5KSB7XG5cdFx0XHR0aGlzLnNsb3RNZXNoRmFjdG9yeSA9IHNsb3RNZXNoRmFjdG9yeTtcblx0XHRcdGNvbnN0IHRlbXBTbG90TWVzaEZhY3RvcnkgPSB0aGlzLnNsb3RNZXNoRmFjdG9yeSgpO1xuXHRcdFx0aWYgKHRlbXBTbG90TWVzaEZhY3RvcnkgaW5zdGFuY2VvZiBEYXJrU2xvdE1lc2gpIHRoaXMuZGFya1RpbnQgPSB0cnVlO1xuXHRcdFx0dGVtcFNsb3RNZXNoRmFjdG9yeS5kZXN0cm95KCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5za2VsZXRvbi5zbG90cy5sZW5ndGg7IGkrKykge1xuXHRcdFx0XHRpZiAodGhpcy5za2VsZXRvbi5zbG90c1tpXS5kYXRhLmRhcmtDb2xvcikge1xuXHRcdFx0XHRcdHRoaXMuc2xvdE1lc2hGYWN0b3J5ID0gKCkgPT4gbmV3IERhcmtTbG90TWVzaCgpO1xuXHRcdFx0XHRcdHRoaXMuZGFya1RpbnQgPSB0cnVlO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0LyoqIElmIHtAbGluayBTcGluZS5hdXRvVXBkYXRlfSBpcyBgZmFsc2VgLCB0aGlzIG1ldGhvZCBhbGxvd3MgdG8gdXBkYXRlIHRoZSBBbmltYXRpb25TdGF0ZSBhbmQgdGhlIFNrZWxldG9uIHdpdGggdGhlIGdpdmVuIGRlbHRhLiAqL1xuXHRwdWJsaWMgdXBkYXRlIChkZWx0YVNlY29uZHM6IG51bWJlcik6IHZvaWQge1xuXHRcdHRoaXMuaW50ZXJuYWxVcGRhdGUoMCwgZGVsdGFTZWNvbmRzKTtcblx0fVxuXG5cdHByb3RlY3RlZCBpbnRlcm5hbFVwZGF0ZSAoX2RlbHRhRnJhbWU6IG51bWJlciwgZGVsdGFTZWNvbmRzPzogbnVtYmVyKTogdm9pZCB7XG5cdFx0dGhpcy5oYXNOZXZlclVwZGF0ZWQgPSBmYWxzZTtcblxuXHRcdC8vIEJlY2F1c2UgcmVhc29ucywgcGl4aSB1c2VzIGRlbHRhRnJhbWVzIGF0IDYwZnBzLiBXZSBpZ25vcmUgdGhlIGRlZmF1bHQgZGVsdGFGcmFtZXMgYW5kIHVzZSB0aGUgZGVsdGFTZWNvbmRzIGZyb20gcGl4aSB0aWNrZXIuXG5cdFx0Y29uc3QgZGVsdGEgPSBkZWx0YVNlY29uZHMgPz8gdGhpcy5fdGlja2VyLmRlbHRhTVMgLyAxMDAwO1xuXHRcdHRoaXMuc3RhdGUudXBkYXRlKGRlbHRhKTtcblx0XHR0aGlzLnN0YXRlLmFwcGx5KHRoaXMuc2tlbGV0b24pO1xuXHRcdHRoaXMuYmVmb3JlVXBkYXRlV29ybGRUcmFuc2Zvcm1zKHRoaXMpO1xuXHRcdHRoaXMuc2tlbGV0b24udXBkYXRlKGRlbHRhKTtcblx0XHR0aGlzLnNrZWxldG9uLnVwZGF0ZVdvcmxkVHJhbnNmb3JtKFBoeXNpY3MudXBkYXRlKTtcblx0XHR0aGlzLmFmdGVyVXBkYXRlV29ybGRUcmFuc2Zvcm1zKHRoaXMpO1xuXHR9XG5cblx0LyoqIFJlbmRlciB0aGUgbWVzaGVzIGJhc2VkIG9uIHRoZSBjdXJyZW50IHNrZWxldG9uIHN0YXRlLCByZW5kZXIgZGVidWcgaW5mb3JtYXRpb24sIHRoZW4gY2FsbCB7QGxpbmsgQ29udGFpbmVyLnVwZGF0ZVRyYW5zZm9ybX0uICovXG5cdHB1YmxpYyBvdmVycmlkZSB1cGRhdGVUcmFuc2Zvcm0gKCk6IHZvaWQge1xuXHRcdHRoaXMucmVuZGVyTWVzaGVzKCk7XG5cdFx0dGhpcy5zb3J0Q2hpbGRyZW4oKTtcblx0XHR0aGlzLmRlYnVnPy5yZW5kZXJEZWJ1Zyh0aGlzKTtcblx0XHRzdXBlci51cGRhdGVUcmFuc2Zvcm0oKTtcblx0fVxuXG5cdC8qKiBEZXN0cm95IFNwaW5lIGdhbWUgb2JqZWN0IGVsZW1lbnRzLCB0aGVuIGNhbGwgdGhlIHtAbGluayBDb250YWluZXIuZGVzdHJveX0gd2l0aCB0aGUgZ2l2ZW4gb3B0aW9ucyAqL1xuXHRwdWJsaWMgb3ZlcnJpZGUgZGVzdHJveSAob3B0aW9ucz86IGJvb2xlYW4gfCBJRGVzdHJveU9wdGlvbnMgfCB1bmRlZmluZWQpOiB2b2lkIHtcblx0XHRpZiAodGhpcy5hdXRvVXBkYXRlKSB0aGlzLmF1dG9VcGRhdGUgPSBmYWxzZTtcblx0XHQodGhpcy5fdGlja2VyIGFzIGFueSkgPSBudWxsO1xuXHRcdGZvciAoY29uc3QgWywgbWVzaF0gb2YgdGhpcy5tZXNoZXNDYWNoZSkge1xuXHRcdFx0bWVzaD8uZGVzdHJveSgpO1xuXHRcdH1cblx0XHR0aGlzLnN0YXRlLmNsZWFyTGlzdGVuZXJzKCk7XG5cdFx0dGhpcy5kZWJ1ZyA9IHVuZGVmaW5lZDtcblx0XHR0aGlzLm1lc2hlc0NhY2hlLmNsZWFyKCk7XG5cdFx0dGhpcy5zbG90c09iamVjdC5jbGVhcigpO1xuXG5cdFx0Zm9yIChsZXQgbWFza0tleSBpbiB0aGlzLmNsaXBwaW5nU2xvdFRvUGl4aU1hc2tzKSB7XG5cdFx0XHRjb25zdCBtYXNrT2JqID0gdGhpcy5jbGlwcGluZ1Nsb3RUb1BpeGlNYXNrc1ttYXNrS2V5XTtcblx0XHRcdG1hc2tPYmoubWFzaz8uZGVzdHJveSgpO1xuXHRcdFx0ZGVsZXRlIHRoaXMuY2xpcHBpbmdTbG90VG9QaXhpTWFza3NbbWFza0tleV07XG5cdFx0fVxuXG5cdFx0c3VwZXIuZGVzdHJveShvcHRpb25zKTtcblx0fVxuXG5cdHByaXZhdGUgcmVzZXRNZXNoZXMgKCk6IHZvaWQge1xuXHRcdGZvciAoY29uc3QgWywgbWVzaF0gb2YgdGhpcy5tZXNoZXNDYWNoZSkge1xuXHRcdFx0bWVzaC56SW5kZXggPSAtMTtcblx0XHRcdG1lc2gudmlzaWJsZSA9IGZhbHNlO1xuXHRcdH1cblx0fVxuXG5cdHByb3RlY3RlZCBfY2FsY3VsYXRlQm91bmRzICgpOiB2b2lkIHtcblx0XHRpZiAodGhpcy5oYXNOZXZlclVwZGF0ZWQpIHtcblx0XHRcdHRoaXMuaW50ZXJuYWxVcGRhdGUoMCwgMCk7XG5cdFx0XHR0aGlzLnJlbmRlck1lc2hlcygpO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBDaGVjayB0aGUgZXhpc3RlbmNlIG9mIGEgbWVzaCBmb3IgdGhlIGdpdmVuIHNsb3QuXG5cdCAqIElmIHlvdSB3YW50IHRvIG1hbnVhbGx5IGhhbmRsZSB3aGljaCBtZXNoZXMgZ28gb24gd2hpY2ggc2xvdCBhbmQgaG93IHlvdSBjYWNoZSwgb3ZlcndyaXRlIHRoaXMgbWV0aG9kLlxuXHQgKi9cblx0cHJvdGVjdGVkIGhhc01lc2hGb3JTbG90IChzbG90OiBTbG90KSB7XG5cdFx0cmV0dXJuIHRoaXMubWVzaGVzQ2FjaGUuaGFzKHNsb3QpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNlYXJjaCB0aGUgbWVzaCBjb3JyZXNwb25kaW5nIHRvIHRoZSBnaXZlbiBzbG90IG9yIGNyZWF0ZSBpdCwgaWYgaXQgZG9lcyBub3QgZXhpc3RzLlxuXHQgKiBJZiB5b3Ugd2FudCB0byBtYW51YWxseSBoYW5kbGUgd2hpY2ggbWVzaGVzIGdvIG9uIHdoaWNoIHNsb3QgYW5kIGhvdyB5b3UgY2FjaGUsIG92ZXJ3cml0ZSB0aGlzIG1ldGhvZC5cblx0ICovXG5cdHByb3RlY3RlZCBnZXRNZXNoRm9yU2xvdCAoc2xvdDogU2xvdCk6IElTbG90TWVzaCB7XG5cdFx0aWYgKCF0aGlzLmhhc01lc2hGb3JTbG90KHNsb3QpKSB7XG5cdFx0XHRsZXQgbWVzaCA9IHRoaXMuc2xvdE1lc2hGYWN0b3J5KCk7XG5cdFx0XHR0aGlzLmFkZENoaWxkKG1lc2gpO1xuXHRcdFx0dGhpcy5tZXNoZXNDYWNoZS5zZXQoc2xvdCwgbWVzaCk7XG5cdFx0XHRyZXR1cm4gbWVzaDtcblx0XHR9IGVsc2Uge1xuXHRcdFx0bGV0IG1lc2ggPSB0aGlzLm1lc2hlc0NhY2hlLmdldChzbG90KSE7XG5cdFx0XHRtZXNoLnZpc2libGUgPSB0cnVlO1xuXHRcdFx0cmV0dXJuIG1lc2g7XG5cdFx0fVxuXHR9XG5cblx0cHVibGljIHNsb3RzT2JqZWN0ID0gbmV3IE1hcDxTbG90LCB7IGNvbnRhaW5lcjogQ29udGFpbmVyLCBmb2xsb3dBdHRhY2htZW50VGltZWxpbmU6IGJvb2xlYW4sIGZvbGxvd1Nsb3RDb2xvcjogYm9vbGVhbiB9PigpO1xuXHRwcml2YXRlIGdldFNsb3RGcm9tUmVmIChzbG90UmVmOiBudW1iZXIgfCBzdHJpbmcgfCBTbG90KTogU2xvdCB7XG5cdFx0bGV0IHNsb3Q6IFNsb3QgfCBudWxsO1xuXHRcdGlmICh0eXBlb2Ygc2xvdFJlZiA9PT0gJ251bWJlcicpIHNsb3QgPSB0aGlzLnNrZWxldG9uLnNsb3RzW3Nsb3RSZWZdO1xuXHRcdGVsc2UgaWYgKHR5cGVvZiBzbG90UmVmID09PSAnc3RyaW5nJykgc2xvdCA9IHRoaXMuc2tlbGV0b24uZmluZFNsb3Qoc2xvdFJlZik7XG5cdFx0ZWxzZSBzbG90ID0gc2xvdFJlZjtcblxuXHRcdGlmICghc2xvdCkgdGhyb3cgbmV3IEVycm9yKGBObyBzbG90IGZvdW5kIHdpdGggdGhlIGdpdmVuIHNsb3QgcmVmZXJlbmNlOiAke3Nsb3RSZWZ9YCk7XG5cblx0XHRyZXR1cm4gc2xvdDtcblx0fVxuXHQvKipcblx0ICogQWRkIGEgcGl4aSBDb250YWluZXIgYXMgYSBjaGlsZCBvZiB0aGUgU3BpbmUgb2JqZWN0LlxuXHQgKiBUaGUgQ29udGFpbmVyIHdpbGwgYmUgcmVuZGVyZWQgY29oZXJlbnRseSB3aXRoIHRoZSBkcmF3IG9yZGVyIG9mIHRoZSBzbG90LlxuXHQgKiBJZiBhbiBhdHRhY2htZW50IGlzIGFjdGl2ZSBvbiB0aGUgc2xvdCwgdGhlIHBpeGkgQ29udGFpbmVyIHdpbGwgYmUgcmVuZGVyZWQgb24gdG9wIG9mIGl0LlxuXHQgKiBJZiB0aGUgQ29udGFpbmVyIGlzIGFscmVhZHkgYXR0YWNoZWQgdG8gdGhlIGdpdmVuIHNsb3QsIG5vdGhpbmcgd2lsbCBoYXBwZW4uXG5cdCAqIElmIHRoZSBDb250YWluZXIgaXMgYWxyZWFkeSBhdHRhY2hlZCB0byBhbm90aGVyIHNsb3QsIGl0IHdpbGwgYmUgcmVtb3ZlZCBmcm9tIHRoYXQgc2xvdFxuXHQgKiBiZWZvcmUgYWRkaW5nIGl0IHRvIHRoZSBnaXZlbiBvbmUuXG5cdCAqIElmIGFub3RoZXIgQ29udGFpbmVyIGlzIGFscmVhZHkgYXR0YWNoZWQgdG8gdGhpcyBzbG90LCB0aGUgb2xkIG9uZSB3aWxsIGJlIHJlbW92ZWQgZnJvbSB0aGlzXG5cdCAqIHNsb3QgYmVmb3JlIGFkZGluZyBpdCB0byB0aGUgY3VycmVudCBvbmUuXG5cdCAqIEBwYXJhbSBzbG90UmVmIC0gVGhlIHNsb3QgaW5kZXgsIG9yIHRoZSBzbG90IG5hbWUsIG9yIHRoZSBTbG90IHdoZXJlIHRoZSBwaXhpIG9iamVjdCB3aWxsIGJlIGFkZGVkIHRvLlxuXHQgKiBAcGFyYW0gcGl4aU9iamVjdCAtIFRoZSBwaXhpIENvbnRhaW5lciB0byBhZGQuXG5cdCAqIEBwYXJhbSBvcHRpb25zIC0gT3B0aW9uYWwgc2V0dGluZ3MgZm9yIHRoZSBhdHRhY2htZW50LlxuXHQgKiBAcGFyYW0gb3B0aW9ucy5mb2xsb3dBdHRhY2htZW50VGltZWxpbmUgLSBJZiB0cnVlLCB0aGUgYXR0YWNobWVudCB3aWxsIGZvbGxvdyB0aGUgc2xvdCdzIGF0dGFjaG1lbnQgdGltZWxpbmUuXG5cdCAqIEBwYXJhbSBvcHRpb25zLmZvbGxvd1Nsb3RDb2xvciAtIElmIHRydWUsIHRoZSBjb250YWluZXIgdGludCB3aWxsIGZvbGxvdyB0aGUgc2tlbGV0b24gYW5kIHNsb3QgY29sb3JzLlxuXHQgKi9cblx0YWRkU2xvdE9iamVjdCAoc2xvdFJlZjogbnVtYmVyIHwgc3RyaW5nIHwgU2xvdCwgcGl4aU9iamVjdDogQ29udGFpbmVyLCBvcHRpb25zPzogeyBmb2xsb3dBdHRhY2htZW50VGltZWxpbmU/OiBib29sZWFuLCBmb2xsb3dTbG90Q29sb3I/OiBib29sZWFuIH0pOiB2b2lkIHtcblx0XHRsZXQgc2xvdCA9IHRoaXMuZ2V0U2xvdEZyb21SZWYoc2xvdFJlZik7XG5cdFx0Y29uc3Qgb2xkUGl4aU9iamVjdCA9IHRoaXMuc2xvdHNPYmplY3QuZ2V0KHNsb3QpPy5jb250YWluZXI7XG5cdFx0aWYgKG9sZFBpeGlPYmplY3QgJiYgb2xkUGl4aU9iamVjdCA9PT0gcGl4aU9iamVjdCkgcmV0dXJuO1xuXG5cdFx0Ly8gc2VhcmNoIGlmIHRoZSBwaXhpT2JqZWN0IHdhcyBhbHJlYWR5IGluIGFub3RoZXIgc2xvdE9iamVjdFxuXHRcdGZvciAoY29uc3QgW290aGVyU2xvdCwgeyBjb250YWluZXI6IG9sZFBpeGlPYmplY3RBbm90aGVyU2xvdCB9XSBvZiB0aGlzLnNsb3RzT2JqZWN0KSB7XG5cdFx0XHRpZiAob3RoZXJTbG90ICE9PSBzbG90ICYmIG9sZFBpeGlPYmplY3RBbm90aGVyU2xvdCA9PT0gcGl4aU9iamVjdCkge1xuXHRcdFx0XHR0aGlzLnJlbW92ZVNsb3RPYmplY3Qob3RoZXJTbG90LCBwaXhpT2JqZWN0KTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKG9sZFBpeGlPYmplY3QpIHRoaXMucmVtb3ZlQ2hpbGQob2xkUGl4aU9iamVjdCk7XG5cblx0XHR0aGlzLnNsb3RzT2JqZWN0LnNldChzbG90LCB7XG5cdFx0XHRjb250YWluZXI6IHBpeGlPYmplY3QsXG5cdFx0XHRmb2xsb3dBdHRhY2htZW50VGltZWxpbmU6IG9wdGlvbnM/LmZvbGxvd0F0dGFjaG1lbnRUaW1lbGluZSB8fCBmYWxzZSxcblx0XHRcdGZvbGxvd1Nsb3RDb2xvcjogb3B0aW9ucz8uZm9sbG93U2xvdENvbG9yIHx8IGZhbHNlLFxuXHRcdH0pO1xuXHRcdHRoaXMuYWRkQ2hpbGQocGl4aU9iamVjdCk7XG5cdH1cblx0LyoqXG5cdCAqIFJldHVybiB0aGUgQ29udGFpbmVyIGNvbm5lY3RlZCB0byB0aGUgZ2l2ZW4gc2xvdCwgaWYgYW55LlxuXHQgKiBPdGhlcndpc2UgcmV0dXJuIHVuZGVmaW5lZFxuXHQgKiBAcGFyYW0gcGl4aU9iamVjdCAtIFRoZSBzbG90IGluZGV4LCBvciB0aGUgc2xvdCBuYW1lLCBvciB0aGUgU2xvdCB0byBnZXQgdGhlIENvbnRhaW5lciBmcm9tLlxuXHQgKiBAcmV0dXJucyBhIENvbnRhaW5lciBpZiBhbnksIHVuZGVmaW5lZCBvdGhlcndpc2UuXG5cdCAqL1xuXHRnZXRTbG90T2JqZWN0IChzbG90UmVmOiBudW1iZXIgfCBzdHJpbmcgfCBTbG90KTogQ29udGFpbmVyIHwgdW5kZWZpbmVkIHtcblx0XHRjb25zdCBlbGVtZW50ID0gdGhpcy5zbG90c09iamVjdC5nZXQodGhpcy5nZXRTbG90RnJvbVJlZihzbG90UmVmKSk7XG5cdFx0cmV0dXJuIGVsZW1lbnQgPyBlbGVtZW50LmNvbnRhaW5lciA6IHVuZGVmaW5lZDtcblx0fVxuXG5cdC8qKlxuXHQgKiBSZW1vdmUgYSBzbG90IG9iamVjdCBmcm9tIHRoZSBnaXZlbiBzbG90LlxuXHQgKiBJZiBgcGl4aU9iamVjdGAgaXMgcGFzc2VkIGFuZCBhdHRhY2hlZCB0byB0aGUgZ2l2ZW4gc2xvdCwgcmVtb3ZlIGl0IGZyb20gdGhlIHNsb3QuXG5cdCAqIElmIGBwaXhpT2JqZWN0YCBpcyBub3QgcGFzc2VkIGFuZCB0aGUgZ2l2ZW4gc2xvdCBoYXMgYW4gYXR0YWNoZWQgQ29udGFpbmVyLCByZW1vdmUgaXQgZnJvbSB0aGUgc2xvdC5cblx0ICogQHBhcmFtIHNsb3RSZWYgLSBUaGUgc2xvdCBpbmRleCwgb3IgdGhlIHNsb3QgbmFtZSwgb3IgdGhlIFNsb3Qgd2hlcmUgdGhlIHBpeGkgb2JqZWN0IHdpbGwgYmUgcmVtb3ZlIGZyb20uXG5cdCAqIEBwYXJhbSBwaXhpT2JqZWN0IC0gT3B0aW9uYWwsIFRoZSBwaXhpIENvbnRhaW5lciB0byByZW1vdmUuXG5cdCAqL1xuXHRyZW1vdmVTbG90T2JqZWN0IChzbG90UmVmOiBudW1iZXIgfCBzdHJpbmcgfCBTbG90LCBwaXhpT2JqZWN0PzogQ29udGFpbmVyKTogdm9pZCB7XG5cdFx0bGV0IHNsb3QgPSB0aGlzLmdldFNsb3RGcm9tUmVmKHNsb3RSZWYpO1xuXHRcdGxldCBzbG90T2JqZWN0ID0gdGhpcy5zbG90c09iamVjdC5nZXQoc2xvdCk/LmNvbnRhaW5lcjtcblx0XHRpZiAoIXNsb3RPYmplY3QpIHJldHVybjtcblxuXHRcdC8vIGlmIHBpeGlPYmplY3QgaXMgcGFzc2VkLCByZW1vdmUgb25seSBpZiBpdCBpcyBlcXVhbCB0byB0aGUgZ2l2ZW4gb25lXG5cdFx0aWYgKHBpeGlPYmplY3QgJiYgcGl4aU9iamVjdCAhPT0gc2xvdE9iamVjdCkgcmV0dXJuO1xuXG5cdFx0dGhpcy5yZW1vdmVDaGlsZChzbG90T2JqZWN0KTtcblx0XHR0aGlzLnNsb3RzT2JqZWN0LmRlbGV0ZShzbG90KTtcblx0fVxuXG5cdC8qKlxuXHQgKiBSZW1vdmVzIGFsbCBQaXhpSlMgY29udGFpbmVycyBhdHRhY2hlZCB0byBhbnkgc2xvdC5cblx0ICovXG5cdHB1YmxpYyByZW1vdmVTbG90T2JqZWN0cyAoKSB7XG5cdFx0Zm9yIChjb25zdCBbLCBzbG90T2JqZWN0XSBvZiB0aGlzLnNsb3RzT2JqZWN0KSB7XG5cdFx0XHRzbG90T2JqZWN0LmNvbnRhaW5lci5yZW1vdmVGcm9tUGFyZW50KCk7XG5cdFx0fVxuXHRcdHRoaXMuc2xvdHNPYmplY3QuY2xlYXIoKTtcblx0fVxuXG5cdHByaXZhdGUgdmVydGljZXNDYWNoZTogTnVtYmVyQXJyYXlMaWtlID0gVXRpbHMubmV3RmxvYXRBcnJheSgxMDI0KTtcblx0cHJpdmF0ZSBjbGlwcGluZ1Nsb3RUb1BpeGlNYXNrczogUmVjb3JkPHN0cmluZywgU2xvdHNUb0NsaXBwaW5nPiA9IHt9O1xuXG5cdHByaXZhdGUgdXBkYXRlU2xvdE9iamVjdCAoZWxlbWVudDogeyBjb250YWluZXI6IENvbnRhaW5lciwgZm9sbG93QXR0YWNobWVudFRpbWVsaW5lOiBib29sZWFuLCBmb2xsb3dTbG90Q29sb3I6IGJvb2xlYW4gfSwgc2xvdDogU2xvdCwgekluZGV4OiBudW1iZXIpIHtcblx0XHRjb25zdCB7IGNvbnRhaW5lcjogc2xvdE9iamVjdCwgZm9sbG93QXR0YWNobWVudFRpbWVsaW5lIH0gPSBlbGVtZW50XG5cblx0XHRjb25zdCBmb2xsb3dBdHRhY2htZW50VmFsdWUgPSBmb2xsb3dBdHRhY2htZW50VGltZWxpbmUgPyBCb29sZWFuKHNsb3QuYXR0YWNobWVudCkgOiB0cnVlO1xuXHRcdHNsb3RPYmplY3QudmlzaWJsZSA9IHRoaXMuc2tlbGV0b24uZHJhd09yZGVyLmluY2x1ZGVzKHNsb3QpICYmIGZvbGxvd0F0dGFjaG1lbnRWYWx1ZTtcblxuXHRcdGlmIChzbG90T2JqZWN0LnZpc2libGUpIHtcblx0XHRcdGxldCBib25lID0gc2xvdC5ib25lO1xuXG5cdFx0XHRjb25zdCBtYXRyaXggPSBzbG90T2JqZWN0LmxvY2FsVHJhbnNmb3JtO1xuXHRcdFx0bWF0cml4LmEgPSBib25lLmE7XG5cdFx0XHRtYXRyaXguYiA9IGJvbmUuYztcblx0XHRcdG1hdHJpeC5jID0gLWJvbmUuYjtcblx0XHRcdG1hdHJpeC5kID0gLWJvbmUuZDtcblx0XHRcdG1hdHJpeC50eCA9IGJvbmUud29ybGRYO1xuXHRcdFx0bWF0cml4LnR5ID0gYm9uZS53b3JsZFk7XG5cdFx0XHRzbG90T2JqZWN0LnRyYW5zZm9ybS5zZXRGcm9tTWF0cml4KG1hdHJpeCk7XG5cblx0XHRcdHNsb3RPYmplY3QuekluZGV4ID0gekluZGV4O1xuXHRcdFx0c2xvdE9iamVjdC5hbHBoYSA9IHRoaXMuc2tlbGV0b24uY29sb3IuYSAqIHNsb3QuY29sb3IuYTtcblxuXHRcdFx0aWYgKGVsZW1lbnQuZm9sbG93U2xvdENvbG9yKSB7XG5cdFx0XHRcdHRoaXMuc2V0U2xvdE9iamVjdFRpbnQoc2xvdE9iamVjdCxcblx0XHRcdFx0XHQoKDI1NSAqIHRoaXMuc2tlbGV0b24uY29sb3IuciAqIHNsb3QuY29sb3IucikgPDwgMTYpIHxcblx0XHRcdFx0XHQoKDI1NSAqIHRoaXMuc2tlbGV0b24uY29sb3IuZyAqIHNsb3QuY29sb3IuZykgPDwgOCkgfFxuXHRcdFx0XHRcdCgyNTUgKiB0aGlzLnNrZWxldG9uLmNvbG9yLmIgKiBzbG90LmNvbG9yLmIpXG5cdFx0XHRcdCk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0cHJpdmF0ZSBzZXRTbG90T2JqZWN0VGludCAoc2xvdE9iamVjdDogQ29udGFpbmVyLCB0aW50OiBudW1iZXIpIHtcblx0XHRjb25zdCB0aW50YWJsZSA9IHNsb3RPYmplY3QgYXMgQ29udGFpbmVyICYgeyB0aW50PzogbnVtYmVyLCBjaGlsZHJlbj86IENvbnRhaW5lcltdIH07XG5cblx0XHRpZiAoXCJ0aW50XCIgaW4gdGludGFibGUpIHRpbnRhYmxlLnRpbnQgPSB0aW50O1xuXG5cdFx0Zm9yIChjb25zdCBjaGlsZCBvZiB0aW50YWJsZS5jaGlsZHJlbiA/PyBbXSkge1xuXHRcdFx0dGhpcy5zZXRTbG90T2JqZWN0VGludChjaGlsZCwgdGludCk7XG5cdFx0fVxuXHR9XG5cblx0cHJpdmF0ZSBjdXJyZW50Q2xpcHBpbmdTbG90OiBTbG90c1RvQ2xpcHBpbmcgfCB1bmRlZmluZWQ7XG5cdHByaXZhdGUgdXBkYXRlQW5kU2V0UGl4aU1hc2sgKHNsb3Q6IFNsb3QsIGxhc3Q6IGJvb2xlYW4pIHtcblx0XHQvLyBhc3NpZ24vY3JlYXRlIHRoZSBjdXJyZW50Q2xpcHBpbmdTbG90XG5cdFx0Y29uc3QgYXR0YWNobWVudCA9IHNsb3QuYXR0YWNobWVudDtcblx0XHRpZiAoYXR0YWNobWVudCAmJiBhdHRhY2htZW50IGluc3RhbmNlb2YgQ2xpcHBpbmdBdHRhY2htZW50KSB7XG5cdFx0XHRjb25zdCBjbGlwID0gKHRoaXMuY2xpcHBpbmdTbG90VG9QaXhpTWFza3Nbc2xvdC5kYXRhLm5hbWVdIHx8PSB7IHNsb3QsIHZlcnRpY2VzOiBuZXcgQXJyYXk8bnVtYmVyPigpIH0pO1xuXHRcdFx0Y2xpcC5tYXNrQ29tcHV0ZWQgPSBmYWxzZTtcblx0XHRcdHRoaXMuY3VycmVudENsaXBwaW5nU2xvdCA9IGNsaXA7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gYXNzaWduIHRoZSBjdXJyZW50Q2xpcHBpbmdTbG90IG1hc2sgdG8gdGhlIHNsb3Qgb2JqZWN0XG5cdFx0bGV0IGN1cnJlbnRDbGlwcGluZ1Nsb3QgPSB0aGlzLmN1cnJlbnRDbGlwcGluZ1Nsb3Q7XG5cdFx0Y29uc3Qgc2xvdE9iamVjdCA9IHRoaXMuc2xvdHNPYmplY3QuZ2V0KHNsb3QpO1xuXHRcdGlmIChjdXJyZW50Q2xpcHBpbmdTbG90ICYmIHNsb3RPYmplY3QpIHtcblx0XHRcdC8vIGNyZWF0ZSB0aGUgcGl4aSBtYXNrLCBvbmx5IHRoZSBmaXJzdCB0aW1lIGFuZCBpZiB0aGUgY2xpcHBlZCBzbG90IGlzIHRoZSBmaXJzdCBvbmUgY2xpcHBlZCBieSB0aGlzIGN1cnJlbnRDbGlwcGluZ1Nsb3Rcblx0XHRcdGxldCBtYXNrID0gY3VycmVudENsaXBwaW5nU2xvdC5tYXNrO1xuXHRcdFx0aWYgKCFtYXNrKSB7XG5cdFx0XHRcdG1hc2sgPSBtYXNrUG9vbC5vYnRhaW4oKTtcblx0XHRcdFx0Y3VycmVudENsaXBwaW5nU2xvdC5tYXNrID0gbWFzaztcblx0XHRcdFx0dGhpcy5hZGRDaGlsZChtYXNrKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gY29tcHV0ZSB0aGUgcGl4aSBtYXNrIHBvbHlnb24sIGlmIHRoZSBjbGlwcGVkIHNsb3QgaXMgdGhlIGZpcnN0IG9uZSBjbGlwcGVkIGJ5IHRoaXMgY3VycmVudENsaXBwaW5nU2xvdFxuXHRcdFx0aWYgKCFjdXJyZW50Q2xpcHBpbmdTbG90Lm1hc2tDb21wdXRlZCkge1xuXHRcdFx0XHRsZXQgc2xvdENsaXBwaW5nID0gY3VycmVudENsaXBwaW5nU2xvdC5zbG90O1xuXHRcdFx0XHRsZXQgY2xpcHBpbmdBdHRhY2htZW50ID0gc2xvdENsaXBwaW5nLmF0dGFjaG1lbnQgYXMgQ2xpcHBpbmdBdHRhY2htZW50O1xuXHRcdFx0XHRjdXJyZW50Q2xpcHBpbmdTbG90Lm1hc2tDb21wdXRlZCA9IHRydWU7XG5cdFx0XHRcdGNvbnN0IHdvcmxkVmVydGljZXNMZW5ndGggPSBjbGlwcGluZ0F0dGFjaG1lbnQud29ybGRWZXJ0aWNlc0xlbmd0aDtcblx0XHRcdFx0Y29uc3QgdmVydGljZXMgPSBjdXJyZW50Q2xpcHBpbmdTbG90LnZlcnRpY2VzO1xuXHRcdFx0XHRjbGlwcGluZ0F0dGFjaG1lbnQuY29tcHV0ZVdvcmxkVmVydGljZXMoc2xvdENsaXBwaW5nLCAwLCB3b3JsZFZlcnRpY2VzTGVuZ3RoLCB2ZXJ0aWNlcywgMCwgMik7XG5cdFx0XHRcdG1hc2suY2xlYXIoKS5saW5lU3R5bGUoMCkuYmVnaW5GaWxsKDB4MDAwMDAwKS5kcmF3UG9seWdvbih2ZXJ0aWNlcykuZW5kRmlsbCgpO1xuXHRcdFx0fVxuXG5cdFx0XHRzbG90T2JqZWN0LmNvbnRhaW5lci5tYXNrID0gbWFzaztcblx0XHR9IGVsc2UgaWYgKHNsb3RPYmplY3Q/LmNvbnRhaW5lci5tYXNrKSB7XG5cdFx0XHQvLyByZW1vdmUgdGhlIG1hc2ssIGlmIHNsb3Qgb2JqZWN0IGhhcyBhIG1hc2ssIGJ1dCBjdXJyZW50Q2xpcHBpbmdTbG90IGlzIHVuZGVmaW5lZFxuXHRcdFx0c2xvdE9iamVjdC5jb250YWluZXIubWFzayA9IG51bGw7XG5cdFx0fVxuXG5cdFx0Ly8gaWYgY3VycmVudCBzbG90IGlzIHRoZSBlbmRpbmcgb25lIG9mIHRoZSBjdXJyZW50Q2xpcHBpbmdTbG90IG1hc2ssIHNldCBjdXJyZW50Q2xpcHBpbmdTbG90IHRvIHVuZGVmaW5lZFxuXHRcdGlmIChjdXJyZW50Q2xpcHBpbmdTbG90ICYmIChjdXJyZW50Q2xpcHBpbmdTbG90LnNsb3QuYXR0YWNobWVudCBhcyBDbGlwcGluZ0F0dGFjaG1lbnQpLmVuZFNsb3QgPT0gc2xvdC5kYXRhKSB7XG5cdFx0XHR0aGlzLmN1cnJlbnRDbGlwcGluZ1Nsb3QgPSB1bmRlZmluZWQ7XG5cdFx0fVxuXG5cdFx0Ly8gY2xlYW4gdXAgdW51c2VkIG1hc2tzXG5cdFx0aWYgKGxhc3QpIHtcblx0XHRcdGZvciAoY29uc3Qga2V5IGluIHRoaXMuY2xpcHBpbmdTbG90VG9QaXhpTWFza3MpIHtcblx0XHRcdFx0Y29uc3QgY2xpcHBpbmdTbG90VG9QaXhpTWFzayA9IHRoaXMuY2xpcHBpbmdTbG90VG9QaXhpTWFza3Nba2V5XTtcblx0XHRcdFx0aWYgKCghKGNsaXBwaW5nU2xvdFRvUGl4aU1hc2suc2xvdC5hdHRhY2htZW50IGluc3RhbmNlb2YgQ2xpcHBpbmdBdHRhY2htZW50KSB8fCAhY2xpcHBpbmdTbG90VG9QaXhpTWFzay5tYXNrQ29tcHV0ZWQpICYmIGNsaXBwaW5nU2xvdFRvUGl4aU1hc2subWFzaykge1xuXHRcdFx0XHRcdHRoaXMucmVtb3ZlQ2hpbGQoY2xpcHBpbmdTbG90VG9QaXhpTWFzay5tYXNrKTtcblx0XHRcdFx0XHRtYXNrUG9vbC5mcmVlKGNsaXBwaW5nU2xvdFRvUGl4aU1hc2subWFzayk7XG5cdFx0XHRcdFx0Y2xpcHBpbmdTbG90VG9QaXhpTWFzay5tYXNrID0gdW5kZWZpbmVkO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHR0aGlzLmN1cnJlbnRDbGlwcGluZ1Nsb3QgPSB1bmRlZmluZWQ7XG5cdFx0fVxuXHR9XG5cblx0Lypcblx0KiBDb2xvcnMgaW4gcGl4aSBhcmUgcHJlbXVsdGlwbGllZC5cblx0KiBQaXhpIGJsZW5kaW5nIG1vZGVzIGFyZSBtb2RpZmllZCB0byB3b3JrIHdpdGggcHJlbXVsdGlwbGllZCBjb2xvcnMuIFdlIGNhbm5vdCBjcmVhdGUgY3VzdG9tIGJsZW5kaW5nIG1vZGVzLlxuXHQqIFRleHR1cmVzIGFyZSBsb2FkZWQgYXMgcHJlbXVsdGlwbGllZCAoc2VlIGFzc2Vycy9hdGxhc0xvYWRlci50czogYWxwaGFNb2RlOiBgcGFnZS5wbWEgPyBBTFBIQV9NT0RFUy5QTUEgOiBBTFBIQV9NT0RFUy5VTlBBQ0tgKTpcblx0KiAtIHRleHR1cmVzIG5vbiBwcmVtdWx0aXBsaWVkIGFyZSBwcmVtdWx0aXBsaWVkIG9uIEdQVSBvbiB1cGxvYWRcblx0KiAtIHRleHR1cmVzIHByZW11bHRpcGxpZWQgYXJlIHVwbG9hZGVkIG9uIEdQVSBhcyBpcyBzaW5jZSB0aGV5IGFyZSBhbHJlYWR5IHByZW11bHRpcGxpZWRcblx0KlxuXHQqIFdlIG5lZWQgdG8gdGFrZSB0aGlzIGludG8gY29uc2lkZXJhdGlvbiBhbmQgY2FsY3VsYXRlcyBmaW5hbCBjb2xvcnMgZm9yIGJvdGggbGlnaHQgYW5kIGRhcmsgY29sb3IgYXMgaWYgdGV4dHVyZXMgd2VyZSBhbHdheXMgcHJlbXVsdGlwbGllZC5cblx0KiBUaGlzIGltcGxpZXMgZm9yIGV4YW1wbGUgdGhhdCBhbHBoYSBmb3IgZGFyayB0aW50IGlzIGFsd2F5cyAxLiBUaGlzIGlzIHdheSBpbiBEYXJrVGludFJlbmRlcmVyIHdlIGhhdmUgb25seSB0aGUgYWxwaGEgb2YgdGhlIGxpZ2h0IGNvbG9yLlxuXHQqIElmIHdlIGV2ZXIgd2FudCB0byBsb2FkIHRleHR1cmUgYXMgbm9uIHByZW11bHRpcGxpZWQgb24gR1BVLCB3ZSBtdXN0IGFkZCBhIG5ldyBkYXJrIGFscGhhIHBhcmFtZXRlciB0byB0aGUgVGludE1hdGVyaWFsIGFuZCBzZXQgdGhlIGFscGhhLlxuXHQqL1xuXHRwcml2YXRlIHJlbmRlck1lc2hlcyAoKTogdm9pZCB7XG5cdFx0dGhpcy5yZXNldE1lc2hlcygpO1xuXG5cdFx0bGV0IHRyaWFuZ2xlczogQXJyYXk8bnVtYmVyPiB8IG51bGwgPSBudWxsO1xuXHRcdGxldCB1dnM6IE51bWJlckFycmF5TGlrZSB8IG51bGwgPSBudWxsO1xuXG5cdFx0Y29uc3QgZHJhd09yZGVyID0gdGhpcy5za2VsZXRvbi5kcmF3T3JkZXI7XG5cblx0XHRmb3IgKGxldCBpID0gMCwgbiA9IGRyYXdPcmRlci5sZW5ndGgsIHNsb3RPYmplY3RzQ291bnRlciA9IDA7IGkgPCBuOyBpKyspIHtcblx0XHRcdGNvbnN0IHNsb3QgPSBkcmF3T3JkZXJbaV07XG5cblx0XHRcdC8vIHJlbmRlciBwaXhpIG9iamVjdCBvbiB0aGUgY3VycmVudCBzbG90IG9uIHRvcCBvZiB0aGUgc2xvdCBhdHRhY2htZW50XG5cdFx0XHRsZXQgcGl4aU9iamVjdCA9IHRoaXMuc2xvdHNPYmplY3QuZ2V0KHNsb3QpO1xuXHRcdFx0bGV0IHpJbmRleCA9IGkgKyBzbG90T2JqZWN0c0NvdW50ZXI7XG5cdFx0XHRpZiAocGl4aU9iamVjdCkge1xuXHRcdFx0XHR0aGlzLnVwZGF0ZVNsb3RPYmplY3QocGl4aU9iamVjdCwgc2xvdCwgekluZGV4ICsgMSk7XG5cdFx0XHRcdHNsb3RPYmplY3RzQ291bnRlcisrO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy51cGRhdGVBbmRTZXRQaXhpTWFzayhzbG90LCBpID09PSBkcmF3T3JkZXIubGVuZ3RoIC0gMSk7XG5cblx0XHRcdGNvbnN0IHVzZURhcmtDb2xvciA9IHNsb3QuZGFya0NvbG9yICE9IG51bGw7XG5cdFx0XHRjb25zdCB2ZXJ0ZXhTaXplID0gU3BpbmUuY2xpcHBlci5pc0NsaXBwaW5nKCkgPyAyIDogdXNlRGFya0NvbG9yID8gU3BpbmUuREFSS19WRVJURVhfU0laRSA6IFNwaW5lLlZFUlRFWF9TSVpFO1xuXHRcdFx0aWYgKCFzbG90LmJvbmUuYWN0aXZlKSB7XG5cdFx0XHRcdFNwaW5lLmNsaXBwZXIuY2xpcEVuZFdpdGhTbG90KHNsb3QpO1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblx0XHRcdGNvbnN0IGF0dGFjaG1lbnQgPSBzbG90LmdldEF0dGFjaG1lbnQoKTtcblx0XHRcdGxldCBhdHRhY2htZW50Q29sb3I6IENvbG9yIHwgbnVsbDtcblx0XHRcdGxldCB0ZXh0dXJlOiBTcGluZVRleHR1cmUgfCBudWxsO1xuXHRcdFx0bGV0IG51bUZsb2F0cyA9IDA7XG5cdFx0XHRpZiAoYXR0YWNobWVudCBpbnN0YW5jZW9mIFJlZ2lvbkF0dGFjaG1lbnQpIHtcblx0XHRcdFx0Y29uc3QgcmVnaW9uID0gYXR0YWNobWVudDtcblx0XHRcdFx0YXR0YWNobWVudENvbG9yID0gcmVnaW9uLmNvbG9yO1xuXHRcdFx0XHRudW1GbG9hdHMgPSB2ZXJ0ZXhTaXplICogNDtcblx0XHRcdFx0cmVnaW9uLmNvbXB1dGVXb3JsZFZlcnRpY2VzKHNsb3QsIHRoaXMudmVydGljZXNDYWNoZSwgMCwgdmVydGV4U2l6ZSk7XG5cdFx0XHRcdHRyaWFuZ2xlcyA9IFNwaW5lLlFVQURfVFJJQU5HTEVTO1xuXHRcdFx0XHR1dnMgPSByZWdpb24udXZzO1xuXHRcdFx0XHR0ZXh0dXJlID0gPFNwaW5lVGV4dHVyZT5yZWdpb24ucmVnaW9uPy50ZXh0dXJlO1xuXHRcdFx0fSBlbHNlIGlmIChhdHRhY2htZW50IGluc3RhbmNlb2YgTWVzaEF0dGFjaG1lbnQpIHtcblx0XHRcdFx0Y29uc3QgbWVzaCA9IGF0dGFjaG1lbnQ7XG5cdFx0XHRcdGF0dGFjaG1lbnRDb2xvciA9IG1lc2guY29sb3I7XG5cdFx0XHRcdG51bUZsb2F0cyA9IChtZXNoLndvcmxkVmVydGljZXNMZW5ndGggPj4gMSkgKiB2ZXJ0ZXhTaXplO1xuXHRcdFx0XHRpZiAobnVtRmxvYXRzID4gdGhpcy52ZXJ0aWNlc0NhY2hlLmxlbmd0aCkge1xuXHRcdFx0XHRcdHRoaXMudmVydGljZXNDYWNoZSA9IFV0aWxzLm5ld0Zsb2F0QXJyYXkobnVtRmxvYXRzKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRtZXNoLmNvbXB1dGVXb3JsZFZlcnRpY2VzKHNsb3QsIDAsIG1lc2gud29ybGRWZXJ0aWNlc0xlbmd0aCwgdGhpcy52ZXJ0aWNlc0NhY2hlLCAwLCB2ZXJ0ZXhTaXplKTtcblx0XHRcdFx0dHJpYW5nbGVzID0gbWVzaC50cmlhbmdsZXM7XG5cdFx0XHRcdHV2cyA9IG1lc2gudXZzO1xuXHRcdFx0XHR0ZXh0dXJlID0gPFNwaW5lVGV4dHVyZT5tZXNoLnJlZ2lvbj8udGV4dHVyZTtcblx0XHRcdH0gZWxzZSBpZiAoYXR0YWNobWVudCBpbnN0YW5jZW9mIENsaXBwaW5nQXR0YWNobWVudCkge1xuXHRcdFx0XHRTcGluZS5jbGlwcGVyLmNsaXBTdGFydChzbG90LCBhdHRhY2htZW50KTtcblx0XHRcdFx0Y29udGludWU7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRpZiAodGhpcy5oYXNNZXNoRm9yU2xvdChzbG90KSkge1xuXHRcdFx0XHRcdHRoaXMuZ2V0TWVzaEZvclNsb3Qoc2xvdCkudmlzaWJsZSA9IGZhbHNlO1xuXHRcdFx0XHR9XG5cdFx0XHRcdFNwaW5lLmNsaXBwZXIuY2xpcEVuZFdpdGhTbG90KHNsb3QpO1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblx0XHRcdGlmICh0ZXh0dXJlICE9IG51bGwpIHtcblx0XHRcdFx0Y29uc3Qgc2tlbGV0b24gPSBzbG90LmJvbmUuc2tlbGV0b247XG5cdFx0XHRcdGNvbnN0IHNrZWxldG9uQ29sb3IgPSBza2VsZXRvbi5jb2xvcjtcblx0XHRcdFx0Y29uc3Qgc2xvdENvbG9yID0gc2xvdC5jb2xvcjtcblx0XHRcdFx0Y29uc3QgYWxwaGEgPSBza2VsZXRvbkNvbG9yLmEgKiBzbG90Q29sb3IuYSAqIGF0dGFjaG1lbnRDb2xvci5hO1xuXHRcdFx0XHQvLyBjYW5ub3QgcHJlbXVsdGlwbHkgdGhlIGNvbG9ycyBiZWNhdXNlIHRoZSBkZWZhdWx0IG1lc2ggcmVuZGVyZXIgYWxyZWFkeSBkb2VzIHRoYXRcblx0XHRcdFx0dGhpcy5saWdodENvbG9yLnNldChcblx0XHRcdFx0XHRza2VsZXRvbkNvbG9yLnIgKiBzbG90Q29sb3IuciAqIGF0dGFjaG1lbnRDb2xvci5yLFxuXHRcdFx0XHRcdHNrZWxldG9uQ29sb3IuZyAqIHNsb3RDb2xvci5nICogYXR0YWNobWVudENvbG9yLmcsXG5cdFx0XHRcdFx0c2tlbGV0b25Db2xvci5iICogc2xvdENvbG9yLmIgKiBhdHRhY2htZW50Q29sb3IuYixcblx0XHRcdFx0XHRhbHBoYVxuXHRcdFx0XHQpO1xuXHRcdFx0XHRpZiAoc2xvdC5kYXJrQ29sb3IgIT0gbnVsbCkge1xuXHRcdFx0XHRcdHRoaXMuZGFya0NvbG9yLnNldChcblx0XHRcdFx0XHRcdHNsb3QuZGFya0NvbG9yLnIsXG5cdFx0XHRcdFx0XHRzbG90LmRhcmtDb2xvci5nLFxuXHRcdFx0XHRcdFx0c2xvdC5kYXJrQ29sb3IuYixcblx0XHRcdFx0XHRcdDEsXG5cdFx0XHRcdFx0KTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHR0aGlzLmRhcmtDb2xvci5zZXQoMCwgMCwgMCwgMSk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRsZXQgZmluYWxWZXJ0aWNlczogTnVtYmVyQXJyYXlMaWtlO1xuXHRcdFx0XHRsZXQgZmluYWxWZXJ0aWNlc0xlbmd0aDogbnVtYmVyO1xuXHRcdFx0XHRsZXQgZmluYWxJbmRpY2VzOiBOdW1iZXJBcnJheUxpa2U7XG5cdFx0XHRcdGxldCBmaW5hbEluZGljZXNMZW5ndGg6IG51bWJlcjtcblxuXHRcdFx0XHRpZiAoU3BpbmUuY2xpcHBlci5pc0NsaXBwaW5nKCkpIHtcblx0XHRcdFx0XHRTcGluZS5jbGlwcGVyLmNsaXBUcmlhbmdsZXModGhpcy52ZXJ0aWNlc0NhY2hlLCB0cmlhbmdsZXMsIHRyaWFuZ2xlcy5sZW5ndGgsIHV2cywgdGhpcy5saWdodENvbG9yLCB0aGlzLmRhcmtDb2xvciwgdXNlRGFya0NvbG9yKTtcblxuXHRcdFx0XHRcdGZpbmFsVmVydGljZXMgPSBTcGluZS5jbGlwcGVyLmNsaXBwZWRWZXJ0aWNlcztcblx0XHRcdFx0XHRmaW5hbFZlcnRpY2VzTGVuZ3RoID0gZmluYWxWZXJ0aWNlcy5sZW5ndGg7XG5cblx0XHRcdFx0XHRmaW5hbEluZGljZXMgPSBTcGluZS5jbGlwcGVyLmNsaXBwZWRUcmlhbmdsZXM7XG5cdFx0XHRcdFx0ZmluYWxJbmRpY2VzTGVuZ3RoID0gZmluYWxJbmRpY2VzLmxlbmd0aDtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRjb25zdCB2ZXJ0cyA9IHRoaXMudmVydGljZXNDYWNoZTtcblx0XHRcdFx0XHRmb3IgKGxldCB2ID0gMiwgdSA9IDAsIG4gPSBudW1GbG9hdHM7IHYgPCBuOyB2ICs9IHZlcnRleFNpemUsIHUgKz0gMikge1xuXHRcdFx0XHRcdFx0bGV0IHRlbXBWID0gdjtcblx0XHRcdFx0XHRcdHZlcnRzW3RlbXBWKytdID0gdGhpcy5saWdodENvbG9yLnI7XG5cdFx0XHRcdFx0XHR2ZXJ0c1t0ZW1wVisrXSA9IHRoaXMubGlnaHRDb2xvci5nO1xuXHRcdFx0XHRcdFx0dmVydHNbdGVtcFYrK10gPSB0aGlzLmxpZ2h0Q29sb3IuYjtcblx0XHRcdFx0XHRcdHZlcnRzW3RlbXBWKytdID0gdGhpcy5saWdodENvbG9yLmE7XG5cblx0XHRcdFx0XHRcdHZlcnRzW3RlbXBWKytdID0gdXZzW3VdO1xuXHRcdFx0XHRcdFx0dmVydHNbdGVtcFYrK10gPSB1dnNbdSArIDFdO1xuXG5cdFx0XHRcdFx0XHRpZiAodXNlRGFya0NvbG9yKSB7XG5cdFx0XHRcdFx0XHRcdHZlcnRzW3RlbXBWKytdID0gdGhpcy5kYXJrQ29sb3Iucjtcblx0XHRcdFx0XHRcdFx0dmVydHNbdGVtcFYrK10gPSB0aGlzLmRhcmtDb2xvci5nO1xuXHRcdFx0XHRcdFx0XHR2ZXJ0c1t0ZW1wVisrXSA9IHRoaXMuZGFya0NvbG9yLmI7XG5cdFx0XHRcdFx0XHRcdHZlcnRzW3RlbXBWKytdID0gdGhpcy5kYXJrQ29sb3IuYTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZmluYWxWZXJ0aWNlcyA9IHRoaXMudmVydGljZXNDYWNoZTtcblx0XHRcdFx0XHRmaW5hbFZlcnRpY2VzTGVuZ3RoID0gbnVtRmxvYXRzO1xuXHRcdFx0XHRcdGZpbmFsSW5kaWNlcyA9IHRyaWFuZ2xlcztcblx0XHRcdFx0XHRmaW5hbEluZGljZXNMZW5ndGggPSB0cmlhbmdsZXMubGVuZ3RoO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKGZpbmFsVmVydGljZXNMZW5ndGggPT0gMCB8fCBmaW5hbEluZGljZXNMZW5ndGggPT0gMCkge1xuXHRcdFx0XHRcdFNwaW5lLmNsaXBwZXIuY2xpcEVuZFdpdGhTbG90KHNsb3QpO1xuXHRcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Y29uc3QgbWVzaCA9IHRoaXMuZ2V0TWVzaEZvclNsb3Qoc2xvdCk7XG5cdFx0XHRcdG1lc2gucmVuZGVyYWJsZSA9IHRydWU7XG5cdFx0XHRcdG1lc2guekluZGV4ID0gekluZGV4O1xuXHRcdFx0XHRtZXNoLnVwZGF0ZUZyb21TcGluZURhdGEodGV4dHVyZSwgc2xvdC5kYXRhLmJsZW5kTW9kZSwgc2xvdC5kYXRhLm5hbWUsIGZpbmFsVmVydGljZXMsIGZpbmFsVmVydGljZXNMZW5ndGgsIGZpbmFsSW5kaWNlcywgZmluYWxJbmRpY2VzTGVuZ3RoLCB1c2VEYXJrQ29sb3IpO1xuXHRcdFx0fVxuXG5cdFx0XHRTcGluZS5jbGlwcGVyLmNsaXBFbmRXaXRoU2xvdChzbG90KTtcblx0XHR9XG5cdFx0U3BpbmUuY2xpcHBlci5jbGlwRW5kKCk7XG5cdH1cblxuXHRjYWxjdWxhdGVCb3VuZHMgKCkge1xuXHRcdGlmICghdGhpcy5fYm91bmRzUHJvdmlkZXIpIHtcblx0XHRcdHN1cGVyLmNhbGN1bGF0ZUJvdW5kcygpO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGNvbnN0IHRyYW5zZm9ybSA9IHRoaXMudHJhbnNmb3JtO1xuXHRcdGlmICh0aGlzLl9ib3VuZHNTcGluZUlEID09PSB0cmFuc2Zvcm0uX3dvcmxkSUQpIHJldHVybjtcblxuXHRcdHRoaXMudXBkYXRlQm91bmRzKCk7XG5cblx0XHRjb25zdCBib3VuZHMgPSB0aGlzLl9sb2NhbEJvdW5kcztcblx0XHRjb25zdCBwID0gdGhpcy5fYm91bmRzUG9pbnQ7XG5cblx0XHRwLnNldChib3VuZHMubWluWCwgYm91bmRzLm1pblkpO1xuXHRcdHRyYW5zZm9ybS53b3JsZFRyYW5zZm9ybS5hcHBseShwLCBwKTtcblx0XHR0aGlzLl9ib3VuZHMubWluWCA9IHAueFxuXHRcdHRoaXMuX2JvdW5kcy5taW5ZID0gcC55O1xuXG5cdFx0cC5zZXQoYm91bmRzLm1heFgsIGJvdW5kcy5tYXhZKVxuXHRcdHRyYW5zZm9ybS53b3JsZFRyYW5zZm9ybS5hcHBseShwLCBwKTtcblx0XHR0aGlzLl9ib3VuZHMubWF4WCA9IHAueFxuXHRcdHRoaXMuX2JvdW5kcy5tYXhZID0gcC55O1xuXHR9XG5cblx0dXBkYXRlQm91bmRzICgpIHtcblx0XHRpZiAoIXRoaXMuX2JvdW5kc1Byb3ZpZGVyIHx8ICF0aGlzLl9ib3VuZHNTcGluZURpcnR5KSByZXR1cm47XG5cblx0XHR0aGlzLl9ib3VuZHNTcGluZURpcnR5ID0gZmFsc2U7XG5cblx0XHRpZiAoIXRoaXMuX2xvY2FsQm91bmRzKSB7XG5cdFx0XHR0aGlzLl9sb2NhbEJvdW5kcyA9IG5ldyBCb3VuZHMoKTtcblx0XHR9XG5cblx0XHRjb25zdCBib3VuZHNTcGluZSA9IHRoaXMuX2JvdW5kc1Byb3ZpZGVyLmNhbGN1bGF0ZUJvdW5kcyh0aGlzKTtcblxuXHRcdGNvbnN0IGJvdW5kcyA9IHRoaXMuX2xvY2FsQm91bmRzO1xuXHRcdGJvdW5kcy5jbGVhcigpO1xuXHRcdGJvdW5kcy5taW5YID0gYm91bmRzU3BpbmUueDtcblx0XHRib3VuZHMubWluWSA9IGJvdW5kc1NwaW5lLnk7XG5cdFx0Ym91bmRzLm1heFggPSBib3VuZHNTcGluZS54ICsgYm91bmRzU3BpbmUud2lkdGg7XG5cdFx0Ym91bmRzLm1heFkgPSBib3VuZHNTcGluZS55ICsgYm91bmRzU3BpbmUuaGVpZ2h0O1xuXG5cdFx0dGhpcy5oaXRBcmVhID0gdGhpcy5fbG9jYWxCb3VuZHMuZ2V0UmVjdGFuZ2xlKCk7XG5cdH1cblxuXHQvKipcblx0ICogU2V0IHRoZSBwb3NpdGlvbiBvZiB0aGUgYm9uZSBnaXZlbiBpbiBpbnB1dCB0aHJvdWdoIGEge0BsaW5rIElQb2ludERhdGF9LlxuXHQgKiBAcGFyYW0gYm9uZTogdGhlIGJvbmUgbmFtZSBvciB0aGUgYm9uZSBpbnN0YW5jZSB0byBzZXQgdGhlIHBvc2l0aW9uXG5cdCAqIEBwYXJhbSBvdXRQb3M6IHRoZSBuZXcgcG9zaXRpb24gb2YgdGhlIGJvbmUuXG5cdCAqIEB0aHJvd3Mge0Vycm9yfTogaWYgdGhlIGdpdmVuIGJvbmUgaXMgbm90IGZvdW5kIGluIHRoZSBza2VsZXRvbiwgYW4gZXJyb3IgaXMgdGhyb3duXG5cdCAqL1xuXHRwdWJsaWMgc2V0Qm9uZVBvc2l0aW9uIChib25lOiBzdHJpbmcgfCBCb25lLCBwb3NpdGlvbjogSVBvaW50RGF0YSk6IHZvaWQge1xuXHRcdGNvbnN0IGJvbmVBdXggPSBib25lO1xuXHRcdGlmICh0eXBlb2YgYm9uZSA9PT0gXCJzdHJpbmdcIikge1xuXHRcdFx0Ym9uZSA9IHRoaXMuc2tlbGV0b24uZmluZEJvbmUoYm9uZSkhO1xuXHRcdH1cblxuXHRcdGlmICghYm9uZSkgdGhyb3cgRXJyb3IoYENhbm5vdCBzZXQgYm9uZSBwb3NpdGlvbiwgYm9uZSAke1N0cmluZyhib25lQXV4KX0gbm90IGZvdW5kYCk7XG5cdFx0U3BpbmUudmVjdG9yQXV4LnNldChwb3NpdGlvbi54LCBwb3NpdGlvbi55KTtcblxuXHRcdGlmIChib25lLnBhcmVudCkge1xuXHRcdFx0Y29uc3QgYXV4ID0gYm9uZS5wYXJlbnQud29ybGRUb0xvY2FsKFNwaW5lLnZlY3RvckF1eCk7XG5cdFx0XHRib25lLnggPSBhdXgueDtcblx0XHRcdGJvbmUueSA9IGF1eC55O1xuXHRcdH1cblx0XHRlbHNlIHtcblx0XHRcdGJvbmUueCA9IFNwaW5lLnZlY3RvckF1eC54O1xuXHRcdFx0Ym9uZS55ID0gU3BpbmUudmVjdG9yQXV4Lnk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIFJldHVybiB0aGUgcG9zaXRpb24gb2YgdGhlIGJvbmUgZ2l2ZW4gaW4gaW5wdXQgaW50byBhbiB7QGxpbmsgSVBvaW50RGF0YX0uXG5cdCAqIEBwYXJhbSBib25lOiB0aGUgYm9uZSBuYW1lIG9yIHRoZSBib25lIGluc3RhbmNlIHRvIGdldCB0aGUgcG9zaXRpb24gZnJvbVxuXHQgKiBAcGFyYW0gb3V0UG9zOiBhbiBvcHRpb25hbCB7QGxpbmsgSVBvaW50RGF0YX0gdG8gdXNlIHRvIHJldHVybiB0aGUgYm9uZSBwb3NpdGlvbiwgcmF0aGVybiB0aGFuIGluc3RhbnRpYXRpbmcgYSBuZXcgb2JqZWN0LlxuXHQgKiBAcmV0dXJucyB7SVBvaW50RGF0YSB8IHVuZGVmaW5lZH06IHRoZSBwb3NpdGlvbiBvZiB0aGUgYm9uZSwgb3IgdW5kZWZpbmVkIGlmIG5vIG1hdGNoaW5nIGJvbmUgaXMgZm91bmQgaW4gdGhlIHNrZWxldG9uXG5cdCAqL1xuXHRwdWJsaWMgZ2V0Qm9uZVBvc2l0aW9uIChib25lOiBzdHJpbmcgfCBCb25lLCBvdXRQb3M/OiBJUG9pbnREYXRhKTogSVBvaW50RGF0YSB8IHVuZGVmaW5lZCB7XG5cdFx0Y29uc3QgYm9uZUF1eCA9IGJvbmU7XG5cdFx0aWYgKHR5cGVvZiBib25lID09PSBcInN0cmluZ1wiKSB7XG5cdFx0XHRib25lID0gdGhpcy5za2VsZXRvbi5maW5kQm9uZShib25lKSE7XG5cdFx0fVxuXG5cdFx0aWYgKCFib25lKSB7XG5cdFx0XHRjb25zb2xlLmVycm9yKGBDYW5ub3QgZ2V0IGJvbmUgcG9zaXRpb24hIEJvbmUgJHtTdHJpbmcoYm9uZUF1eCl9IG5vdCBmb3VuZGApO1xuXHRcdFx0cmV0dXJuIG91dFBvcztcblx0XHR9XG5cblx0XHRpZiAoIW91dFBvcykge1xuXHRcdFx0b3V0UG9zID0geyB4OiAwLCB5OiAwIH07XG5cdFx0fVxuXG5cdFx0b3V0UG9zLnggPSBib25lLndvcmxkWDtcblx0XHRvdXRQb3MueSA9IGJvbmUud29ybGRZO1xuXHRcdHJldHVybiBvdXRQb3M7XG5cdH1cblxuXHQvKiogQ29udmVydHMgYSBwb2ludCBmcm9tIHRoZSBza2VsZXRvbiBjb29yZGluYXRlIHN5c3RlbSB0byB0aGUgUGl4aSB3b3JsZCBjb29yZGluYXRlIHN5c3RlbS4gKi9cblx0c2tlbGV0b25Ub1BpeGlXb3JsZENvb3JkaW5hdGVzIChwb2ludDogeyB4OiBudW1iZXI7IHk6IG51bWJlciB9KSB7XG5cdFx0dGhpcy53b3JsZFRyYW5zZm9ybS5hcHBseShwb2ludCwgcG9pbnQpO1xuXHR9XG5cblx0LyoqIENvbnZlcnRzIGEgcG9pbnQgZnJvbSB0aGUgUGl4aSB3b3JsZCBjb29yZGluYXRlIHN5c3RlbSB0byB0aGUgc2tlbGV0b24gY29vcmRpbmF0ZSBzeXN0ZW0uICovXG5cdHBpeGlXb3JsZENvb3JkaW5hdGVzVG9Ta2VsZXRvbiAocG9pbnQ6IHsgeDogbnVtYmVyOyB5OiBudW1iZXIgfSkge1xuXHRcdHRoaXMud29ybGRUcmFuc2Zvcm0uYXBwbHlJbnZlcnNlKHBvaW50LCBwb2ludCk7XG5cdH1cblxuXHQvKiogQ29udmVydHMgYSBwb2ludCBmcm9tIHRoZSBQaXhpIHdvcmxkIGNvb3JkaW5hdGUgc3lzdGVtIHRvIHRoZSBib25lJ3MgbG9jYWwgY29vcmRpbmF0ZSBzeXN0ZW0uICovXG5cdHBpeGlXb3JsZENvb3JkaW5hdGVzVG9Cb25lIChwb2ludDogeyB4OiBudW1iZXI7IHk6IG51bWJlciB9LCBib25lOiBCb25lKSB7XG5cdFx0dGhpcy5waXhpV29ybGRDb29yZGluYXRlc1RvU2tlbGV0b24ocG9pbnQpO1xuXHRcdGlmIChib25lLnBhcmVudCkge1xuXHRcdFx0Ym9uZS5wYXJlbnQud29ybGRUb0xvY2FsKHBvaW50IGFzIFZlY3RvcjIpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRib25lLndvcmxkVG9Mb2NhbChwb2ludCBhcyBWZWN0b3IyKTtcblx0XHR9XG5cdH1cblxuXHQvKiogQSBjYWNoZSBjb250YWluaW5nIHNrZWxldG9uIGRhdGEgYW5kIGF0bGFzZXMgYWxyZWFkeSBsb2FkZWQgYnkge0BsaW5rIFNwaW5lLmZyb219LiAqL1xuXHRwdWJsaWMgc3RhdGljIHJlYWRvbmx5IHNrZWxldG9uQ2FjaGU6IFJlY29yZDxzdHJpbmcsIFNrZWxldG9uRGF0YT4gPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuXG5cdC8qKlxuXHQgKiBVc2UgdGhpcyBtZXRob2QgdG8gaW5zdGFudGlhdGUgYSBTcGluZSBnYW1lIG9iamVjdC5cblx0ICogQmVmb3JlIGluc3RhbnRpYXRpbmcgYSBTcGluZSBnYW1lIG9iamVjdCwgdGhlIHNrZWxldG9uIChgLnNrZWxgIG9yIGAuanNvbmApIGFuZCB0aGUgYXRsYXMgdGV4dCBmaWxlcyBtdXN0IGJlIGxvYWRlZCBpbnRvIHRoZSBBc3NldHMuIEZvciBleGFtcGxlOlxuXHQgKiBgYGBcblx0ICogUElYSS5Bc3NldHMuYWRkKFwic2Fja0RhdGFcIiwgXCIvYXNzZXRzL3NhY2stcHJvLnNrZWxcIik7XG5cdCAqIFBJWEkuQXNzZXRzLmFkZChcInNhY2tBdGxhc1wiLCBcIi9hc3NldHMvc2Fjay1wbWEuYXRsYXNcIik7XG5cdCAqIGF3YWl0IFBJWEkuQXNzZXRzLmxvYWQoW1wic2Fja0RhdGFcIiwgXCJzYWNrQXRsYXNcIl0pO1xuXHQgKiBgYGBcblx0ICogT25jZSBhIFNwaW5lIGdhbWUgb2JqZWN0IGlzIGNyZWF0ZWQsIGl0cyBza2VsZXRvbiBkYXRhIGlzIGNhY2hlZCBpbnRvIHtAbGluayBTcGluZS5za2VsZXRvbkNhY2hlfSB1c2luZyB0aGUga2V5OlxuXHQgKiBgJHtza2VsZXRvbkFzc2V0TmFtZX0tJHthdGxhc0Fzc2V0TmFtZX0tJHtvcHRpb25zPy5zY2FsZSA/PyAxfWBcblx0ICpcblx0ICogQHBhcmFtIG9wdGlvbnMgLSBPcHRpb25zIHRvIGNvbmZpZ3VyZSB0aGUgU3BpbmUgZ2FtZSBvYmplY3QuIFNlZSB7QGxpbmsgU3BpbmVGcm9tT3B0aW9uc31cblx0ICogQHJldHVybnMge1NwaW5lfSBUaGUgU3BpbmUgZ2FtZSBvYmplY3QgaW5zdGFudGlhdGVkXG5cdCAqL1xuXHRwdWJsaWMgc3RhdGljIGZyb20gKG9wdGlvbnM6IFNwaW5lRnJvbU9wdGlvbnMpOiBTcGluZTtcblxuXHQvKipcblx0ICogQGRlcHJlY2F0ZWQgdXNlIHRoZSBgZnJvbShvcHRpb25zOiBTcGluZUZyb21PcHRpb25zKWAgdmVyc2lvbi5cblx0ICogVXNlIHRoaXMgbWV0aG9kIHRvIGluc3RhbnRpYXRlIGEgU3BpbmUgZ2FtZSBvYmplY3QuXG5cdCAqIEJlZm9yZSBpbnN0YW50aWF0aW5nIGEgU3BpbmUgZ2FtZSBvYmplY3QsIHRoZSBza2VsZXRvbiAoYC5za2VsYCBvciBgLmpzb25gKSBhbmQgdGhlIGF0bGFzIHRleHQgZmlsZXMgbXVzdCBiZSBsb2FkZWQgaW50byB0aGUgQXNzZXRzLiBGb3IgZXhhbXBsZTpcblx0ICogYGBgXG5cdCAqIFBJWEkuQXNzZXRzLmFkZChcInNhY2tEYXRhXCIsIFwiL2Fzc2V0cy9zYWNrLXByby5za2VsXCIpO1xuXHQgKiBQSVhJLkFzc2V0cy5hZGQoXCJzYWNrQXRsYXNcIiwgXCIvYXNzZXRzL3NhY2stcG1hLmF0bGFzXCIpO1xuXHQgKiBhd2FpdCBQSVhJLkFzc2V0cy5sb2FkKFtcInNhY2tEYXRhXCIsIFwic2Fja0F0bGFzXCJdKTtcblx0ICogYGBgXG5cdCAqIE9uY2UgYSBTcGluZSBnYW1lIG9iamVjdCBpcyBjcmVhdGVkLCBpdHMgc2tlbGV0b24gZGF0YSBpcyBjYWNoZWQgaW50byB7QGxpbmsgU3BpbmUuc2tlbGV0b25DYWNoZX0gdXNpbmcgdGhlIGtleTpcblx0ICogYCR7c2tlbGV0b25Bc3NldE5hbWV9LSR7YXRsYXNBc3NldE5hbWV9LSR7b3B0aW9ucz8uc2NhbGUgPz8gMX1gXG5cdCAqXG5cdCAqIEBwYXJhbSBza2VsZXRvbkFzc2V0TmFtZSAtIHRoZSBhc3NldCBuYW1lIGZvciB0aGUgc2tlbGV0b24gYC5za2VsYCBvciBgLmpzb25gIGZpbGUgcHJldmlvdXNseSBsb2FkZWQgaW50byB0aGUgQXNzZXRzXG5cdCAqIEBwYXJhbSBhdGxhc0Fzc2V0TmFtZSAtIHRoZSBhc3NldCBuYW1lIGZvciB0aGUgYXRsYXMgZmlsZSBwcmV2aW91c2x5IGxvYWRlZCBpbnRvIHRoZSBBc3NldHNcblx0ICogQHBhcmFtIG9wdGlvbnMgLSBPcHRpb25zIHRvIGNvbmZpZ3VyZSB0aGUgU3BpbmUgZ2FtZSBvYmplY3Rcblx0ICogQHJldHVybnMge1NwaW5lfSBUaGUgU3BpbmUgZ2FtZSBvYmplY3QgaW5zdGFudGlhdGVkXG5cdCAqL1xuXHRwdWJsaWMgc3RhdGljIGZyb20gKHNrZWxldG9uQXNzZXROYW1lOiBzdHJpbmcsIGF0bGFzQXNzZXROYW1lOiBzdHJpbmcsIG9wdGlvbnM/OiBJU3BpbmVPcHRpb25zKTogU3BpbmU7XG5cdHB1YmxpYyBzdGF0aWMgZnJvbSAoXG5cdFx0cGFyYW1PbmU6IHN0cmluZyB8IFNwaW5lRnJvbU9wdGlvbnMsXG5cdFx0YXRsYXNBc3NldE5hbWU/OiBzdHJpbmcsXG5cdFx0b3B0aW9ucz86IElTcGluZU9wdGlvbnMpXG5cdFx0OiBTcGluZSB7XG5cdFx0aWYgKHR5cGVvZiBwYXJhbU9uZSA9PT0gXCJzdHJpbmdcIikge1xuXHRcdFx0cmV0dXJuIFNwaW5lLm9sZEZyb20ocGFyYW1PbmUsIGF0bGFzQXNzZXROYW1lISwgb3B0aW9ucyk7XG5cdFx0fVxuXG5cdFx0Y29uc3QgeyBza2VsZXRvbiwgYXRsYXMsIHNjYWxlID0gMSwgZGFya1RpbnQsIGF1dG9VcGRhdGUsIGJvdW5kc1Byb3ZpZGVyLCB0aWNrZXIgfSA9IHBhcmFtT25lO1xuXHRcdGNvbnN0IGNhY2hlS2V5ID0gYCR7c2tlbGV0b259LSR7YXRsYXN9LSR7c2NhbGV9YDtcblx0XHRsZXQgc2tlbGV0b25EYXRhID0gU3BpbmUuc2tlbGV0b25DYWNoZVtjYWNoZUtleV07XG5cdFx0aWYgKCFza2VsZXRvbkRhdGEpIHtcblx0XHRcdGNvbnN0IHNrZWxldG9uQXNzZXQgPSBBc3NldHMuZ2V0PGFueSB8IFVpbnQ4QXJyYXk+KHNrZWxldG9uKTtcblx0XHRcdGNvbnN0IGF0bGFzQXNzZXQgPSBBc3NldHMuZ2V0PFRleHR1cmVBdGxhcz4oYXRsYXMpO1xuXHRcdFx0Y29uc3QgYXR0YWNobWVudExvYWRlciA9IG5ldyBBdGxhc0F0dGFjaG1lbnRMb2FkZXIoYXRsYXNBc3NldCk7XG5cdFx0XHRsZXQgcGFyc2VyID0gc2tlbGV0b25Bc3NldCBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkgPyBuZXcgU2tlbGV0b25CaW5hcnkoYXR0YWNobWVudExvYWRlcikgOiBuZXcgU2tlbGV0b25Kc29uKGF0dGFjaG1lbnRMb2FkZXIpO1xuXHRcdFx0cGFyc2VyLnNjYWxlID0gc2NhbGU7XG5cdFx0XHRza2VsZXRvbkRhdGEgPSBwYXJzZXIucmVhZFNrZWxldG9uRGF0YShza2VsZXRvbkFzc2V0KTtcblx0XHRcdFNwaW5lLnNrZWxldG9uQ2FjaGVbY2FjaGVLZXldID0gc2tlbGV0b25EYXRhO1xuXHRcdH1cblx0XHRyZXR1cm4gbmV3IFNwaW5lKHsgc2tlbGV0b25EYXRhLCBkYXJrVGludCwgYXV0b1VwZGF0ZSwgYm91bmRzUHJvdmlkZXIsIHRpY2tlciB9KTtcblx0fVxuXG5cblx0cHJpdmF0ZSBzdGF0aWMgb2xkRnJvbSAoc2tlbGV0b25Bc3NldE5hbWU6IHN0cmluZywgYXRsYXNBc3NldE5hbWU6IHN0cmluZywgb3B0aW9ucz86IElTcGluZU9wdGlvbnMpOiBTcGluZSB7XG5cdFx0Y29uc3QgY2FjaGVLZXkgPSBgJHtza2VsZXRvbkFzc2V0TmFtZX0tJHthdGxhc0Fzc2V0TmFtZX0tJHtvcHRpb25zPy5zY2FsZSA/PyAxfWA7XG5cdFx0bGV0IHNrZWxldG9uRGF0YSA9IFNwaW5lLnNrZWxldG9uQ2FjaGVbY2FjaGVLZXldO1xuXHRcdGlmIChza2VsZXRvbkRhdGEpIHtcblx0XHRcdHJldHVybiBuZXcgU3BpbmUoc2tlbGV0b25EYXRhLCBvcHRpb25zKTtcblx0XHR9XG5cdFx0Y29uc3Qgc2tlbGV0b25Bc3NldCA9IEFzc2V0cy5nZXQ8YW55IHwgVWludDhBcnJheT4oc2tlbGV0b25Bc3NldE5hbWUpO1xuXHRcdGNvbnN0IGF0bGFzQXNzZXQgPSBBc3NldHMuZ2V0PFRleHR1cmVBdGxhcz4oYXRsYXNBc3NldE5hbWUpO1xuXHRcdGNvbnN0IGF0dGFjaG1lbnRMb2FkZXIgPSBuZXcgQXRsYXNBdHRhY2htZW50TG9hZGVyKGF0bGFzQXNzZXQpO1xuXHRcdGxldCBwYXJzZXIgPSBza2VsZXRvbkFzc2V0IGluc3RhbmNlb2YgVWludDhBcnJheSA/IG5ldyBTa2VsZXRvbkJpbmFyeShhdHRhY2htZW50TG9hZGVyKSA6IG5ldyBTa2VsZXRvbkpzb24oYXR0YWNobWVudExvYWRlcik7XG5cdFx0cGFyc2VyLnNjYWxlID0gb3B0aW9ucz8uc2NhbGUgPz8gMTtcblx0XHRza2VsZXRvbkRhdGEgPSBwYXJzZXIucmVhZFNrZWxldG9uRGF0YShza2VsZXRvbkFzc2V0KTtcblx0XHRTcGluZS5za2VsZXRvbkNhY2hlW2NhY2hlS2V5XSA9IHNrZWxldG9uRGF0YTtcblx0XHRyZXR1cm4gbmV3IHRoaXMoc2tlbGV0b25EYXRhLCBvcHRpb25zKTtcblx0fVxuXG5cdHB1YmxpYyBnZXQgdGludCAoKTogbnVtYmVyIHtcblx0XHRyZXR1cm4gdGhpcy5za2VsZXRvbi5jb2xvci50b1JnYjg4OCgpO1xuXHR9XG5cdHB1YmxpYyBzZXQgdGludCAodmFsdWU6IG51bWJlcikge1xuXHRcdENvbG9yLnJnYjg4OFRvQ29sb3IodGhpcy5za2VsZXRvbi5jb2xvciwgdmFsdWUpO1xuXHR9XG59XG5cbmludGVyZmFjZSBTbG90c1RvQ2xpcHBpbmcge1xuXHRzbG90OiBTbG90LFxuXHRtYXNrPzogR3JhcGhpY3MsXG5cdG1hc2tDb21wdXRlZD86IGJvb2xlYW4sXG5cdHZlcnRpY2VzOiBBcnJheTxudW1iZXI+LFxufTtcblxuY29uc3QgbWFza1Bvb2wgPSBuZXcgUG9vbDxHcmFwaGljcz4oKCkgPT4gbmV3IEdyYXBoaWNzKTtcblxuU2tlbGV0b24ueURvd24gPSB0cnVlO1xuXG4vKipcbiAqIFJlcHJlc2VudHMgdGhlIG1lc2ggdHlwZSB1c2VkIGluIGEgU3BpbmUgb2JqZWN0cy4gQXZhaWxhYmxlIGltcGxlbWVudGF0aW9ucyBhcmUge0BsaW5rIERhcmtTbG90TWVzaH0gYW5kIHtAbGluayBTbG90TWVzaH0uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSVNsb3RNZXNoIGV4dGVuZHMgRGlzcGxheU9iamVjdCB7XG5cdG5hbWU6IHN0cmluZztcblx0dXBkYXRlRnJvbVNwaW5lRGF0YSAoXG5cdFx0c2xvdFRleHR1cmU6IFNwaW5lVGV4dHVyZSxcblx0XHRzbG90QmxlbmRNb2RlOiBCbGVuZE1vZGUsXG5cdFx0c2xvdE5hbWU6IHN0cmluZyxcblx0XHRmaW5hbFZlcnRpY2VzOiBOdW1iZXJBcnJheUxpa2UsXG5cdFx0ZmluYWxWZXJ0aWNlc0xlbmd0aDogbnVtYmVyLFxuXHRcdGZpbmFsSW5kaWNlczogTnVtYmVyQXJyYXlMaWtlLFxuXHRcdGZpbmFsSW5kaWNlc0xlbmd0aDogbnVtYmVyLFxuXHRcdGRhcmtUaW50OiBib29sZWFuXG5cdCk6IHZvaWQ7XG59XG4iXX0=
|