@esotericsoftware/spine-webgl
Version:
The official Spine Runtimes for the web.
113 lines • 17.3 kB
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 { AssetManager, Input, ManagedWebGLRenderingContext, SceneRenderer, TimeKeeper } from "./index.js";
/** Manages the life-cycle and WebGL context of a {@link SpineCanvasApp}. The app loads
* assets and initializes itself, then updates and renders its state at the screen refresh rate. */
export class SpineCanvas {
config;
context;
/** Tracks the current time, delta, and other time related statistics. */
time = new TimeKeeper();
/** The HTML canvas to render to. */
htmlCanvas;
/** The WebGL rendering context. */
gl;
/** The scene renderer for easy drawing of skeletons, shapes, and images. */
renderer;
/** The asset manager to load assets with. */
assetManager;
/** The input processor used to listen to mouse, touch, and keyboard events. */
input;
disposed = false;
/** Constructs a new spine canvas, rendering to the provided HTML canvas. */
constructor(canvas, config) {
this.config = config;
if (!config.pathPrefix)
config.pathPrefix = "";
if (!config.app)
config.app = {
loadAssets: () => { },
initialize: () => { },
update: () => { },
render: () => { },
error: () => { },
dispose: () => { },
};
if (!config.webglConfig)
config.webglConfig = { alpha: true };
this.htmlCanvas = canvas;
this.context = new ManagedWebGLRenderingContext(canvas, config.webglConfig);
this.renderer = new SceneRenderer(canvas, this.context);
this.gl = this.context.gl;
this.assetManager = new AssetManager(this.context, config.pathPrefix);
this.input = new Input(canvas);
if (config.app.loadAssets)
config.app.loadAssets(this);
const loop = () => {
if (this.disposed)
return;
requestAnimationFrame(loop);
this.time.update();
if (config.app.update)
config.app.update(this, this.time.delta);
if (config.app.render)
config.app.render(this);
};
const waitForAssets = () => {
if (this.disposed)
return;
if (this.assetManager.isLoadingComplete()) {
if (this.assetManager.hasErrors()) {
if (config.app.error)
config.app.error(this, this.assetManager.getErrors());
}
else {
if (config.app.initialize)
config.app.initialize(this);
loop();
}
return;
}
requestAnimationFrame(waitForAssets);
};
requestAnimationFrame(waitForAssets);
}
/** Clears the canvas with the given color. The color values are given in the range [0,1]. */
clear(r, g, b, a) {
this.gl.clearColor(r, g, b, a);
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
}
/** Disposes the app, so the update() and render() functions are no longer called. Calls the dispose() callback.*/
dispose() {
if (this.config.app.dispose)
this.config.app.dispose(this);
this.disposed = true;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU3BpbmVDYW52YXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvU3BpbmVDYW52YXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsrRUEyQitFO0FBRS9FLE9BQU8sRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLDRCQUE0QixFQUFFLGFBQWEsRUFBa0IsVUFBVSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBK0IxSDttR0FDbUc7QUFDbkcsTUFBTSxPQUFPLFdBQVc7SUFtQnlCO0lBbEJ2QyxPQUFPLENBQStCO0lBRS9DLHlFQUF5RTtJQUNoRSxJQUFJLEdBQUcsSUFBSSxVQUFVLEVBQUUsQ0FBQztJQUNqQyxvQ0FBb0M7SUFDM0IsVUFBVSxDQUFvQjtJQUN2QyxtQ0FBbUM7SUFDMUIsRUFBRSxDQUF3QjtJQUNuQyw0RUFBNEU7SUFDbkUsUUFBUSxDQUFnQjtJQUNqQyw2Q0FBNkM7SUFDcEMsWUFBWSxDQUFlO0lBQ3BDLCtFQUErRTtJQUN0RSxLQUFLLENBQVE7SUFFZCxRQUFRLEdBQUcsS0FBSyxDQUFDO0lBRXpCLDRFQUE0RTtJQUM1RSxZQUFhLE1BQXlCLEVBQVUsTUFBeUI7UUFBekIsV0FBTSxHQUFOLE1BQU0sQ0FBbUI7UUFDeEUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVO1lBQUUsTUFBTSxDQUFDLFVBQVUsR0FBRyxFQUFFLENBQUM7UUFDL0MsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHO1lBQUUsTUFBTSxDQUFDLEdBQUcsR0FBRztnQkFDN0IsVUFBVSxFQUFFLEdBQUcsRUFBRSxHQUFHLENBQUM7Z0JBQ3JCLFVBQVUsRUFBRSxHQUFHLEVBQUUsR0FBRyxDQUFDO2dCQUNyQixNQUFNLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQztnQkFDakIsTUFBTSxFQUFFLEdBQUcsRUFBRSxHQUFHLENBQUM7Z0JBQ2pCLEtBQUssRUFBRSxHQUFHLEVBQUUsR0FBRyxDQUFDO2dCQUNoQixP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QyxPQUFPO1lBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzNELElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDO0lBQ3RCLENBQUM7Q0FDRCIsInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcbiAqIFNwaW5lIFJ1bnRpbWVzIExpY2Vuc2UgQWdyZWVtZW50XG4gKiBMYXN0IHVwZGF0ZWQgQXByaWwgNSwgMjAyNS4gUmVwbGFjZXMgYWxsIHByaW9yIHZlcnNpb25zLlxuICpcbiAqIENvcHlyaWdodCAoYykgMjAxMy0yMDI1LCBFc290ZXJpYyBTb2Z0d2FyZSBMTENcbiAqXG4gKiBJbnRlZ3JhdGlvbiBvZiB0aGUgU3BpbmUgUnVudGltZXMgaW50byBzb2Z0d2FyZSBvciBvdGhlcndpc2UgY3JlYXRpbmdcbiAqIGRlcml2YXRpdmUgd29ya3Mgb2YgdGhlIFNwaW5lIFJ1bnRpbWVzIGlzIHBlcm1pdHRlZCB1bmRlciB0aGUgdGVybXMgYW5kXG4gKiBjb25kaXRpb25zIG9mIFNlY3Rpb24gMiBvZiB0aGUgU3BpbmUgRWRpdG9yIExpY2Vuc2UgQWdyZWVtZW50OlxuICogaHR0cDovL2Vzb3Rlcmljc29mdHdhcmUuY29tL3NwaW5lLWVkaXRvci1saWNlbnNlXG4gKlxuICogT3RoZXJ3aXNlLCBpdCBpcyBwZXJtaXR0ZWQgdG8gaW50ZWdyYXRlIHRoZSBTcGluZSBSdW50aW1lcyBpbnRvIHNvZnR3YXJlXG4gKiBvciBvdGhlcndpc2UgY3JlYXRlIGRlcml2YXRpdmUgd29ya3Mgb2YgdGhlIFNwaW5lIFJ1bnRpbWVzIChjb2xsZWN0aXZlbHksXG4gKiBcIlByb2R1Y3RzXCIpLCBwcm92aWRlZCB0aGF0IGVhY2ggdXNlciBvZiB0aGUgUHJvZHVjdHMgbXVzdCBvYnRhaW4gdGhlaXIgb3duXG4gKiBTcGluZSBFZGl0b3IgbGljZW5zZSBhbmQgcmVkaXN0cmlidXRpb24gb2YgdGhlIFByb2R1Y3RzIGluIGFueSBmb3JtIG11c3RcbiAqIGluY2x1ZGUgdGhpcyBsaWNlbnNlIGFuZCBjb3B5cmlnaHQgbm90aWNlLlxuICpcbiAqIFRIRSBTUElORSBSVU5USU1FUyBBUkUgUFJPVklERUQgQlkgRVNPVEVSSUMgU09GVFdBUkUgTExDIFwiQVMgSVNcIiBBTkQgQU5ZXG4gKiBFWFBSRVNTIE9SIElNUExJRUQgV0FSUkFOVElFUywgSU5DTFVESU5HLCBCVVQgTk9UIExJTUlURUQgVE8sIFRIRSBJTVBMSUVEXG4gKiBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSBBTkQgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQVJFXG4gKiBESVNDTEFJTUVELiBJTiBOTyBFVkVOVCBTSEFMTCBFU09URVJJQyBTT0ZUV0FSRSBMTEMgQkUgTElBQkxFIEZPUiBBTllcbiAqIERJUkVDVCwgSU5ESVJFQ1QsIElOQ0lERU5UQUwsIFNQRUNJQUwsIEVYRU1QTEFSWSwgT1IgQ09OU0VRVUVOVElBTCBEQU1BR0VTXG4gKiAoSU5DTFVESU5HLCBCVVQgTk9UIExJTUlURUQgVE8sIFBST0NVUkVNRU5UIE9GIFNVQlNUSVRVVEUgR09PRFMgT1IgU0VSVklDRVMsXG4gKiBCVVNJTkVTUyBJTlRFUlJVUFRJT04sIE9SIExPU1MgT0YgVVNFLCBEQVRBLCBPUiBQUk9GSVRTKSBIT1dFVkVSIENBVVNFRCBBTkRcbiAqIE9OIEFOWSBUSEVPUlkgT0YgTElBQklMSVRZLCBXSEVUSEVSIElOIENPTlRSQUNULCBTVFJJQ1QgTElBQklMSVRZLCBPUiBUT1JUXG4gKiAoSU5DTFVESU5HIE5FR0xJR0VOQ0UgT1IgT1RIRVJXSVNFKSBBUklTSU5HIElOIEFOWSBXQVkgT1VUIE9GIFRIRSBVU0UgT0ZcbiAqIFRIRSBTUElORSBSVU5USU1FUywgRVZFTiBJRiBBRFZJU0VEIE9GIFRIRSBQT1NTSUJJTElUWSBPRiBTVUNIIERBTUFHRS5cbiAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgQXNzZXRNYW5hZ2VyLCBJbnB1dCwgTWFuYWdlZFdlYkdMUmVuZGVyaW5nQ29udGV4dCwgU2NlbmVSZW5kZXJlciwgdHlwZSBTdHJpbmdNYXAsIFRpbWVLZWVwZXIgfSBmcm9tIFwiLi9pbmRleC5qc1wiO1xuXG4vKiogQW4gYXBwIHJ1bm5pbmcgaW5zaWRlIGEge0BsaW5rIFNwaW5lQ2FudmFzfS4gVGhlIGFwcCBsaWZlLWN5Y2xlXG4gKiBpcyBhcyBmb2xsb3dzOlxuICpcbiAqIDEuIGBsb2FkQXNzZXRzKClgIGlzIGNhbGxlZC4gVGhlIGFwcCBjYW4gcXVldWUgYXNzZXRzIGZvciBsb2FkaW5nIHZpYSB7QGxpbmsgU3BpbmVDYW52YXMuYXNzZXRNYW5hZ2VyfS5cbiAqIDIuIGBpbml0aWFsaXplKClgIGlzIGNhbGxlZCB3aGVuIGFsbCBhc3NldHMgYXJlIGxvYWRlZC4gVGhlIGFwcCBjYW4gc2V0dXAgYW55dGhpbmcgaXQgbmVlZHMgdG8gZW50ZXIgdGhlIG1haW4gYXBwbGljYXRpb24gbG9naWMuXG4gKiAzLiBgdXBkYXRlKClgIGlzIGNhbGxlZCBwZXJpb2RpY2FsbHkgYXQgc2NyZWVuIHJlZnJlc2ggcmF0ZS4gVGhlIGFwcCBjYW4gdXBkYXRlIGl0cyBzdGF0ZS5cbiAqIDQuIGByZW5kZXIoKWAgaXMgY2FsbGVkIHBlcmlvZGljYWxseSBhdCBzY3JlZW4gcmVmcmVzaCByYXRlLiBUaGUgYXBwIGNhbiByZW5kZXIgaXRzIHN0YXRlIHZpYSB7QGxpbmsgU3BpbmVDYW52YXMucmVuZGVyZXJ9IG9yIGRpcmVjdGx5IHZpYSB0aGUgV2ViR0wgY29udGV4dCBpbiB7QGxpbmsgU3BpbmVDYW52YXMuZ2x9LlxuICpcbiAqIFRoZSBgZXJyb3IoKWAgbWV0aG9kIGlzIGNhbGxlZCBpbiBjYXNlIHRoZSBhc3NldHMgY291bGQgbm90IGJlIGxvYWRlZC4gVGhlIGBkaXNwb3NlKClgIG1ldGhvZCBpcyBjYWxsZWQgaW4gY2FzZSB0aGUgY2FudmFzIGhhcyBiZWVuIGRpc3Bvc2VkIHZpYSB7QGxpbmsgU3BpbmVDYW52YXMuZGlzcG9zZX0uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3BpbmVDYW52YXNBcHAge1xuXHRsb2FkQXNzZXRzPyhjYW52YXM6IFNwaW5lQ2FudmFzKTogdm9pZDtcblx0aW5pdGlhbGl6ZT8oY2FudmFzOiBTcGluZUNhbnZhcyk6IHZvaWQ7XG5cdHVwZGF0ZT8oY2FudmFzOiBTcGluZUNhbnZhcywgZGVsdGE6IG51bWJlcik6IHZvaWQ7XG5cdHJlbmRlcj8oY2FudmFzOiBTcGluZUNhbnZhcyk6IHZvaWQ7XG5cdGVycm9yPyhjYW52YXM6IFNwaW5lQ2FudmFzLCBlcnJvcnM6IFN0cmluZ01hcDxzdHJpbmc+KTogdm9pZDtcblx0ZGlzcG9zZT8oY2FudmFzOiBTcGluZUNhbnZhcyk6IHZvaWQ7XG59XG5cbi8qKiBDb25maWd1cmF0aW9uIHBhc3NlZCB0byB0aGUge0BsaW5rIFNwaW5lQ2FudmFzfSBjb25zdHJ1Y3RvciAqL1xuZXhwb3J0IGludGVyZmFjZSBTcGluZUNhbnZhc0NvbmZpZyB7XG5cdC8qIFRoZSB7QGxpbmsgU3BpbmVDYW52YXNBcHB9IHRvIGJlIHJ1biBpbiB0aGUgY2FudmFzLiAqL1xuXHRhcHA6IFNwaW5lQ2FudmFzQXBwO1xuXHQvKiBUaGUgcGF0aCBwcmVmaXggdG8gYmUgdXNlZCBieSB0aGUge0BsaW5rIEFzc2V0TWFuYWdlcn0uICovXG5cdHBhdGhQcmVmaXg/OiBzdHJpbmc7XG5cdC8qIFRoZSBXZWJHTCBjb250ZXh0IGNvbmZpZ3VyYXRpb24gKi9cblx0d2ViZ2xDb25maWc/OiBXZWJHTENvbnRleHRBdHRyaWJ1dGVzO1xufVxuXG4vKiogTWFuYWdlcyB0aGUgbGlmZS1jeWNsZSBhbmQgV2ViR0wgY29udGV4dCBvZiBhIHtAbGluayBTcGluZUNhbnZhc0FwcH0uIFRoZSBhcHAgbG9hZHNcbiAqIGFzc2V0cyBhbmQgaW5pdGlhbGl6ZXMgaXRzZWxmLCB0aGVuIHVwZGF0ZXMgYW5kIHJlbmRlcnMgaXRzIHN0YXRlIGF0IHRoZSBzY3JlZW4gcmVmcmVzaCByYXRlLiAqL1xuZXhwb3J0IGNsYXNzIFNwaW5lQ2FudmFzIHtcblx0cmVhZG9ubHkgY29udGV4dDogTWFuYWdlZFdlYkdMUmVuZGVyaW5nQ29udGV4dDtcblxuXHQvKiogVHJhY2tzIHRoZSBjdXJyZW50IHRpbWUsIGRlbHRhLCBhbmQgb3RoZXIgdGltZSByZWxhdGVkIHN0YXRpc3RpY3MuICovXG5cdHJlYWRvbmx5IHRpbWUgPSBuZXcgVGltZUtlZXBlcigpO1xuXHQvKiogVGhlIEhUTUwgY2FudmFzIHRvIHJlbmRlciB0by4gKi9cblx0cmVhZG9ubHkgaHRtbENhbnZhczogSFRNTENhbnZhc0VsZW1lbnQ7XG5cdC8qKiBUaGUgV2ViR0wgcmVuZGVyaW5nIGNvbnRleHQuICovXG5cdHJlYWRvbmx5IGdsOiBXZWJHTFJlbmRlcmluZ0NvbnRleHQ7XG5cdC8qKiBUaGUgc2NlbmUgcmVuZGVyZXIgZm9yIGVhc3kgZHJhd2luZyBvZiBza2VsZXRvbnMsIHNoYXBlcywgYW5kIGltYWdlcy4gKi9cblx0cmVhZG9ubHkgcmVuZGVyZXI6IFNjZW5lUmVuZGVyZXI7XG5cdC8qKiBUaGUgYXNzZXQgbWFuYWdlciB0byBsb2FkIGFzc2V0cyB3aXRoLiAqL1xuXHRyZWFkb25seSBhc3NldE1hbmFnZXI6IEFzc2V0TWFuYWdlcjtcblx0LyoqIFRoZSBpbnB1dCBwcm9jZXNzb3IgdXNlZCB0byBsaXN0ZW4gdG8gbW91c2UsIHRvdWNoLCBhbmQga2V5Ym9hcmQgZXZlbnRzLiAqL1xuXHRyZWFkb25seSBpbnB1dDogSW5wdXQ7XG5cblx0cHJpdmF0ZSBkaXNwb3NlZCA9IGZhbHNlO1xuXG5cdC8qKiBDb25zdHJ1Y3RzIGEgbmV3IHNwaW5lIGNhbnZhcywgcmVuZGVyaW5nIHRvIHRoZSBwcm92aWRlZCBIVE1MIGNhbnZhcy4gKi9cblx0Y29uc3RydWN0b3IgKGNhbnZhczogSFRNTENhbnZhc0VsZW1lbnQsIHByaXZhdGUgY29uZmlnOiBTcGluZUNhbnZhc0NvbmZpZykge1xuXHRcdGlmICghY29uZmlnLnBhdGhQcmVmaXgpIGNvbmZpZy5wYXRoUHJlZml4ID0gXCJcIjtcblx0XHRpZiAoIWNvbmZpZy5hcHApIGNvbmZpZy5hcHAgPSB7XG5cdFx0XHRsb2FkQXNzZXRzOiAoKSA9PiB7IH0sXG5cdFx0XHRpbml0aWFsaXplOiAoKSA9PiB7IH0sXG5cdFx0XHR1cGRhdGU6ICgpID0+IHsgfSxcblx0XHRcdHJlbmRlcjogKCkgPT4geyB9LFxuXHRcdFx0ZXJyb3I6ICgpID0+IHsgfSxcblx0XHRcdGRpc3Bvc2U6ICgpID0+IHsgfSxcblx0XHR9XG5cdFx0aWYgKCFjb25maWcud2ViZ2xDb25maWcpIGNvbmZpZy53ZWJnbENvbmZpZyA9IHsgYWxwaGE6IHRydWUgfTtcblxuXHRcdHRoaXMuaHRtbENhbnZhcyA9IGNhbnZhcztcblx0XHR0aGlzLmNvbnRleHQgPSBuZXcgTWFuYWdlZFdlYkdMUmVuZGVyaW5nQ29udGV4dChjYW52YXMsIGNvbmZpZy53ZWJnbENvbmZpZyk7XG5cdFx0dGhpcy5yZW5kZXJlciA9IG5ldyBTY2VuZVJlbmRlcmVyKGNhbnZhcywgdGhpcy5jb250ZXh0KTtcblx0XHR0aGlzLmdsID0gdGhpcy5jb250ZXh0LmdsO1xuXHRcdHRoaXMuYXNzZXRNYW5hZ2VyID0gbmV3IEFzc2V0TWFuYWdlcih0aGlzLmNvbnRleHQsIGNvbmZpZy5wYXRoUHJlZml4KTtcblx0XHR0aGlzLmlucHV0ID0gbmV3IElucHV0KGNhbnZhcyk7XG5cblx0XHRpZiAoY29uZmlnLmFwcC5sb2FkQXNzZXRzKSBjb25maWcuYXBwLmxvYWRBc3NldHModGhpcyk7XG5cblx0XHRjb25zdCBsb29wID0gKCkgPT4ge1xuXHRcdFx0aWYgKHRoaXMuZGlzcG9zZWQpIHJldHVybjtcblx0XHRcdHJlcXVlc3RBbmltYXRpb25GcmFtZShsb29wKTtcblx0XHRcdHRoaXMudGltZS51cGRhdGUoKTtcblx0XHRcdGlmIChjb25maWcuYXBwLnVwZGF0ZSkgY29uZmlnLmFwcC51cGRhdGUodGhpcywgdGhpcy50aW1lLmRlbHRhKTtcblx0XHRcdGlmIChjb25maWcuYXBwLnJlbmRlcikgY29uZmlnLmFwcC5yZW5kZXIodGhpcyk7XG5cdFx0fVxuXG5cdFx0Y29uc3Qgd2FpdEZvckFzc2V0cyA9ICgpID0+IHtcblx0XHRcdGlmICh0aGlzLmRpc3Bvc2VkKSByZXR1cm47XG5cdFx0XHRpZiAodGhpcy5hc3NldE1hbmFnZXIuaXNMb2FkaW5nQ29tcGxldGUoKSkge1xuXHRcdFx0XHRpZiAodGhpcy5hc3NldE1hbmFnZXIuaGFzRXJyb3JzKCkpIHtcblx0XHRcdFx0XHRpZiAoY29uZmlnLmFwcC5lcnJvcikgY29uZmlnLmFwcC5lcnJvcih0aGlzLCB0aGlzLmFzc2V0TWFuYWdlci5nZXRFcnJvcnMoKSk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0aWYgKGNvbmZpZy5hcHAuaW5pdGlhbGl6ZSkgY29uZmlnLmFwcC5pbml0aWFsaXplKHRoaXMpO1xuXHRcdFx0XHRcdGxvb3AoKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cdFx0XHRyZXF1ZXN0QW5pbWF0aW9uRnJhbWUod2FpdEZvckFzc2V0cyk7XG5cdFx0fVxuXHRcdHJlcXVlc3RBbmltYXRpb25GcmFtZSh3YWl0Rm9yQXNzZXRzKTtcblx0fVxuXG5cdC8qKiBDbGVhcnMgdGhlIGNhbnZhcyB3aXRoIHRoZSBnaXZlbiBjb2xvci4gVGhlIGNvbG9yIHZhbHVlcyBhcmUgZ2l2ZW4gaW4gdGhlIHJhbmdlIFswLDFdLiAqL1xuXHRjbGVhciAocjogbnVtYmVyLCBnOiBudW1iZXIsIGI6IG51bWJlciwgYTogbnVtYmVyKSB7XG5cdFx0dGhpcy5nbC5jbGVhckNvbG9yKHIsIGcsIGIsIGEpO1xuXHRcdHRoaXMuZ2wuY2xlYXIodGhpcy5nbC5DT0xPUl9CVUZGRVJfQklUKTtcblx0fVxuXG5cdC8qKiBEaXNwb3NlcyB0aGUgYXBwLCBzbyB0aGUgdXBkYXRlKCkgYW5kIHJlbmRlcigpIGZ1bmN0aW9ucyBhcmUgbm8gbG9uZ2VyIGNhbGxlZC4gQ2FsbHMgdGhlIGRpc3Bvc2UoKSBjYWxsYmFjay4qL1xuXHRkaXNwb3NlICgpIHtcblx0XHRpZiAodGhpcy5jb25maWcuYXBwLmRpc3Bvc2UpIHRoaXMuY29uZmlnLmFwcC5kaXNwb3NlKHRoaXMpO1xuXHRcdHRoaXMuZGlzcG9zZWQgPSB0cnVlO1xuXHR9XG59XG4iXX0=