@esotericsoftware/spine-canvaskit
Version:
The official Spine Runtimes for CanvasKit for NodeJS
204 lines • 29.4 kB
JavaScript
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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.
*****************************************************************************/
export * from "@esotericsoftware/spine-core";
import { AnimationState, AnimationStateData, AtlasAttachmentLoader, BlendMode, Physics, Skeleton, SkeletonBinary, SkeletonJson, SkeletonRendererCore, Texture, TextureAtlas, } from "@esotericsoftware/spine-core";
Skeleton.yDown = true;
// CanvasKit blend modes for premultiplied alpha
function toCkBlendMode(ck, blendMode) {
switch (blendMode) {
case BlendMode.Normal:
return ck.BlendMode.SrcOver;
case BlendMode.Additive:
return ck.BlendMode.Plus;
case BlendMode.Multiply:
return ck.BlendMode.SrcOver;
case BlendMode.Screen:
return ck.BlendMode.Screen;
default:
return ck.BlendMode.SrcOver;
}
}
function binaryDataToUint8Array(buffer) {
if (buffer instanceof ArrayBuffer)
return new Uint8Array(buffer);
if (buffer instanceof Uint8Array)
return buffer;
return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
}
function bufferToUtf8String(buffer) {
const globalBuffer = globalThis.Buffer;
if (globalBuffer?.isBuffer(buffer)) {
return buffer.toString("utf-8");
}
else if (typeof TextDecoder !== "undefined") {
return new TextDecoder("utf-8").decode(binaryDataToUint8Array(buffer));
}
else {
throw new Error("Unsupported environment");
}
}
class CanvasKitTexture extends Texture {
getImage() {
return this._image;
}
setFilters() { }
setWraps() { }
dispose() {
const data = this._image;
for (const paint of data.paintPerBlendMode.values()) {
paint.delete();
}
for (const shader of data.shaders) {
shader.delete();
}
data.image.delete();
this._image = null;
}
static async fromFile(ck, path, readFile) {
const imgData = await readFile(path);
if (!imgData)
throw new Error(`Could not load image ${path}`);
const image = ck.MakeImageFromEncoded(binaryDataToUint8Array(imgData));
if (!image)
throw new Error(`Could not load image ${path}`);
const paintPerBlendMode = new Map();
const shaders = [];
for (const blendMode of [
BlendMode.Normal,
BlendMode.Additive,
BlendMode.Multiply,
BlendMode.Screen,
]) {
const paint = new ck.Paint();
const shader = image.makeShaderOptions(ck.TileMode.Clamp, ck.TileMode.Clamp, ck.FilterMode.Linear, ck.MipmapMode.Linear);
paint.setShader(shader);
paint.setBlendMode(toCkBlendMode(ck, blendMode));
paintPerBlendMode.set(blendMode, paint);
shaders.push(shader);
}
return new CanvasKitTexture({ shaders, paintPerBlendMode, image });
}
}
/**
* Loads a {@link TextureAtlas} and its atlas page images from the given file path using the `readFile(path: string): Promise<Buffer>` function.
* Throws an `Error` if the file or one of the atlas page images could not be loaded.
*/
export async function loadTextureAtlas(ck, atlasFile, readFile) {
const atlas = new TextureAtlas(bufferToUtf8String(await readFile(atlasFile)));
const slashIndex = atlasFile.lastIndexOf("/");
const parentDir = slashIndex >= 0 ? atlasFile.substring(0, slashIndex + 1) : "";
for (const page of atlas.pages) {
const texture = await CanvasKitTexture.fromFile(ck, parentDir + page.name, readFile);
page.setTexture(texture);
}
return atlas;
}
/**
* Loads a {@link SkeletonData} from the given file path (`.json` or `.skel`) using the `readFile(path: string): Promise<Buffer>` function.
* Attachments will be looked up in the provided atlas.
*/
export async function loadSkeletonData(skeletonFile, atlas, readFile, scale = 1) {
const attachmentLoader = new AtlasAttachmentLoader(atlas);
const loader = skeletonFile.endsWith(".json")
? new SkeletonJson(attachmentLoader)
: new SkeletonBinary(attachmentLoader);
loader.scale = scale;
const data = await readFile(skeletonFile);
if (loader instanceof SkeletonJson) {
return loader.readSkeletonData(bufferToUtf8String(data));
}
return loader.readSkeletonData(binaryDataToUint8Array(data));
}
/**
* Manages a {@link Skeleton} and its associated {@link AnimationState}. A drawable is constructed from a {@link SkeletonData}, which can
* be shared by any number of drawables.
*/
export class SkeletonDrawable {
skeleton;
animationState;
/**
* Constructs a new drawble from the skeleton data.
*/
constructor(skeletonData) {
this.skeleton = new Skeleton(skeletonData);
this.animationState = new AnimationState(new AnimationStateData(skeletonData));
}
/**
* Updates the animation state and skeleton time by the delta time. Applies the
* animations to the skeleton and calculates the final pose of the skeleton.
*
* @param deltaTime the time since the last update in seconds
* @param physicsUpdate optional {@link Physics} update mode.
*/
update(deltaTime, physicsUpdate = Physics.update) {
this.animationState.update(deltaTime);
this.skeleton.update(deltaTime);
this.animationState.apply(this.skeleton);
this.skeleton.updateWorldTransform(physicsUpdate);
}
}
/**
* Renders a {@link Skeleton} or {@link SkeletonDrawable} to a CanvasKit {@link Canvas}.
*/
export class SkeletonRenderer {
ck;
skeletonRenderer = new SkeletonRendererCore();
/**
* Creates a new skeleton renderer.
* @param ck the {@link CanvasKit} instance returned by `CanvasKitInit()`.
*/
constructor(ck) {
this.ck = ck;
}
render(canvas, skeleton) {
if (skeleton instanceof SkeletonDrawable)
skeleton = skeleton.skeleton;
let command = this.skeletonRenderer.render(skeleton);
while (command) {
const { positions, uvs, colors, indices } = command;
const ckImage = command.texture.getImage();
const image = ckImage.image;
const width = image.width();
const height = image.height();
for (let i = 0; i < uvs.length; i += 2) {
uvs[i] = uvs[i] * width;
uvs[i + 1] = uvs[i + 1] * height;
}
const vertices = this.ck.MakeVertices(this.ck.VertexMode.Triangles, positions, uvs, colors,
// biome-ignore lint/suspicious/noExplicitAny: canvaskit wants indices as an array of number
indices, false);
const ckPaint = ckImage.paintPerBlendMode.get(command.blendMode);
if (ckPaint)
canvas.drawVertices(vertices, this.ck.BlendMode.Modulate, ckPaint);
vertices.delete();
command = command.next;
}
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsrRUEyQitFO0FBRS9FLGNBQWMsOEJBQThCLENBQUM7QUFFN0MsT0FBTyxFQUNOLGNBQWMsRUFDZCxrQkFBa0IsRUFDbEIscUJBQXFCLEVBQ3JCLFNBQVMsRUFDVCxPQUFPLEVBQ1AsUUFBUSxFQUNSLGNBQWMsRUFFZCxZQUFZLEVBQ1osb0JBQW9CLEVBQ3BCLE9BQU8sRUFDUCxZQUFZLEdBQ1osTUFBTSw4QkFBOEIsQ0FBQztBQUl0QyxRQUFRLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQztBQVF0QixnREFBZ0Q7QUFDaEQsU0FBUyxhQUFhLENBQUUsRUFBYSxFQUFFLFNBQW9CO0lBQzFELFFBQVEsU0FBUyxFQUFFLENBQUM7UUFDbkIsS0FBSyxTQUFTLENBQUMsTUFBTTtZQUNwQixPQUFPLEVBQUUsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDO1FBQzdCLEtBQUssU0FBUyxDQUFDLFFBQVE7WUFDdEIsT0FBTyxFQUFFLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQztRQUMxQixLQUFLLFNBQVMsQ0FBQyxRQUFRO1lBQ3RCLE9BQU8sRUFBRSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUM7UUFDN0IsS0FBSyxTQUFTLENBQUMsTUFBTTtZQUNwQixPQUFPLEVBQUUsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDO1FBQzVCO1lBQ0MsT0FBTyxFQUFFLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQztJQUM5QixDQUFDO0FBQ0YsQ0FBQztBQVdELFNBQVMsc0JBQXNCLENBQUUsTUFBa0I7SUFDbEQsSUFBSSxNQUFNLFlBQVksV0FBVztRQUFFLE9BQU8sSUFBSSxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDakUsSUFBSSxNQUFNLFlBQVksVUFBVTtRQUFFLE9BQU8sTUFBTSxDQUFD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QUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDO1lBQ2xDLENBQUM7WUFFRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FDcEMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsU0FBUyxFQUM1QixTQUFTLEVBQ1QsR0FBRyxFQUNILE1BQU07WUFDTiw0RkFBNEY7WUFDNUYsT0FBMEIsRUFDMUIsS0FBSyxDQUNMLENBQUM7WUFDRixNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUNqRSxJQUFJLE9BQU87Z0JBQUUsTUFBTSxDQUFDLFlBQVksQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBQ2hGLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNsQixPQUFPLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQztRQUN4QixDQUFDO0lBQ0YsQ0FBQztDQUVEIiwic291cmNlc0NvbnRlbnQiOlsiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuICogU3BpbmUgUnVudGltZXMgTGljZW5zZSBBZ3JlZW1lbnRcbiAqIExhc3QgdXBkYXRlZCBKdWx5IDI4LCAyMDIzLiBSZXBsYWNlcyBhbGwgcHJpb3IgdmVyc2lvbnMuXG4gKlxuICogQ29weXJpZ2h0IChjKSAyMDEzLTIwMjMsIEVzb3RlcmljIFNvZnR3YXJlIExMQ1xuICpcbiAqIEludGVncmF0aW9uIG9mIHRoZSBTcGluZSBSdW50aW1lcyBpbnRvIHNvZnR3YXJlIG9yIG90aGVyd2lzZSBjcmVhdGluZ1xuICogZGVyaXZhdGl2ZSB3b3JrcyBvZiB0aGUgU3BpbmUgUnVudGltZXMgaXMgcGVybWl0dGVkIHVuZGVyIHRoZSB0ZXJtcyBhbmRcbiAqIGNvbmRpdGlvbnMgb2YgU2VjdGlvbiAyIG9mIHRoZSBTcGluZSBFZGl0b3IgTGljZW5zZSBBZ3JlZW1lbnQ6XG4gKiBodHRwOi8vZXNvdGVyaWNzb2Z0d2FyZS5jb20vc3BpbmUtZWRpdG9yLWxpY2Vuc2VcbiAqXG4gKiBPdGhlcndpc2UsIGl0IGlzIHBlcm1pdHRlZCB0byBpbnRlZ3JhdGUgdGhlIFNwaW5lIFJ1bnRpbWVzIGludG8gc29mdHdhcmUgb3JcbiAqIG90aGVyd2lzZSBjcmVhdGUgZGVyaXZhdGl2ZSB3b3JrcyBvZiB0aGUgU3BpbmUgUnVudGltZXMgKGNvbGxlY3RpdmVseSxcbiAqIFwiUHJvZHVjdHNcIiksIHByb3ZpZGVkIHRoYXQgZWFjaCB1c2VyIG9mIHRoZSBQcm9kdWN0cyBtdXN0IG9idGFpbiB0aGVpciBvd25cbiAqIFNwaW5lIEVkaXRvciBsaWNlbnNlIGFuZCByZWRpc3RyaWJ1dGlvbiBvZiB0aGUgUHJvZHVjdHMgaW4gYW55IGZvcm0gbXVzdFxuICogaW5jbHVkZSB0aGlzIGxpY2Vuc2UgYW5kIGNvcHlyaWdodCBub3RpY2UuXG4gKlxuICogVEhFIFNQSU5FIFJVTlRJTUVTIEFSRSBQUk9WSURFRCBCWSBFU09URVJJQyBTT0ZUV0FSRSBMTEMgXCJBUyBJU1wiIEFORCBBTllcbiAqIEVYUFJFU1MgT1IgSU1QTElFRCBXQVJSQU5USUVTLCBJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgVEhFIElNUExJRURcbiAqIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZIEFORCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBUkVcbiAqIERJU0NMQUlNRUQuIElOIE5PIEVWRU5UIFNIQUxMIEVTT1RFUklDIFNPRlRXQVJFIExMQyBCRSBMSUFCTEUgRk9SIEFOWVxuICogRElSRUNULCBJTkRJUkVDVCwgSU5DSURFTlRBTCwgU1BFQ0lBTCwgRVhFTVBMQVJZLCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVNcbiAqIChJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgUFJPQ1VSRU1FTlQgT0YgU1VCU1RJVFVURSBHT09EUyBPUiBTRVJWSUNFUyxcbiAqIEJVU0lORVNTIElOVEVSUlVQVElPTiwgT1IgTE9TUyBPRiBVU0UsIERBVEEsIE9SIFBST0ZJVFMpIEhPV0VWRVIgQ0FVU0VEIEFORFxuICogT04gQU5ZIFRIRU9SWSBPRiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQ09OVFJBQ1QsIFNUUklDVCBMSUFCSUxJVFksIE9SIFRPUlRcbiAqIChJTkNMVURJTkcgTkVHTElHRU5DRSBPUiBPVEhFUldJU0UpIEFSSVNJTkcgSU4gQU5ZIFdBWSBPVVQgT0YgVEhFIFVTRSBPRiBUSEVcbiAqIFNQSU5FIFJVTlRJTUVTLCBFVkVOIElGIEFEVklTRUQgT0YgVEhFIFBPU1NJQklMSVRZIE9GIFNVQ0ggREFNQUdFLlxuICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5leHBvcnQgKiBmcm9tIFwiQGVzb3Rlcmljc29mdHdhcmUvc3BpbmUtY29yZVwiO1xuXG5pbXBvcnQge1xuXHRBbmltYXRpb25TdGF0ZSxcblx0QW5pbWF0aW9uU3RhdGVEYXRhLFxuXHRBdGxhc0F0dGFjaG1lbnRMb2FkZXIsXG5cdEJsZW5kTW9kZSxcblx0UGh5c2ljcyxcblx0U2tlbGV0b24sXG5cdFNrZWxldG9uQmluYXJ5LFxuXHR0eXBlIFNrZWxldG9uRGF0YSxcblx0U2tlbGV0b25Kc29uLFxuXHRTa2VsZXRvblJlbmRlcmVyQ29yZSxcblx0VGV4dHVyZSxcblx0VGV4dHVyZUF0bGFzLFxufSBmcm9tIFwiQGVzb3Rlcmljc29mdHdhcmUvc3BpbmUtY29yZVwiO1xuXG5pbXBvcnQgdHlwZSB7IENhbnZhcywgQ2FudmFzS2l0LCBJbWFnZSwgUGFpbnQsIFNoYWRlciB9IGZyb20gXCJjYW52YXNraXQtd2FzbVwiO1xuXG5Ta2VsZXRvbi55RG93biA9IHRydWU7XG5cbnR5cGUgQ2FudmFzS2l0SW1hZ2UgPSB7XG5cdHNoYWRlcnM6IFNoYWRlcltdO1xuXHRwYWludFBlckJsZW5kTW9kZTogTWFwPEJsZW5kTW9kZSwgUGFpbnQ+O1xuXHRpbWFnZTogSW1hZ2U7XG59O1xuXG4vLyBDYW52YXNLaXQgYmxlbmQgbW9kZXMgZm9yIHByZW11bHRpcGxpZWQgYWxwaGFcbmZ1bmN0aW9uIHRvQ2tCbGVuZE1vZGUgKGNrOiBDYW52YXNLaXQsIGJsZW5kTW9kZTogQmxlbmRNb2RlKSB7XG5cdHN3aXRjaCAoYmxlbmRNb2RlKSB7XG5cdFx0Y2FzZSBCbGVuZE1vZGUuTm9ybWFsOlxuXHRcdFx0cmV0dXJuIGNrLkJsZW5kTW9kZS5TcmNPdmVyO1xuXHRcdGNhc2UgQmxlbmRNb2RlLkFkZGl0aXZlOlxuXHRcdFx0cmV0dXJuIGNrLkJsZW5kTW9kZS5QbHVzO1xuXHRcdGNhc2UgQmxlbmRNb2RlLk11bHRpcGx5OlxuXHRcdFx0cmV0dXJuIGNrLkJsZW5kTW9kZS5TcmNPdmVyO1xuXHRcdGNhc2UgQmxlbmRNb2RlLlNjcmVlbjpcblx0XHRcdHJldHVybiBjay5CbGVuZE1vZGUuU2NyZWVuO1xuXHRcdGRlZmF1bHQ6XG5cdFx0XHRyZXR1cm4gY2suQmxlbmRNb2RlLlNyY092ZXI7XG5cdH1cbn1cblxudHlwZSBOb2RlQnVmZmVyTGlrZSA9IHtcblx0cmVhZG9ubHkgYnVmZmVyOiBBcnJheUJ1ZmZlckxpa2U7XG5cdHJlYWRvbmx5IGJ5dGVPZmZzZXQ6IG51bWJlcjtcblx0cmVhZG9ubHkgYnl0ZUxlbmd0aDogbnVtYmVyO1xuXHR0b1N0cmluZyAoZW5jb2Rpbmc/OiBcInV0Zi04XCIgfCBcInV0ZjhcIik6IHN0cmluZztcbn07XG5cbnR5cGUgQmluYXJ5RGF0YSA9IEFycmF5QnVmZmVyIHwgVWludDhBcnJheSB8IE5vZGVCdWZmZXJMaWtlO1xuXG5mdW5jdGlvbiBiaW5hcnlEYXRhVG9VaW50OEFycmF5IChidWZmZXI6IEJpbmFyeURhdGEpOiBVaW50OEFycmF5IHtcblx0aWYgKGJ1ZmZlciBpbnN0YW5jZW9mIEFycmF5QnVmZmVyKSByZXR1cm4gbmV3IFVpbnQ4QXJyYXkoYnVmZmVyKTtcblx0aWYgKGJ1ZmZlciBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpIHJldHVybiBidWZmZXI7XG5cdHJldHVybiBuZXcgVWludDhBcnJheShidWZmZXIuYnVmZmVyLCBidWZmZXIuYnl0ZU9mZnNldCwgYnVmZmVyLmJ5dGVMZW5ndGgpO1xufVxuXG5mdW5jdGlvbiBidWZmZXJUb1V0ZjhTdHJpbmcgKGJ1ZmZlcjogQmluYXJ5RGF0YSkge1xuXHRjb25zdCBnbG9iYWxCdWZmZXIgPSAoZ2xvYmFsVGhpcyBhcyB7IEJ1ZmZlcj86IHsgaXNCdWZmZXI6ICh2YWx1ZTogdW5rbm93bikgPT4gYm9vbGVhbiB9IH0pLkJ1ZmZlcjtcblx0aWYgKGdsb2JhbEJ1ZmZlcj8uaXNCdWZmZXIoYnVmZmVyKSkge1xuXHRcdHJldHVybiBidWZmZXIudG9TdHJpbmcoXCJ1dGYtOFwiKTtcblx0fSBlbHNlIGlmICh0eXBlb2YgVGV4dERlY29kZXIgIT09IFwidW5kZWZpbmVkXCIpIHtcblx0XHRyZXR1cm4gbmV3IFRleHREZWNvZGVyKFwidXRmLThcIikuZGVjb2RlKGJpbmFyeURhdGFUb1VpbnQ4QXJyYXkoYnVmZmVyKSk7XG5cdH0gZWxzZSB7XG5cdFx0dGhyb3cgbmV3IEVycm9yKFwiVW5zdXBwb3J0ZWQgZW52aXJvbm1lbnRcIik7XG5cdH1cbn1cblxuY2xhc3MgQ2FudmFzS2l0VGV4dHVyZSBleHRlbmRzIFRleHR1cmUge1xuXHRnZXRJbWFnZSAoKTogQ2FudmFzS2l0SW1hZ2Uge1xuXHRcdHJldHVybiB0aGlzLl9pbWFnZTtcblx0fVxuXG5cdHNldEZpbHRlcnMgKCk6IHZvaWQgeyB9XG5cblx0c2V0V3JhcHMgKCk6IHZvaWQgeyB9XG5cblx0ZGlzcG9zZSAoKTogdm9pZCB7XG5cdFx0Y29uc3QgZGF0YTogQ2FudmFzS2l0SW1hZ2UgPSB0aGlzLl9pbWFnZTtcblx0XHRmb3IgKGNvbnN0IHBhaW50IG9mIGRhdGEucGFpbnRQZXJCbGVuZE1vZGUudmFsdWVzKCkpIHtcblx0XHRcdHBhaW50LmRlbGV0ZSgpO1xuXHRcdH1cblx0XHRmb3IgKGNvbnN0IHNoYWRlciBvZiBkYXRhLnNoYWRlcnMpIHtcblx0XHRcdHNoYWRlci5kZWxldGUoKTtcblx0XHR9XG5cdFx0ZGF0YS5pbWFnZS5kZWxldGUoKTtcblx0XHR0aGlzLl9pbWFnZSA9IG51bGw7XG5cdH1cblxuXHRzdGF0aWMgYXN5bmMgZnJvbUZpbGUgKFxuXHRcdGNrOiBDYW52YXNLaXQsXG5cdFx0cGF0aDogc3RyaW5nLFxuXHRcdHJlYWRGaWxlOiAocGF0aDogc3RyaW5nKSA9PiBQcm9taXNlPEJpbmFyeURhdGE+XG5cdCk6IFByb21pc2U8Q2FudmFzS2l0VGV4dHVyZT4ge1xuXHRcdGNvbnN0IGltZ0RhdGEgPSBhd2FpdCByZWFkRmlsZShwYXRoKTtcblx0XHRpZiAoIWltZ0RhdGEpIHRocm93IG5ldyBFcnJvcihgQ291bGQgbm90IGxvYWQgaW1hZ2UgJHtwYXRofWApO1xuXHRcdGNvbnN0IGltYWdlID0gY2suTWFrZUltYWdlRnJvbUVuY29kZWQoYmluYXJ5RGF0YVRvVWludDhBcnJheShpbWdEYXRhKSk7XG5cdFx0aWYgKCFpbWFnZSkgdGhyb3cgbmV3IEVycm9yKGBDb3VsZCBub3QgbG9hZCBpbWFnZSAke3BhdGh9YCk7XG5cdFx0Y29uc3QgcGFpbnRQZXJCbGVuZE1vZGUgPSBuZXcgTWFwPEJsZW5kTW9kZSwgUGFpbnQ+KCk7XG5cdFx0Y29uc3Qgc2hhZGVyczogU2hhZGVyW10gPSBbXTtcblx0XHRmb3IgKGNvbnN0IGJsZW5kTW9kZSBvZiBbXG5cdFx0XHRCbGVuZE1vZGUuTm9ybWFsLFxuXHRcdFx0QmxlbmRNb2RlLkFkZGl0aXZlLFxuXHRcdFx0QmxlbmRNb2RlLk11bHRpcGx5LFxuXHRcdFx0QmxlbmRNb2RlLlNjcmVlbixcblx0XHRdKSB7XG5cdFx0XHRjb25zdCBwYWludCA9IG5ldyBjay5QYWludCgpO1xuXHRcdFx0Y29uc3Qgc2hhZGVyID0gaW1hZ2UubWFrZVNoYWRlck9wdGlvbnMoXG5cdFx0XHRcdGNrLlRpbGVNb2RlLkNsYW1wLFxuXHRcdFx0XHRjay5UaWxlTW9kZS5DbGFtcCxcblx0XHRcdFx0Y2suRmlsdGVyTW9kZS5MaW5lYXIsXG5cdFx0XHRcdGNrLk1pcG1hcE1vZGUuTGluZWFyXG5cdFx0XHQpO1xuXHRcdFx0cGFpbnQuc2V0U2hhZGVyKHNoYWRlcik7XG5cdFx0XHRwYWludC5zZXRCbGVuZE1vZGUodG9Da0JsZW5kTW9kZShjaywgYmxlbmRNb2RlKSk7XG5cdFx0XHRwYWludFBlckJsZW5kTW9kZS5zZXQoYmxlbmRNb2RlLCBwYWludCk7XG5cdFx0XHRzaGFkZXJzLnB1c2goc2hhZGVyKTtcblx0XHR9XG5cdFx0cmV0dXJuIG5ldyBDYW52YXNLaXRUZXh0dXJlKHsgc2hhZGVycywgcGFpbnRQZXJCbGVuZE1vZGUsIGltYWdlIH0pO1xuXHR9XG59XG5cbi8qKlxuICogTG9hZHMgYSB7QGxpbmsgVGV4dHVyZUF0bGFzfSBhbmQgaXRzIGF0bGFzIHBhZ2UgaW1hZ2VzIGZyb20gdGhlIGdpdmVuIGZpbGUgcGF0aCB1c2luZyB0aGUgYHJlYWRGaWxlKHBhdGg6IHN0cmluZyk6IFByb21pc2U8QnVmZmVyPmAgZnVuY3Rpb24uXG4gKiBUaHJvd3MgYW4gYEVycm9yYCBpZiB0aGUgZmlsZSBvciBvbmUgb2YgdGhlIGF0bGFzIHBhZ2UgaW1hZ2VzIGNvdWxkIG5vdCBiZSBsb2FkZWQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsb2FkVGV4dHVyZUF0bGFzIChcblx0Y2s6IENhbnZhc0tpdCxcblx0YXRsYXNGaWxlOiBzdHJpbmcsXG5cdHJlYWRGaWxlOiAocGF0aDogc3RyaW5nKSA9PiBQcm9taXNlPEJpbmFyeURhdGE+XG4pOiBQcm9taXNlPFRleHR1cmVBdGxhcz4ge1xuXHRjb25zdCBhdGxhcyA9IG5ldyBUZXh0dXJlQXRsYXMoYnVmZmVyVG9VdGY4U3RyaW5nKGF3YWl0IHJlYWRGaWxlKGF0bGFzRmlsZSkpKTtcblx0Y29uc3Qgc2xhc2hJbmRleCA9IGF0bGFzRmlsZS5sYXN0SW5kZXhPZihcIi9cIik7XG5cdGNvbnN0IHBhcmVudERpciA9XG5cdFx0c2xhc2hJbmRleCA+PSAwID8gYXRsYXNGaWxlLnN1YnN0cmluZygwLCBzbGFzaEluZGV4ICsgMSkgOiBcIlwiO1xuXHRmb3IgKGNvbnN0IHBhZ2Ugb2YgYXRsYXMucGFnZXMpIHtcblx0XHRjb25zdCB0ZXh0dXJlID0gYXdhaXQgQ2FudmFzS2l0VGV4dHVyZS5mcm9tRmlsZShcblx0XHRcdGNrLFxuXHRcdFx0cGFyZW50RGlyICsgcGFnZS5uYW1lLFxuXHRcdFx0cmVhZEZpbGVcblx0XHQpO1xuXHRcdHBhZ2Uuc2V0VGV4dHVyZSh0ZXh0dXJlKTtcblx0fVxuXHRyZXR1cm4gYXRsYXM7XG59XG5cbi8qKlxuICogTG9hZHMgYSB7QGxpbmsgU2tlbGV0b25EYXRhfcKgZnJvbSB0aGUgZ2l2ZW4gZmlsZSBwYXRoIChgLmpzb25gIG9yIGAuc2tlbGApIHVzaW5nIHRoZSBgcmVhZEZpbGUocGF0aDogc3RyaW5nKTogUHJvbWlzZTxCdWZmZXI+YCBmdW5jdGlvbi5cbiAqIEF0dGFjaG1lbnRzIHdpbGwgYmUgbG9va2VkIHVwIGluIHRoZSBwcm92aWRlZCBhdGxhcy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGxvYWRTa2VsZXRvbkRhdGEgKFxuXHRza2VsZXRvbkZpbGU6IHN0cmluZyxcblx0YXRsYXM6IFRleHR1cmVBdGxhcyxcblx0cmVhZEZpbGU6IChwYXRoOiBzdHJpbmcpID0+IFByb21pc2U8QmluYXJ5RGF0YT4sXG5cdHNjYWxlID0gMVxuKTogUHJvbWlzZTxTa2VsZXRvbkRhdGE+IHtcblx0Y29uc3QgYXR0YWNobWVudExvYWRlciA9IG5ldyBBdGxhc0F0dGFjaG1lbnRMb2FkZXIoYXRsYXMpO1xuXHRjb25zdCBsb2FkZXIgPSBza2VsZXRvbkZpbGUuZW5kc1dpdGgoXCIuanNvblwiKVxuXHRcdD8gbmV3IFNrZWxldG9uSnNvbihhdHRhY2htZW50TG9hZGVyKVxuXHRcdDogbmV3IFNrZWxldG9uQmluYXJ5KGF0dGFjaG1lbnRMb2FkZXIpO1xuXHRsb2FkZXIuc2NhbGUgPSBzY2FsZTtcblx0Y29uc3QgZGF0YSA9IGF3YWl0IHJlYWRGaWxlKHNrZWxldG9uRmlsZSk7XG5cdGlmIChsb2FkZXIgaW5zdGFuY2VvZiBTa2VsZXRvbkpzb24pIHtcblx0XHRyZXR1cm4gbG9hZGVyLnJlYWRTa2VsZXRvbkRhdGEoYnVmZmVyVG9VdGY4U3RyaW5nKGRhdGEpKVxuXHR9XG5cdHJldHVybiBsb2FkZXIucmVhZFNrZWxldG9uRGF0YShiaW5hcnlEYXRhVG9VaW50OEFycmF5KGRhdGEpKTtcbn1cblxuLyoqXG4gKiBNYW5hZ2VzIGEge0BsaW5rIFNrZWxldG9ufSBhbmQgaXRzIGFzc29jaWF0ZWQge0BsaW5rIEFuaW1hdGlvblN0YXRlfS4gQSBkcmF3YWJsZSBpcyBjb25zdHJ1Y3RlZCBmcm9tIGEge0BsaW5rIFNrZWxldG9uRGF0YX0sIHdoaWNoIGNhblxuICogYmUgc2hhcmVkIGJ5IGFueSBudW1iZXIgb2YgZHJhd2FibGVzLlxuICovXG5leHBvcnQgY2xhc3MgU2tlbGV0b25EcmF3YWJsZSB7XG5cdHB1YmxpYyByZWFkb25seSBza2VsZXRvbjogU2tlbGV0b247XG5cdHB1YmxpYyByZWFkb25seSBhbmltYXRpb25TdGF0ZTogQW5pbWF0aW9uU3RhdGU7XG5cblx0LyoqXG5cdCAqIENvbnN0cnVjdHMgYSBuZXcgZHJhd2JsZSBmcm9tIHRoZSBza2VsZXRvbiBkYXRhLlxuXHQgKi9cblx0Y29uc3RydWN0b3IgKHNrZWxldG9uRGF0YTogU2tlbGV0b25EYXRhKSB7XG5cdFx0dGhpcy5za2VsZXRvbiA9IG5ldyBTa2VsZXRvbihza2VsZXRvbkRhdGEpO1xuXHRcdHRoaXMuYW5pbWF0aW9uU3RhdGUgPSBuZXcgQW5pbWF0aW9uU3RhdGUoXG5cdFx0XHRuZXcgQW5pbWF0aW9uU3RhdGVEYXRhKHNrZWxldG9uRGF0YSlcblx0XHQpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFVwZGF0ZXMgdGhlIGFuaW1hdGlvbiBzdGF0ZSBhbmQgc2tlbGV0b24gdGltZSBieSB0aGUgZGVsdGEgdGltZS4gQXBwbGllcyB0aGVcblx0ICogYW5pbWF0aW9ucyB0byB0aGUgc2tlbGV0b24gYW5kIGNhbGN1bGF0ZXMgdGhlIGZpbmFsIHBvc2Ugb2YgdGhlIHNrZWxldG9uLlxuXHQgKlxuXHQgKiBAcGFyYW0gZGVsdGFUaW1lIHRoZSB0aW1lIHNpbmNlIHRoZSBsYXN0IHVwZGF0ZSBpbiBzZWNvbmRzXG5cdCAqIEBwYXJhbSBwaHlzaWNzVXBkYXRlIG9wdGlvbmFsIHtAbGluayBQaHlzaWNzfSB1cGRhdGUgbW9kZS5cblx0ICovXG5cdHVwZGF0ZSAoZGVsdGFUaW1lOiBudW1iZXIsIHBoeXNpY3NVcGRhdGU6IFBoeXNpY3MgPSBQaHlzaWNzLnVwZGF0ZSkge1xuXHRcdHRoaXMuYW5pbWF0aW9uU3RhdGUudXBkYXRlKGRlbHRhVGltZSk7XG5cdFx0dGhpcy5za2VsZXRvbi51cGRhdGUoZGVsdGFUaW1lKTtcblx0XHR0aGlzLmFuaW1hdGlvblN0YXRlLmFwcGx5KHRoaXMuc2tlbGV0b24pO1xuXHRcdHRoaXMuc2tlbGV0b24udXBkYXRlV29ybGRUcmFuc2Zvcm0ocGh5c2ljc1VwZGF0ZSk7XG5cdH1cbn1cblxuLyoqXG4gKiBSZW5kZXJzIGEge0BsaW5rIFNrZWxldG9ufSBvciB7QGxpbmsgU2tlbGV0b25EcmF3YWJsZX0gdG8gYSBDYW52YXNLaXQge0BsaW5rIENhbnZhc30uXG4gKi9cbmV4cG9ydCBjbGFzcyBTa2VsZXRvblJlbmRlcmVyIHtcblx0cHJpdmF0ZSBza2VsZXRvblJlbmRlcmVyID0gbmV3IFNrZWxldG9uUmVuZGVyZXJDb3JlKCk7XG5cblx0LyoqXG5cdCAqIENyZWF0ZXMgYSBuZXcgc2tlbGV0b24gcmVuZGVyZXIuXG5cdCAqIEBwYXJhbSBjayB0aGUge0BsaW5rIENhbnZhc0tpdH0gaW5zdGFuY2UgcmV0dXJuZWQgYnkgYENhbnZhc0tpdEluaXQoKWAuXG5cdCAqL1xuXHRjb25zdHJ1Y3RvciAocHJpdmF0ZSBjazogQ2FudmFzS2l0KSB7IH1cblxuXHRyZW5kZXIgKGNhbnZhczogQ2FudmFzLCBza2VsZXRvbjogU2tlbGV0b24gfCBTa2VsZXRvbkRyYXdhYmxlKSB7XG5cdFx0aWYgKHNrZWxldG9uIGluc3RhbmNlb2YgU2tlbGV0b25EcmF3YWJsZSkgc2tlbGV0b24gPSBza2VsZXRvbi5za2VsZXRvbjtcblx0XHRsZXQgY29tbWFuZCA9IHRoaXMuc2tlbGV0b25SZW5kZXJlci5yZW5kZXIoc2tlbGV0b24pO1xuXHRcdHdoaWxlIChjb21tYW5kKSB7XG5cdFx0XHRjb25zdCB7IHBvc2l0aW9ucywgdXZzLCBjb2xvcnMsIGluZGljZXMgfSA9IGNvbW1hbmQ7XG5cdFx0XHRjb25zdCBja0ltYWdlID0gY29tbWFuZC50ZXh0dXJlLmdldEltYWdlKCk7XG5cdFx0XHRjb25zdCBpbWFnZSA9IGNrSW1hZ2UuaW1hZ2U7XG5cdFx0XHRjb25zdCB3aWR0aCA9IGltYWdlLndpZHRoKCk7XG5cdFx0XHRjb25zdCBoZWlnaHQgPSBpbWFnZS5oZWlnaHQoKTtcblxuXHRcdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCB1dnMubGVuZ3RoOyBpICs9IDIpIHtcblx0XHRcdFx0dXZzW2ldID0gdXZzW2ldICogd2lkdGg7XG5cdFx0XHRcdHV2c1tpICsgMV0gPSB1dnNbaSArIDFdICogaGVpZ2h0O1xuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCB2ZXJ0aWNlcyA9IHRoaXMuY2suTWFrZVZlcnRpY2VzKFxuXHRcdFx0XHR0aGlzLmNrLlZlcnRleE1vZGUuVHJpYW5nbGVzLFxuXHRcdFx0XHRwb3NpdGlvbnMsXG5cdFx0XHRcdHV2cyxcblx0XHRcdFx0Y29sb3JzLFxuXHRcdFx0XHQvLyBiaW9tZS1pZ25vcmUgbGludC9zdXNwaWNpb3VzL25vRXhwbGljaXRBbnk6IGNhbnZhc2tpdCB3YW50cyBpbmRpY2VzIGFzIGFuIGFycmF5IG9mIG51bWJlclxuXHRcdFx0XHRpbmRpY2VzIGFzIGFueSBhcyBudW1iZXJbXSxcblx0XHRcdFx0ZmFsc2Vcblx0XHRcdCk7XG5cdFx0XHRjb25zdCBja1BhaW50ID0gY2tJbWFnZS5wYWludFBlckJsZW5kTW9kZS5nZXQoY29tbWFuZC5ibGVuZE1vZGUpO1xuXHRcdFx0aWYgKGNrUGFpbnQpIGNhbnZhcy5kcmF3VmVydGljZXModmVydGljZXMsIHRoaXMuY2suQmxlbmRNb2RlLk1vZHVsYXRlLCBja1BhaW50KTtcblx0XHRcdHZlcnRpY2VzLmRlbGV0ZSgpO1xuXHRcdFx0Y29tbWFuZCA9IGNvbW1hbmQubmV4dDtcblx0XHR9XG5cdH1cblxufVxuIl19