ngx-spine
Version:
[](https://travis-ci.org/PoiScript/ngx-spine)
652 lines • 57.7 kB
JavaScript
/**
* @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