UNPKG

@esotericsoftware/spine-canvaskit

Version:

The official Spine Runtimes for CanvasKit for NodeJS

204 lines 29.4 kB
/****************************************************************************** * 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