UNPKG

ngx-spine

Version:

[![Build Status](https://travis-ci.org/PoiScript/ngx-spine.svg?branch=master)](https://travis-ci.org/PoiScript/ngx-spine)

652 lines 57.7 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ import { Input, Output, EventEmitter, ViewChild, Component, ElementRef, ChangeDetectionStrategy } from "@angular/core"; import { AssetManager, SceneRenderer, ManagedWebGLRenderingContext, ResizeMode } from "./spine-ts/webgl"; import { TimeKeeper, Skeleton, AnimationState, AtlasAttachmentLoader, SkeletonJson, SkeletonBinary, AnimationStateData, Vector2 } from "./spine-ts/core"; /** * @record */ function Viewport() { } if (false) { /** @type {?} */ Viewport.prototype.x; /** @type {?} */ Viewport.prototype.y; /** @type {?} */ Viewport.prototype.width; /** @type {?} */ Viewport.prototype.height; /** @type {?} */ Viewport.prototype.padLeft; /** @type {?} */ Viewport.prototype.padRight; /** @type {?} */ Viewport.prototype.padTop; /** @type {?} */ Viewport.prototype.padBottom; } /** * @record */ function DataUrls() { } if (false) { /** @type {?|undefined} */ DataUrls.prototype.json; /** @type {?|undefined} */ DataUrls.prototype.skel; /** @type {?} */ DataUrls.prototype.atlas; } export class NgxSpineWebglComponent { constructor() { /* Optional: the default mix time used to switch between two animations. */ this.defaultMix = 0.25; /* Optional: whether the skeleton uses premultiplied alpha. Default: true. */ this.premultipliedAlpha = true; this.transitionTime = 0.2; this.speed = 1; // The name of the animation to be played. Default: first animation in the skeleton. this.animationValue = null; this.animationChange = new EventEmitter(); /* Optional: list of animation names from which the user can choose. */ this.animationsValue = []; this.animationsChange = new EventEmitter(); /* Optional: the name of the skin to be set. Default: the default skin. */ this.skinValue = null; this.skinChange = new EventEmitter(); /* Optional: list of skin names from which the user can choose. */ this.skinsValue = []; this.skinsChange = new EventEmitter(); this.loaded = new EventEmitter(); this.time = new TimeKeeper(); this.paused = true; this.playTime = 0; this.currentViewport = null; this.previousViewport = null; this.viewportTransitionStart = 0; this.init = false; } /** * @return {?} */ get dataUrls() { return this.urls; } /** * @param {?} urls * @return {?} */ set dataUrls(urls) { this.urls = urls; if (!this.urls.json && !this.urls.skel) { throw new Error("Please specify the URL of the skeleton JSON or .skel file."); } if (!this.urls.atlas) { throw new Error("Please specify the URL of the atlas file."); } if (this.init) { this.loaded.emit(false); this.loadAsset().then((/** * @return {?} */ () => { console.log("load assets"); this.loadSkeleton(); this.loaded.emit(true); requestAnimationFrame((/** * @return {?} */ () => this.drawFrame())); })); } } /** * @param {?} val * @return {?} */ set animation(val) { this.animationValue = val; this.animationChange.emit(val); if (this.skeleton && this.animations.length > 0) { this.playTime = 0; this.setAnimation(val); } } /** * @return {?} */ get animation() { return this.animationValue; } /** * @param {?} val * @return {?} */ set animations(val) { this.animationsValue = val; this.animationsChange.emit(val); } /** * @return {?} */ get animations() { return this.animationsValue; } /** * @param {?} val * @return {?} */ set skin(val) { this.skinValue = val; this.skinChange.emit(this.skinValue); if (this.skeleton && this.animations.length > 0) { this.skeleton.setSkinByName(val); this.skeleton.setSlotsToSetupPose(); } } /** * @return {?} */ get skin() { return this.skinValue; } /** * @param {?} val * @return {?} */ set skins(val) { this.skinsValue = val; this.skinsChange.emit(val); } /** * @return {?} */ get skins() { return this.skinsValue; } /** * @return {?} */ ngAfterViewInit() { this.loaded.emit(false); // webgl setup this.context = new ManagedWebGLRenderingContext(this.canvas.nativeElement, { alpha: true }); this.sceneRenderer = new SceneRenderer(this.canvas.nativeElement, this.context, true); // load the assets this.assetManager = new AssetManager(this.context); this.init = true; this.loadAsset().then((/** * @return {?} */ () => { console.log("load assets"); this.loadSkeleton(); this.loaded.emit(true); requestAnimationFrame((/** * @return {?} */ () => this.drawFrame())); })); } /** * @private * @return {?} */ loadAsset() { /** @type {?} */ const promises = []; promises.push(new Promise((/** * @param {?} resolve * @param {?} reject * @return {?} */ (resolve, reject) => { this.assetManager.loadTextureAtlas(this.dataUrls.atlas, resolve, reject); }))); if (this.dataUrls.json) { promises.push(new Promise((/** * @param {?} resolve * @param {?} reject * @return {?} */ (resolve, reject) => { this.assetManager.loadText(this.dataUrls.json, resolve, reject); }))); } else { promises.push(new Promise((/** * @param {?} resolve * @param {?} reject * @return {?} */ (resolve, reject) => { this.assetManager.loadBinary(this.dataUrls.skel, resolve, reject); }))); } return Promise.all(promises); } /** * @private * @return {?} */ loadSkeleton() { /** @type {?} */ const atlas = this.assetManager.get(this.dataUrls.atlas); /** @type {?} */ let skeletonData; if (this.dataUrls.json) { /** @type {?} */ const json = this.assetManager.get(this.dataUrls.json); /** @type {?} */ const skeletonJson = new SkeletonJson(new AtlasAttachmentLoader(atlas)); skeletonData = skeletonJson.readSkeletonData(json); } else { /** @type {?} */ const binary = this.assetManager.get(this.dataUrls.skel); /** @type {?} */ const skeletonBinary = new SkeletonBinary(new AtlasAttachmentLoader(atlas)); skeletonData = skeletonBinary.readSkeletonData(binary); } this.skeleton = new Skeleton(skeletonData); /** @type {?} */ const stateData = new AnimationStateData(skeletonData); stateData.defaultMix = this.defaultMix; this.animationState = new AnimationState(stateData); /// Setup skin if (skeletonData.skins.length > 0) { this.skins = skeletonData.skins.map((/** * @param {?} s * @return {?} */ s => s.name)); } else { throw new Error(""); } if (this.skin) { if (!this.skins.includes(this.skin)) { throw new Error(""); } this.skeleton.setSkinByName(this.skin); this.skeleton.setSlotsToSetupPose(); } else { this.skin = this.skins[0]; } /// Setup animations if (skeletonData.animations.length > 0) { this.animations = skeletonData.animations.map((/** * @param {?} a * @return {?} */ a => a.name)); } if (this.animation) { if (!this.animations.includes(this.animation)) { throw new Error(""); } } else { this.animation = this.animations[0]; } this.play(); } /** * @param {?=} requestNextFrame * @return {?} */ drawFrame(requestNextFrame = true) { if (requestNextFrame) { requestAnimationFrame((/** * @return {?} */ () => this.drawFrame())); } /** @type {?} */ const gl = this.context.gl; gl.clearColor(0, 0, 0, 0); gl.clear(gl.COLOR_BUFFER_BIT); // Resize the canvas this.sceneRenderer.resize(ResizeMode.Expand); // Update animation and skeleton if (!this.paused && this.animation) { this.time.update(); /** @type {?} */ const delta = this.time.delta * this.speed; /** @type {?} */ const animationDuration = this.animationState.getCurrent(0).animation .duration; this.playTime += delta; while (this.playTime >= animationDuration && animationDuration !== 0) { this.playTime -= animationDuration; } this.playTime = Math.max(0, Math.min(this.playTime, animationDuration)); // this.timelineSlider.setValue(this.playTime / animationDuration); this.animationState.update(delta); this.animationState.apply(this.skeleton); } this.skeleton.updateWorldTransform(); /** @type {?} */ let viewport = { x: this.currentViewport.x - ((/** @type {?} */ (this.currentViewport.padLeft))), y: this.currentViewport.y - ((/** @type {?} */ (this.currentViewport.padBottom))), width: this.currentViewport.width + ((/** @type {?} */ (this.currentViewport.padLeft))) + ((/** @type {?} */ (this.currentViewport.padRight))), height: this.currentViewport.height + ((/** @type {?} */ (this.currentViewport.padBottom))) + ((/** @type {?} */ (this.currentViewport.padTop))) }; /** @type {?} */ const transitionAlpha = (performance.now() - this.viewportTransitionStart) / 1000 / this.transitionTime; if (this.previousViewport && transitionAlpha < 1) { /** @type {?} */ const oldViewport = { x: this.previousViewport.x - ((/** @type {?} */ (this.previousViewport.padLeft))), y: this.previousViewport.y - ((/** @type {?} */ (this.previousViewport.padBottom))), width: this.previousViewport.width + ((/** @type {?} */ (this.previousViewport.padLeft))) + ((/** @type {?} */ (this.previousViewport.padRight))), height: this.previousViewport.height + ((/** @type {?} */ (this.previousViewport.padBottom))) + ((/** @type {?} */ (this.previousViewport.padTop))) }; viewport = { x: oldViewport.x + (viewport.x - oldViewport.x) * transitionAlpha, y: oldViewport.y + (viewport.y - oldViewport.y) * transitionAlpha, width: oldViewport.width + (viewport.width - oldViewport.width) * transitionAlpha, height: oldViewport.height + (viewport.height - oldViewport.height) * transitionAlpha }; } /** @type {?} */ const viewportSize = this.scale(viewport.width, viewport.height, this.canvas.nativeElement.width, this.canvas.nativeElement.height); this.sceneRenderer.camera.zoom = viewport.width / viewportSize.x; this.sceneRenderer.camera.position.x = viewport.x + viewport.width / 2; this.sceneRenderer.camera.position.y = viewport.y + viewport.height / 2; this.sceneRenderer.begin(); this.sceneRenderer.drawSkeleton(this.skeleton, this.premultipliedAlpha); this.sceneRenderer.end(); this.sceneRenderer.camera.zoom = 0; } /** * @private * @return {?} */ play() { this.paused = false; this.setAnimation(this.animation); } /** * @private * @return {?} */ pause() { this.paused = true; } /** * @param {?} animation * @return {?} */ setAnimation(animation) { // Determine viewport this.previousViewport = this.currentViewport; /** @type {?} */ const animViewport = this.calculateAnimationViewport(animation); // The calculated animation viewport is the base /** @type {?} */ const viewport = { x: animViewport.x, y: animViewport.y, width: animViewport.width, height: animViewport.height, padLeft: "10%", padRight: "10%", padTop: "10%", padBottom: "10%" }; // Translate percentage paddings to world units viewport.padLeft = this.percentageToWorldUnit(viewport.width, viewport.padLeft); viewport.padRight = this.percentageToWorldUnit(viewport.width, viewport.padRight); viewport.padBottom = this.percentageToWorldUnit(viewport.height, viewport.padBottom); viewport.padTop = this.percentageToWorldUnit(viewport.height, viewport.padTop); // Adjust x, y, width, and height by padding. this.currentViewport = viewport; this.viewportTransitionStart = performance.now(); this.animationState.clearTracks(); this.skeleton.setToSetupPose(); this.animationState.setAnimation(0, animation, true); } /** * @private * @param {?} size * @param {?} percentageOrAbsolute * @return {?} */ percentageToWorldUnit(size, percentageOrAbsolute) { if (typeof percentageOrAbsolute === "string") { return ((size * parseFloat(percentageOrAbsolute.substr(0, percentageOrAbsolute.length - 1))) / 100); } else { return percentageOrAbsolute; } } /** * @private * @param {?} animationName * @return {?} */ calculateAnimationViewport(animationName) { /** @type {?} */ const animation = this.skeleton.data.findAnimation(animationName); this.animationState.clearTracks(); this.skeleton.setToSetupPose(); this.animationState.setAnimationWith(0, animation, true); /** @type {?} */ const steps = 100; /** @type {?} */ const stepTime = animation.duration > 0 ? animation.duration / steps : 0; /** @type {?} */ const offset = new Vector2(); /** @type {?} */ const size = new Vector2(); /** @type {?} */ let minX = 100000000; /** @type {?} */ let maxX = -100000000; /** @type {?} */ let minY = 100000000; /** @type {?} */ let maxY = -100000000; for (let i = 0; i < steps; i++) { this.animationState.update(stepTime); this.animationState.apply(this.skeleton); this.skeleton.updateWorldTransform(); this.skeleton.getBounds(offset, size); minX = Math.min(offset.x, minX); maxX = Math.max(offset.x + size.x, maxX); minY = Math.min(offset.y, minY); maxY = Math.max(offset.y + size.y, maxY); } offset.x = minX; offset.y = minY; size.x = maxX - minX; size.y = maxY - minY; return { x: offset.x, y: offset.y, width: size.x, height: size.y }; } /** * @private * @param {?} sourceWidth * @param {?} sourceHeight * @param {?} targetWidth * @param {?} targetHeight * @return {?} */ scale(sourceWidth, sourceHeight, targetWidth, targetHeight) { /** @type {?} */ const targetRatio = targetHeight / targetWidth; /** @type {?} */ const sourceRatio = sourceHeight / sourceWidth; /** @type {?} */ const scale = targetRatio > sourceRatio ? targetWidth / sourceWidth : targetHeight / sourceHeight; /** @type {?} */ const temp = new Vector2(); temp.x = sourceWidth * scale; temp.y = sourceHeight * scale; return temp; } } NgxSpineWebglComponent.decorators = [ { type: Component, args: [{ selector: "ngx-spine-webgl", template: ` <canvas class="ngx-spine-webgl" #canvas></canvas> `, changeDetection: ChangeDetectionStrategy.OnPush }] } ]; NgxSpineWebglComponent.propDecorators = { dataUrls: [{ type: Input }], defaultMix: [{ type: Input }], premultipliedAlpha: [{ type: Input }], transitionTime: [{ type: Input }], speed: [{ type: Input }], canvas: [{ type: ViewChild, args: ["canvas", { static: true, read: ElementRef },] }], animationChange: [{ type: Output }], animation: [{ type: Input }], animationsChange: [{ type: Output }], animations: [{ type: Input }], skinChange: [{ type: Output }], skin: [{ type: Input }], skinsChange: [{ type: Output }], skins: [{ type: Input }], loaded: [{ type: Output }] }; if (false) { /** * @type {?} * @private */ NgxSpineWebglComponent.prototype.urls; /** @type {?} */ NgxSpineWebglComponent.prototype.defaultMix; /** @type {?} */ NgxSpineWebglComponent.prototype.premultipliedAlpha; /** @type {?} */ NgxSpineWebglComponent.prototype.transitionTime; /** @type {?} */ NgxSpineWebglComponent.prototype.speed; /** * @type {?} * @private */ NgxSpineWebglComponent.prototype.canvas; /** * @type {?} * @private */ NgxSpineWebglComponent.prototype.animationValue; /** @type {?} */ NgxSpineWebglComponent.prototype.animationChange; /** * @type {?} * @private */ NgxSpineWebglComponent.prototype.animationsValue; /** @type {?} */ NgxSpineWebglComponent.prototype.animationsChange; /** * @type {?} * @private */ NgxSpineWebglComponent.prototype.skinValue; /** @type {?} */ NgxSpineWebglComponent.prototype.skinChange; /** * @type {?} * @private */ NgxSpineWebglComponent.prototype.skinsValue; /** @type {?} */ NgxSpineWebglComponent.prototype.skinsChange; /** @type {?} */ NgxSpineWebglComponent.prototype.loaded; /** * @type {?} * @private */ NgxSpineWebglComponent.prototype.sceneRenderer; /** * @type {?} * @private */ NgxSpineWebglComponent.prototype.context; /** * @type {?} * @private */ NgxSpineWebglComponent.prototype.assetManager; /** * @type {?} * @private */ NgxSpineWebglComponent.prototype.skeleton; /** * @type {?} * @private */ NgxSpineWebglComponent.prototype.animationState; /** * @type {?} * @private */ NgxSpineWebglComponent.prototype.time; /** * @type {?} * @private */ NgxSpineWebglComponent.prototype.paused; /** * @type {?} * @private */ NgxSpineWebglComponent.prototype.playTime; /** * @type {?} * @private */ NgxSpineWebglComponent.prototype.currentViewport; /** * @type {?} * @private */ NgxSpineWebglComponent.prototype.previousViewport; /** * @type {?} * @private */ NgxSpineWebglComponent.prototype.viewportTransitionStart; /** * @type {?} * @private */ NgxSpineWebglComponent.prototype.init; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LXNwaW5lLXdlYmdsLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiJuZzovL25neC1zcGluZS8iLCJzb3VyY2VzIjpbImxpYi9uZ3gtc3BpbmUtd2ViZ2wuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPLEVBQ0wsS0FBSyxFQUNMLE1BQU0sRUFDTixZQUFZLEVBQ1osU0FBUyxFQUNULFNBQVMsRUFDVCxVQUFVLEVBRVYsdUJBQXVCLEVBQ3hCLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFDTCxZQUFZLEVBQ1osYUFBYSxFQUNiLDRCQUE0QixFQUM1QixVQUFVLEVBQ1gsTUFBTSxrQkFBa0IsQ0FBQztBQUUxQixPQUFPLEVBQ0wsVUFBVSxFQUNWLFFBQVEsRUFDUixjQUFjLEVBRWQscUJBQXFCLEVBQ3JCLFlBQVksRUFDWixjQUFjLEVBQ2Qsa0JBQWtCLEVBQ2xCLE9BQU8sRUFDUixNQUFNLGlCQUFpQixDQUFDOzs7O0FBRXpCLHVCQVNDOzs7SUFSQyxxQkFBVTs7SUFDVixxQkFBVTs7SUFDVix5QkFBYzs7SUFDZCwwQkFBZTs7SUFDZiwyQkFBeUI7O0lBQ3pCLDRCQUEwQjs7SUFDMUIsMEJBQXdCOztJQUN4Qiw2QkFBMkI7Ozs7O0FBRzdCLHVCQVNDOzs7SUFQQyx3QkFBYzs7SUFHZCx3QkFBYzs7SUFHZCx5QkFBYzs7QUFVaEIsTUFBTSxPQUFPLHNCQUFzQjtJQVBuQzs7UUF1Q1csZUFBVSxHQUFHLElBQUksQ0FBQzs7UUFHbEIsdUJBQWtCLEdBQUcsSUFBSSxDQUFDO1FBRTFCLG1CQUFjLEdBQUcsR0FBRyxDQUFDO1FBRXJCLFVBQUssR0FBRyxDQUFDLENBQUM7O1FBTVgsbUJBQWMsR0FBRyxJQUFJLENBQUM7UUFFcEIsb0JBQWUsR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDOztRQWtCdkMsb0JBQWUsR0FBRyxFQUFFLENBQUM7UUFFbkIscUJBQWdCLEdBQUcsSUFBSSxZQUFZLEVBQUUsQ0FBQzs7UUFh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aEMsd0NBQXNCOzs7OztJQUN0QiwwQ0FBcUI7Ozs7O0lBQ3JCLGlEQUF5Qzs7Ozs7SUFDekMsa0RBQTBDOzs7OztJQUMxQyx5REFBb0M7Ozs7O0lBQ3BDLHNDQUFxQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIElucHV0LFxuICBPdXRwdXQsXG4gIEV2ZW50RW1pdHRlcixcbiAgVmlld0NoaWxkLFxuICBDb21wb25lbnQsXG4gIEVsZW1lbnRSZWYsXG4gIEFmdGVyVmlld0luaXQsXG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5XG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5cbmltcG9ydCB7XG4gIEFzc2V0TWFuYWdlcixcbiAgU2NlbmVSZW5kZXJlcixcbiAgTWFuYWdlZFdlYkdMUmVuZGVyaW5nQ29udGV4dCxcbiAgUmVzaXplTW9kZVxufSBmcm9tIFwiLi9zcGluZS10cy93ZWJnbFwiO1xuXG5pbXBvcnQge1xuICBUaW1lS2VlcGVyLFxuICBTa2VsZXRvbixcbiAgQW5pbWF0aW9uU3RhdGUsXG4gIFNrZWxldG9uRGF0YSxcbiAgQXRsYXNBdHRhY2htZW50TG9hZGVyLFxuICBTa2VsZXRvbkpzb24sXG4gIFNrZWxldG9uQmluYXJ5LFxuICBBbmltYXRpb25TdGF0ZURhdGEsXG4gIFZlY3RvcjJcbn0gZnJvbSBcIi4vc3BpbmUtdHMvY29yZVwiO1xuXG5pbnRlcmZhY2UgVmlld3BvcnQge1xuICB4OiBudW1iZXI7XG4gIHk6IG51bWJlcjtcbiAgd2lkdGg6IG51bWJlcjtcbiAgaGVpZ2h0OiBudW1iZXI7XG4gIHBhZExlZnQ6IHN0cmluZyB8IG51bWJlcjtcbiAgcGFkUmlnaHQ6IHN0cmluZyB8IG51bWJlcjtcbiAgcGFkVG9wOiBzdHJpbmcgfCBudW1iZXI7XG4gIHBhZEJvdHRvbTogc3RyaW5nIHwgbnVtYmVyO1xufVxuXG5pbnRlcmZhY2UgRGF0YVVybHMge1xuICAvKiB0aGUgVVJMIG9mIHRoZSBza2VsZXRvbiAuanNvbiBmaWxlICovXG4gIGpzb24/OiBzdHJpbmc7XG5cbiAgLyogdGhlIFVSTCBvZiB0aGUgc2tlbGV0b24gLnNrZWwgZmlsZSAqL1xuICBza2VsPzogc3RyaW5nO1xuXG4gIC8qIHRoZSBVUkwgb2YgdGhlIHNrZWxldG9uIC5hdGxhcyBmaWxlLiBBdGxhcyBwYWdlIGltYWdlcyBhcmUgYXV0b21hdGljYWxseSByZXNvbHZlZC4gKi9cbiAgYXRsYXM6IHN0cmluZztcbn1cblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiBcIm5neC1zcGluZS13ZWJnbFwiLFxuICB0ZW1wbGF0ZTogYFxuICAgIDxjYW52YXMgY2xhc3M9XCJuZ3gtc3BpbmUtd2ViZ2xcIiAjY2FudmFzPjwvY2FudmFzPlxuYCxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2hcbn0pXG5leHBvcnQgY2xhc3MgTmd4U3BpbmVXZWJnbENvbXBvbmVudCBpbXBsZW1lbnRzIEFmdGVyVmlld0luaXQge1xuICBwcml2YXRlIHVybHM6IERhdGFVcmxzO1xuXG4gIGdldCBkYXRhVXJscygpOiBEYXRhVXJscyB7XG4gICAgcmV0dXJuIHRoaXMudXJscztcbiAgfVxuXG4gIEBJbnB1dCgpXG4gIHNldCBkYXRhVXJscyh1cmxzOiBEYXRhVXJscykge1xuICAgIHRoaXMudXJscyA9IHVybHM7XG5cbiAgICBpZiAoIXRoaXMudXJscy5qc29uICYmICF0aGlzLnVybHMuc2tlbCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBcIlBsZWFzZSBzcGVjaWZ5IHRoZSBVUkwgb2YgdGhlIHNrZWxldG9uIEpTT04gb3IgLnNrZWwgZmlsZS5cIlxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKCF0aGlzLnVybHMuYXRsYXMpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIlBsZWFzZSBzcGVjaWZ5IHRoZSBVUkwgb2YgdGhlIGF0bGFzIGZpbGUuXCIpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLmluaXQpIHtcbiAgICAgIHRoaXMubG9hZGVkLmVtaXQoZmFsc2UpO1xuICAgICAgdGhpcy5sb2FkQXNzZXQoKS50aGVuKCgpID0+IHtcbiAgICAgICAgY29uc29sZS5sb2coXCJsb2FkIGFzc2V0c1wiKTtcbiAgICAgICAgdGhpcy5sb2FkU2tlbGV0b24oKTtcbiAgICAgICAgdGhpcy5sb2FkZWQuZW1pdCh0cnVlKTtcbiAgICAgICAgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHRoaXMuZHJhd0ZyYW1lKCkpO1xuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgLyogT3B0aW9uYWw6IHRoZSBkZWZhdWx0IG1peCB0aW1lIHVzZWQgdG8gc3dpdGNoIGJldHdlZW4gdHdvIGFuaW1hdGlvbnMuICovXG4gIEBJbnB1dCgpIGRlZmF1bHRNaXggPSAwLjI1O1xuXG4gIC8qIE9wdGlvbmFsOiB3aGV0aGVyIHRoZSBza2VsZXRvbiB1c2VzIHByZW11bHRpcGxpZWQgYWxwaGEuIERlZmF1bHQ6IHRydWUuICovXG4gIEBJbnB1dCgpIHByZW11bHRpcGxpZWRBbHBoYSA9IHRydWU7XG5cbiAgQElucHV0KCkgdHJhbnNpdGlvblRpbWUgPSAwLjI7XG5cbiAgQElucHV0KCkgc3BlZWQgPSAxO1xuXG4gIEBWaWV3Q2hpbGQoXCJjYW52YXNcIiwgeyBzdGF0aWM6IHRydWUsIHJlYWQ6IEVsZW1lbnRSZWYgfSlcbiAgcHJpdmF0ZSBjYW52YXM6IEVsZW1lbnRSZWY7XG5cbiAgLy8gVGhlIG5hbWUgb2YgdGhlIGFuaW1hdGlvbiB0byBiZSBwbGF5ZWQuIERlZmF1bHQ6IGZpcnN0IGFuaW1hdGlvbiBpbiB0aGUgc2tlbGV0b24uXG4gIHByaXZhdGUgYW5pbWF0aW9uVmFsdWUgPSBudWxsO1xuXG4gIEBPdXRwdXQoKSBhbmltYXRpb25DaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgQElucHV0KClcbiAgc2V0IGFuaW1hdGlvbih2YWw6IHN0cmluZykge1xuICAgIHRoaXMuYW5pbWF0aW9uVmFsdWUgPSB2YWw7XG4gICAgdGhpcy5hbmltYXRpb25DaGFuZ2UuZW1pdCh2YWwpO1xuXG4gICAgaWYgKHRoaXMuc2tlbGV0b24gJiYgdGhpcy5hbmltYXRpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgIHRoaXMucGxheVRpbWUgPSAwO1xuICAgICAgdGhpcy5zZXRBbmltYXRpb24odmFsKTtcbiAgICB9XG4gIH1cblxuICBnZXQgYW5pbWF0aW9uKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuYW5pbWF0aW9uVmFsdWU7XG4gIH1cblxuICAvKiBPcHRpb25hbDogbGlzdCBvZiBhbmltYXRpb24gbmFtZXMgZnJvbSB3aGljaCB0aGUgdXNlciBjYW4gY2hvb3NlLiAqL1xuICBwcml2YXRlIGFuaW1hdGlvbnNWYWx1ZSA9IFtdO1xuXG4gIEBPdXRwdXQoKSBhbmltYXRpb25zQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gIEBJbnB1dCgpXG4gIHNldCBhbmltYXRpb25zKHZhbDogc3RyaW5nW10pIHtcbiAgICB0aGlzLmFuaW1hdGlvbnNWYWx1ZSA9IHZhbDtcbiAgICB0aGlzLmFuaW1hdGlvbnNDaGFuZ2UuZW1pdCh2YWwpO1xuICB9XG5cbiAgZ2V0IGFuaW1hdGlvbnMoKTogc3RyaW5nW10ge1xuICAgIHJldHVybiB0aGlzLmFuaW1hdGlvbnNWYWx1ZTtcbiAgfVxuXG4gIC8qIE9wdGlvbmFsOiB0aGUgbmFtZSBvZiB0aGUgc2tpbiB0byBiZSBzZXQuIERlZmF1bHQ6IHRoZSBkZWZhdWx0IHNraW4uICovXG4gIHByaXZhdGUgc2tpblZhbHVlID0gbnVsbDtcblxuICBAT3V0cHV0KCkgc2tpbkNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICBASW5wdXQoKVxuICBzZXQgc2tpbih2YWw6IHN0cmluZykge1xuICAgIHRoaXMuc2tpblZhbHVlID0gdmFsO1xuICAgIHRoaXMuc2tpbkNoYW5nZS5lbWl0KHRoaXMuc2tpblZhbHVlKTtcblxuICAgIGlmICh0aGlzLnNrZWxldG9uICYmIHRoaXMuYW5pbWF0aW9ucy5sZW5ndGggPiAwKSB7XG4gICAgICB0aGlzLnNrZWxldG9uLnNldFNraW5CeU5hbWUodmFsKTtcbiAgICAgIHRoaXMuc2tlbGV0b24uc2V0U2xvdHNUb1NldHVwUG9zZSgpO1xuICAgIH1cbiAgfVxuXG4gIGdldCBza2luKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuc2tpblZhbHVlO1xuICB9XG5cbiAgLyogT3B0aW9uYWw6IGxpc3Qgb2Ygc2tpbiBuYW1lcyBmcm9tIHdoaWNoIHRoZSB1c2VyIGNhbiBjaG9vc2UuICovXG4gIHByaXZhdGUgc2tpbnNWYWx1ZSA9IFtdO1xuXG4gIEBPdXRwdXQoKSBza2luc0NoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICBASW5wdXQoKVxuICBzZXQgc2tpbnModmFsOiBzdHJpbmdbXSkge1xuICAgIHRoaXMuc2tpbnNWYWx1ZSA9IHZhbDtcbiAgICB0aGlzLnNraW5zQ2hhbmdlLmVtaXQodmFsKTtcbiAgfVxuXG4gIGdldCBza2lucygpOiBzdHJpbmdbXSB7XG4gICAgcmV0dXJuIHRoaXMuc2tpbnNWYWx1ZTtcbiAgfVxuXG4gIEBPdXRwdXQoKSBsb2FkZWQgPSBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XG5cbiAgcHJpdmF0ZSBzY2VuZVJlbmRlcmVyOiBTY2VuZVJlbmRlcmVyO1xuICBwcml2YXRlIGNvbnRleHQ6IE1hbmFnZWRXZWJHTFJlbmRlcmluZ0NvbnRleHQ7XG4gIHByaXZhdGUgYXNzZXRNYW5hZ2VyOiBBc3NldE1hbmFnZXI7XG4gIHByaXZhdGUgc2tlbGV0b246IFNrZWxldG9uO1xuICBwcml2YXRlIGFuaW1hdGlvblN0YXRlOiBBbmltYXRpb25TdGF0ZTtcbiAgcHJpdmF0ZSB0aW1lID0gbmV3IFRpbWVLZWVwZXIoKTtcbiAgcHJpdmF0ZSBwYXVzZWQgPSB0cnVlO1xuICBwcml2YXRlIHBsYXlUaW1lID0gMDtcbiAgcHJpdmF0ZSBjdXJyZW50Vmlld3BvcnQ6IFZpZXdwb3J0ID0gbnVsbDtcbiAgcHJpdmF0ZSBwcmV2aW91c1ZpZXdwb3J0OiBWaWV3cG9ydCA9IG51bGw7XG4gIHByaXZhdGUgdmlld3BvcnRUcmFuc2l0aW9uU3RhcnQgPSAwO1xuICBwcml2YXRlIGluaXQgPSBmYWxzZTtcblxuICBuZ0FmdGVyVmlld0luaXQoKSB7XG4gICAgdGhpcy5sb2FkZWQuZW1pdChmYWxzZSk7XG4gICAgLy8gd2ViZ2wgc2V0dXBcbiAgICB0aGlzLmNvbnRleHQgPSBuZXcgTWFuYWdlZFdlYkdMUmVuZGVyaW5nQ29udGV4dCh0aGlzLmNhbnZhcy5uYXRpdmVFbGVtZW50LCB7XG4gICAgICBhbHBoYTogdHJ1ZVxuICAgIH0pO1xuICAgIHRoaXMuc2NlbmVSZW5kZXJlciA9IG5ldyBTY2VuZVJlbmRlcmVyKFxuICAgICAgdGhpcy5jYW52YXMubmF0aXZlRWxlbWVudCxcbiAgICAgIHRoaXMuY29udGV4dCxcbiAgICAgIHRydWVcbiAgICApO1xuXG4gICAgLy8gbG9hZCB0aGUgYXNzZXRzXG4gICAgdGhpcy5hc3NldE1hbmFnZXIgPSBuZXcgQXNzZXRNYW5hZ2VyKHRoaXMuY29udGV4dCk7XG5cbiAgICB0aGlzLmluaXQgPSB0cnVlO1xuXG4gICAgdGhpcy5sb2FkQXNzZXQoKS50aGVuKCgpID0+IHtcbiAgICAgIGNvbnNvbGUubG9nKFwibG9hZCBhc3NldHNcIik7XG4gICAgICB0aGlzLmxvYWRTa2VsZXRvbigpO1xuICAgICAgdGhpcy5sb2FkZWQuZW1pdCh0cnVlKTtcbiAgICAgIHJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB0aGlzLmRyYXdGcmFtZSgpKTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgbG9hZEFzc2V0KCkge1xuICAgIGNvbnN0IHByb21pc2VzID0gW107XG4gICAgcHJvbWlzZXMucHVzaChcbiAgICAgIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgdGhpcy5hc3NldE1hbmFnZXIubG9hZFRleHR1cmVBdGxhcyhcbiAgICAgICAgICB0aGlzLmRhdGFVcmxzLmF0bGFzLFxuICAgICAgICAgIHJlc29sdmUsXG4gICAgICAgICAgcmVqZWN0XG4gICAgICAgICk7XG4gICAgICB9KVxuICAgICk7XG4gICAgaWYgKHRoaXMuZGF0YVVybHMuanNvbikge1xuICAgICAgcHJvbWlzZXMucHVzaChcbiAgICAgICAgbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgIHRoaXMuYXNzZXRNYW5hZ2VyLmxvYWRUZXh0KHRoaXMuZGF0YVVybHMuanNvbiwgcmVzb2x2ZSwgcmVqZWN0KTtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHByb21pc2VzLnB1c2goXG4gICAgICAgIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICB0aGlzLmFzc2V0TWFuYWdlci5sb2FkQmluYXJ5KHRoaXMuZGF0YVVybHMuc2tlbCwgcmVzb2x2ZSwgcmVqZWN0KTtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBQcm9taXNlLmFsbChwcm9taXNlcyk7XG4gIH1cblxuICBwcml2YXRlIGxvYWRTa2VsZXRvbigpIHtcbiAgICBjb25zdCBhdGxhcyA9IHRoaXMuYXNzZXRNYW5hZ2VyLmdldCh0aGlzLmRhdGFVcmxzLmF0bGFzKTtcbiAgICBsZXQgc2tlbGV0b25EYXRhOiBTa2VsZXRvbkRhdGE7XG5cbiAgICBpZiAodGhpcy5kYXRhVXJscy5qc29uKSB7XG4gICAgICBjb25zdCBqc29uID0gdGhpcy5hc3NldE1hbmFnZXIuZ2V0KHRoaXMuZGF0YVVybHMuanNvbik7XG4gICAgICBjb25zdCBza2VsZXRvbkpzb24gPSBuZXcgU2tlbGV0b25Kc29uKG5ldyBBdGxhc0F0dGFjaG1lbnRMb2FkZXIoYXRsYXMpKTtcbiAgICAgIHNrZWxldG9uRGF0YSA9IHNrZWxldG9uSnNvbi5yZWFkU2tlbGV0b25EYXRhKGpzb24pO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBiaW5hcnkgPSB0aGlzLmFzc2V0TWFuYWdlci5nZXQodGhpcy5kYXRhVXJscy5za2VsKTtcbiAgICAgIGNvbnN0IHNrZWxldG9uQmluYXJ5ID0gbmV3IFNrZWxldG9uQmluYXJ5KFxuICAgICAgICBuZXcgQXRsYXNBdHRhY2htZW50TG9hZGVyKGF0bGFzKVxuICAgICAgKTtcbiAgICAgIHNrZWxldG9uRGF0YSA9IHNrZWxldG9uQmluYXJ5LnJlYWRTa2VsZXRvbkRhdGEoYmluYXJ5KTtcbiAgICB9XG5cbiAgICB0aGlzLnNrZWxldG9uID0gbmV3IFNrZWxldG9uKHNrZWxldG9uRGF0YSk7XG4gICAgY29uc3Qgc3RhdGVEYXRhID0gbmV3IEFuaW1hdGlvblN0YXRlRGF0YShza2VsZXRvbkRhdGEpO1xuICAgIHN0YXRlRGF0YS5kZWZhdWx0TWl4ID0gdGhpcy5kZWZhdWx0TWl4O1xuICAgIHRoaXMuYW5pbWF0aW9uU3RhdGUgPSBuZXcgQW5pbWF0aW9uU3RhdGUoc3RhdGVEYXRhKTtcblxuICAgIC8vLyBTZXR1cCBza2luXG4gICAgaWYgKHNrZWxldG9uRGF0YS5za2lucy5sZW5ndGggPiAwKSB7XG4gICAgICB0aGlzLnNraW5zID0gc2tlbGV0b25EYXRhLnNraW5zLm1hcChzID0+IHMubmFtZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIlwiKTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5za2luKSB7XG4gICAgICBpZiAoIXRoaXMuc2tpbnMuaW5jbHVkZXModGhpcy5za2luKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJcIik7XG4gICAgICB9XG4gICAgICB0aGlzLnNrZWxldG9uLnNldFNraW5CeU5hbWUodGhpcy5za2luKTtcbiAgICAgIHRoaXMuc2tlbGV0b24uc2V0U2xvdHNUb1NldHVwUG9zZSgpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnNraW4gPSB0aGlzLnNraW5zWzBdO1xuICAgIH1cblxuICAgIC8vLyBTZXR1cCBhbmltYXRpb25zXG4gICAgaWYgKHNrZWxldG9uRGF0YS5hbmltYXRpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgIHRoaXMuYW5pbWF0aW9ucyA9IHNrZWxldG9uRGF0YS5hbmltYXRpb25zLm1hcChhID0+IGEubmFtZSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuYW5pbWF0aW9uKSB7XG4gICAgICBpZiAoIXRoaXMuYW5pbWF0aW9ucy5pbmNsdWRlcyh0aGlzLmFuaW1hdGlvbikpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiXCIpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmFuaW1hdGlvbiA9IHRoaXMuYW5pbWF0aW9uc1swXTtcbiAgICB9XG5cbiAgICB0aGlzLnBsYXkoKTtcbiAgfVxuXG4gIGRyYXdGcmFtZShyZXF1ZXN0TmV4dEZyYW1lID0gdHJ1ZSkge1xuICAgIGlmIChyZXF1ZXN0TmV4dEZyYW1lKSB7XG4gICAgICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4gdGhpcy5kcmF3RnJhbWUoKSk7XG4gICAgfVxuXG4gICAgY29uc3QgZ2wgPSB0aGlzLmNvbnRleHQuZ2w7XG5cbiAgICBnbC5jbGVhckNvbG9yKDAsIDAsIDAsIDApO1xuICAgIGdsLmNsZWFyKGdsLkNPTE9SX0JVRkZFUl9CSVQpO1xuXG4gICAgLy8gUmVzaXplIHRoZSBjYW52YXNcbiAgICB0aGlzLnNjZW5lUmVuZGVyZXIucmVzaXplKFJlc2l6ZU1vZGUuRXhwYW5kKTtcblxuICAgIC8vIFVwZGF0ZSBhbmltYXRpb24gYW5kIHNrZWxldG9uXG4gICAgaWYgKCF0aGlzLnBhdXNlZCAmJiB0aGlzLmFuaW1hdGlvbikge1xuICAgICAgdGhpcy50aW1lLnVwZGF0ZSgpO1xuICAgICAgY29uc3QgZGVsdGEgPSB0aGlzLnRpbWUuZGVsdGEgKiB0aGlzLnNwZWVkO1xuXG4gICAgICBjb25zdCBhbmltYXRpb25EdXJhdGlvbiA9IHRoaXMuYW5pbWF0aW9uU3RhdGUuZ2V0Q3VycmVudCgwKS5hbmltYXRpb25cbiAgICAgICAgLmR1cmF0aW9uO1xuICAgICAgdGhpcy5wbGF5VGltZSArPSBkZWx0YTtcbiAgICAgIHdoaWxlICh0aGlzLnBsYXlUaW1lID49IGFuaW1hdGlvbkR1cmF0aW9uICYmIGFuaW1hdGlvbkR1cmF0aW9uICE9PSAwKSB7XG4gICAgICAgIHRoaXMucGxheVRpbWUgLT0gYW5pbWF0aW9uRHVyYXRpb247XG4gICAgICB9XG4gICAgICB0aGlzLnBsYXlUaW1lID0gTWF0aC5tYXgoMCwgTWF0aC5taW4odGhpcy5wbGF5VGltZSwgYW5pbWF0aW9uRHVyYXRpb24pKTtcbiAgICAgIC8vIHRoaXMudGltZWxpbmVTbGlkZXIuc2V0VmFsdWUodGhpcy5wbGF5VGltZSAvIGFuaW1hdGlvbkR1cmF0aW9uKTtcblxuICAgICAgdGhpcy5hbmltYXRpb25TdGF0ZS51cGRhdGUoZGVsdGEpO1xuICAgICAgdGhpcy5hbmltYXRpb25TdGF0ZS5hcHBseSh0aGlzLnNrZWxldG9uKTtcbiAgICB9XG5cbiAgICB0aGlzLnNrZWxldG9uLnVwZGF0ZVdvcmxkVHJhbnNmb3JtKCk7XG5cbiAgICBsZXQgdmlld3BvcnQgPSB7XG4gICAgICB4OiB0aGlzLmN1cnJlbnRWaWV3cG9ydC54IC0gKHRoaXMu