ngx-spine
Version:
[](https://travis-ci.org/PoiScript/ngx-spine)
723 lines • 60.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;
}
var NgxSpineWebglComponent = /** @class */ (function () {
function NgxSpineWebglComponent() {
/* 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;
}
Object.defineProperty(NgxSpineWebglComponent.prototype, "dataUrls", {
get: /**
* @return {?}
*/
function () {
return this.urls;
},
set: /**
* @param {?} urls
* @return {?}
*/
function (urls) {
var _this = this;
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 {?}
*/
function () {
console.log("load assets");
_this.loadSkeleton();
_this.loaded.emit(true);
requestAnimationFrame((/**
* @return {?}
*/
function () { return _this.drawFrame(); }));
}));
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxSpineWebglComponent.prototype, "animation", {
get: /**
* @return {?}
*/
function () {
return this.animationValue;
},
set: /**
* @param {?} val
* @return {?}
*/
function (val) {
this.animationValue = val;
this.animationChange.emit(val);
if (this.skeleton && this.animations.length > 0) {
this.playTime = 0;
this.setAnimation(val);
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxSpineWebglComponent.prototype, "animations", {
get: /**
* @return {?}
*/
function () {
return this.animationsValue;
},
set: /**
* @param {?} val
* @return {?}
*/
function (val) {
this.animationsValue = val;
this.animationsChange.emit(val);
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxSpineWebglComponent.prototype, "skin", {
get: /**
* @return {?}
*/
function () {
return this.skinValue;
},
set: /**
* @param {?} val
* @return {?}
*/
function (val) {
this.skinValue = val;
this.skinChange.emit(this.skinValue);
if (this.skeleton && this.animations.length > 0) {
this.skeleton.setSkinByName(val);
this.skeleton.setSlotsToSetupPose();
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxSpineWebglComponent.prototype, "skins", {
get: /**
* @return {?}
*/
function () {
return this.skinsValue;
},
set: /**
* @param {?} val
* @return {?}
*/
function (val) {
this.skinsValue = val;
this.skinsChange.emit(val);
},
enumerable: true,
configurable: true
});
/**
* @return {?}
*/
NgxSpineWebglComponent.prototype.ngAfterViewInit = /**
* @return {?}
*/
function () {
var _this = this;
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 {?}
*/
function () {
console.log("load assets");
_this.loadSkeleton();
_this.loaded.emit(true);
requestAnimationFrame((/**
* @return {?}
*/
function () { return _this.drawFrame(); }));
}));
};
/**
* @private
* @return {?}
*/
NgxSpineWebglComponent.prototype.loadAsset = /**
* @private
* @return {?}
*/
function () {
var _this = this;
/** @type {?} */
var promises = [];
promises.push(new Promise((/**
* @param {?} resolve
* @param {?} reject
* @return {?}
*/
function (resolve, reject) {
_this.assetManager.loadTextureAtlas(_this.dataUrls.atlas, resolve, reject);
})));
if (this.dataUrls.json) {
promises.push(new Promise((/**
* @param {?} resolve
* @param {?} reject
* @return {?}
*/
function (resolve, reject) {
_this.assetManager.loadText(_this.dataUrls.json, resolve, reject);
})));
}
else {
promises.push(new Promise((/**
* @param {?} resolve
* @param {?} reject
* @return {?}
*/
function (resolve, reject) {
_this.assetManager.loadBinary(_this.dataUrls.skel, resolve, reject);
})));
}
return Promise.all(promises);
};
/**
* @private
* @return {?}
*/
NgxSpineWebglComponent.prototype.loadSkeleton = /**
* @private
* @return {?}
*/
function () {
/** @type {?} */
var atlas = this.assetManager.get(this.dataUrls.atlas);
/** @type {?} */
var skeletonData;
if (this.dataUrls.json) {
/** @type {?} */
var json = this.assetManager.get(this.dataUrls.json);
/** @type {?} */
var skeletonJson = new SkeletonJson(new AtlasAttachmentLoader(atlas));
skeletonData = skeletonJson.readSkeletonData(json);
}
else {
/** @type {?} */
var binary = this.assetManager.get(this.dataUrls.skel);
/** @type {?} */
var skeletonBinary = new SkeletonBinary(new AtlasAttachmentLoader(atlas));
skeletonData = skeletonBinary.readSkeletonData(binary);
}
this.skeleton = new Skeleton(skeletonData);
/** @type {?} */
var 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 {?}
*/
function (s) { return 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 {?}
*/
function (a) { return 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 {?}
*/
NgxSpineWebglComponent.prototype.drawFrame = /**
* @param {?=} requestNextFrame
* @return {?}
*/
function (requestNextFrame) {
var _this = this;
if (requestNextFrame === void 0) { requestNextFrame = true; }
if (requestNextFrame) {
requestAnimationFrame((/**
* @return {?}
*/
function () { return _this.drawFrame(); }));
}
/** @type {?} */
var 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 {?} */
var delta = this.time.delta * this.speed;
/** @type {?} */
var 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 {?} */
var 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 {?} */
var transitionAlpha = (performance.now() - this.viewportTransitionStart) /
1000 /
this.transitionTime;
if (this.previousViewport && transitionAlpha < 1) {
/** @type {?} */
var 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 {?} */
var 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 {?}
*/
NgxSpineWebglComponent.prototype.play = /**
* @private
* @return {?}
*/
function () {
this.paused = false;
this.setAnimation(this.animation);
};
/**
* @private
* @return {?}
*/
NgxSpineWebglComponent.prototype.pause = /**
* @private
* @return {?}
*/
function () {
this.paused = true;
};
/**
* @param {?} animation
* @return {?}
*/
NgxSpineWebglComponent.prototype.setAnimation = /**
* @param {?} animation
* @return {?}
*/
function (animation) {
// Determine viewport
this.previousViewport = this.currentViewport;
/** @type {?} */
var animViewport = this.calculateAnimationViewport(animation);
// The calculated animation viewport is the base
/** @type {?} */
var 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 {?}
*/
NgxSpineWebglComponent.prototype.percentageToWorldUnit = /**
* @private
* @param {?} size
* @param {?} percentageOrAbsolute
* @return {?}
*/
function (size, percentageOrAbsolute) {
if (typeof percentageOrAbsolute === "string") {
return ((size *
parseFloat(percentageOrAbsolute.substr(0, percentageOrAbsolute.length - 1))) /
100);
}
else {
return percentageOrAbsolute;
}
};
/**
* @private
* @param {?} animationName
* @return {?}
*/
NgxSpineWebglComponent.prototype.calculateAnimationViewport = /**
* @private
* @param {?} animationName
* @return {?}
*/
function (animationName) {
/** @type {?} */
var animation = this.skeleton.data.findAnimation(animationName);
this.animationState.clearTracks();
this.skeleton.setToSetupPose();
this.animationState.setAnimationWith(0, animation, true);
/** @type {?} */
var steps = 100;
/** @type {?} */
var stepTime = animation.duration > 0 ? animation.duration / steps : 0;
/** @type {?} */
var offset = new Vector2();
/** @type {?} */
var size = new Vector2();
/** @type {?} */
var minX = 100000000;
/** @type {?} */
var maxX = -100000000;
/** @type {?} */
var minY = 100000000;
/** @type {?} */
var maxY = -100000000;
for (var 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 {?}
*/
NgxSpineWebglComponent.prototype.scale = /**
* @private
* @param {?} sourceWidth
* @param {?} sourceHeight
* @param {?} targetWidth
* @param {?} targetHeight
* @return {?}
*/
function (sourceWidth, sourceHeight, targetWidth, targetHeight) {
/** @type {?} */
var targetRatio = targetHeight / targetWidth;
/** @type {?} */
var sourceRatio = sourceHeight / sourceWidth;
/** @type {?} */
var scale = targetRatio > sourceRatio
? targetWidth / sourceWidth
: targetHeight / sourceHeight;
/** @type {?} */
var temp = new Vector2();
temp.x = sourceWidth * scale;
temp.y = sourceHeight * scale;
return temp;
};
NgxSpineWebglComponent.decorators = [
{ type: Component, args: [{
selector: "ngx-spine-webgl",
template: "\n <canvas class=\"ngx-spine-webgl\" #canvas></canvas>\n",
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 }]
};
return NgxSpineWebglComponent;
}());
export { NgxSpineWebglComponent };
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LXNwaW5lLXdlYmdsLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiJuZzovL25neC1zcGluZS8iLCJzb3VyY2VzIjpbImxpYi9uZ3gtc3BpbmUtd2ViZ2wuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPLEVBQ0wsS0FBSyxFQUNMLE1BQU0sRUFDTixZQUFZLEVBQ1osU0FBUyxFQUNULFNBQVMsRUFDVCxVQUFVLEVBRVYsdUJBQXVCLEVBQ3hCLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFDTCxZQUFZLEVBQ1osYUFBYSxFQUNiLDRCQUE0QixFQUM1QixVQUFVLEVBQ1gsTUFBTSxrQkFBa0IsQ0FBQztBQUUxQixPQUFPLEVBQ0wsVUFBVSxFQUNWLFFBQVEsRUFDUixjQUFjLEVBRWQscUJBQXFCLEVBQ3JCLFlBQVksRUFDWixjQUFjLEVBQ2Qsa0JBQWtCLEVBQ2xCLE9BQU8sRUFDUixNQUFNLGlCQUFpQixDQUFDOzs7O0FBRXpCLHVCQVNDOzs7SUFSQyxxQkFBVTs7SUFDVixxQkFBVTs7SUFDVix5QkFBYzs7SUFDZCwwQkFBZTs7SUFDZiwyQkFBeUI7O0lBQ3pCLDRCQUEwQjs7SUFDMUIsMEJBQXdCOztJQUN4Qiw2QkFBMkI7Ozs7O0FBRzdCLHVCQVNDOzs7SUFQQyx3QkFBYzs7SUFHZCx3QkFBYzs7SUFHZCx5QkFBYzs7QUFHaEI7SUFBQTs7UUF1Q1csZUFBVSxHQUFHLElBQUksQ0FBQzs7UUFHbEIsdUJBQWtCLEdBQUcsSUFBSSxDQUFDO1FBRTFCLG1CQUFjLEdBQUcsR0FBRyxDQUFDO1FBRXJCLFVBQUssR0FBRyxDQUFDLENBQUM7O1FBTVgsbUJBQWMsR0FBRyxJQUFJLENBQUM7UUFFcEIsb0JBQWUsR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDOztRQWtCdkMsb0JBQWUsR0FBRyxFQUFFLENBQUM7UUFFbkIscUJBQWdCLEdBQUcsSUFBSSxZQUFZLEVBQUUsQ0FBQzs7UUFheEMsY0FBUyxHQUFHLElBQUks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QWtCL0MsaURBQTZCOztJQUU3QixrREFBZ0Q7Ozs7O0lBYWhELDJDQUF5Qjs7SUFFekIsNENBQTBDOzs7OztJQWtCMUMsNENBQXdCOztJQUV4Qiw2Q0FBMkM7O0lBWTNDLHdDQUErQzs7Ozs7SUFFL0MsK0NBQXFDOzs7OztJQUNyQyx5Q0FBOEM7Ozs7O0lBQzlDLDhDQUFtQzs7Ozs7SUFDbkMsMENBQTJCOzs7OztJQUMzQixnREFBdUM7Ozs7O0lBQ3ZDLHNDQUFnQzs7Ozs7SUFDaEMsd0NBQXNCOzs7OztJQUN0QiwwQ0FBcUI7Ozs7O0lBQ3JCLGlEQUF5Qzs7Ozs7SUFDekMsa0RBQTBDOzs7OztJQUMxQyx5REFBb0M7Ozs7O0lBQ3BDLHNDQUFxQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIElucHV0LFxuICBPdXRwdXQsXG4gIEV2ZW50RW1pdHRlcixcbiAgVmlld0NoaWxkLFxuICBDb21wb25lbnQsXG4gIEVsZW1lbnRSZWYsXG4gIEFmdGVyVmlld0luaXQsXG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5XG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5cbmltcG9ydCB7XG4gIEFzc2V0TWFuYWdlcixcbiAgU2NlbmVSZW5kZXJlcixcbiAgTWFuYWdlZFdlYkdMUmVuZGVyaW5nQ29udGV4dCxcbiAgUmVzaXplTW9kZVxufSBmcm9tIFwiLi9zcGluZS10cy93ZWJnbFwiO1xuXG5pbXBvcnQge1xuICBUaW1lS2VlcGVyLFxuICBTa2VsZXRvbixcbiAgQW5pbWF0aW9uU3RhdGUsXG4gIFNrZWxldG9uRGF0YSxcbiAgQXRsYXNBdHRhY2htZW50TG9hZGVyLFxuICBTa2VsZXRvbkpzb24sXG4gIFNrZWxldG9uQmluYXJ5LFxuICBBbmltYXRpb25TdGF0ZURhdGEsXG4gIFZlY3RvcjJcbn0gZnJvbSBcIi4vc3BpbmUtdHMvY29yZVwiO1xuXG5pbnRlcmZhY2UgVmlld3BvcnQge1xuICB4OiBudW1iZXI7XG4gIHk6IG51bWJlcjtcbiAgd2lkdGg6IG51bWJlcjtcbiAgaGVpZ2h0OiBudW1iZXI7XG4gIHBhZExlZnQ6IHN0cmluZyB8IG51bWJlcjtcbiAgcGFkUmlnaHQ6IHN0cmluZyB8IG51bWJlcjtcbiAgcGFkVG9wOiBzdHJpbmcgfCBudW1iZXI7XG4gIHBhZEJvdHRvbTogc3RyaW5nIHwgbnVtYmVyO1xufVxuXG5pbnRlcmZhY2UgRGF0YVVybHMge1xuICAvKiB0aGUgVVJMIG9mIHRoZSBza2VsZXRvbiAuanNvbiBmaWxlICovXG4gIGpzb24/OiBzdHJpbmc7XG5cbiAgLyogdGhlIFVSTCBvZiB0aGUgc2tlbGV0b24gLnNrZWwgZmlsZSAqL1xuICBza2VsPzogc3RyaW5nO1xuXG4gIC8qIHRoZSBVUkwgb2YgdGhlIHNrZWxldG9uIC5hdGxhcyBmaWxlLiBBdGxhcyBwYWdlIGltYWdlcyBhcmUgYXV0b21hdGljYWxseSByZXNvbHZlZC4gKi9cbiAgYXRsYXM6IHN0cmluZztcbn1cblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiBcIm5neC1zcGluZS13ZWJnbFwiLFxuICB0ZW1wbGF0ZTogYFxuICAgIDxjYW52YXMgY2xhc3M9XCJuZ3gtc3BpbmUtd2ViZ2xcIiAjY2FudmFzPjwvY2FudmFzPlxuYCxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2hcbn0pXG5leHBvcnQgY2xhc3MgTmd4U3BpbmVXZWJnbENvbXBvbmVudCBpbXBsZW1lbnRzIEFmdGVyVmlld0luaXQge1xuICBwcml2YXRlIHVybHM6IERhdGFVcmxzO1xuXG4gIGdldCBkYXRhVXJscygpOiBEYXRhVXJscyB7XG4gICAgcmV0dXJuIHRoaXMudXJscztcbiAgfVxuXG4gIEBJbnB1dCgpXG4gIHNldCBkYXRhVXJscyh1cmxzOiBEYXRhVXJscykge1xuICAgIHRoaXMudXJscyA9IHVybHM7XG5cbiAgICBpZiAoIXRoaXMudXJscy5qc29uICYmICF0aGlzLnVybHMuc2tlbCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBcIlBsZWFzZSBzcGVjaWZ5IHRoZSBVUkwgb2YgdGhlIHNrZWxldG9uIEpTT04gb3IgLnNrZWwgZmlsZS5cIlxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKCF0aGlzLnVybHMuYXRsYXMpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIlBsZWFzZSBzcGVjaWZ5IHRoZSBVUkwgb2YgdGhlIGF0bGFzIGZpbGUuXCIpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLmluaXQpIHtcbiAgICAgIHRoaXMubG9hZGVkLmVtaXQoZmFsc2UpO1xuICAgICAgdGhpcy5sb2FkQXNzZXQoKS50aGVuKCgpID0+IHtcbiAgICAgICAgY29uc29sZS5sb2coXCJsb2FkIGFzc2V0c1wiKTtcbiAgICAgICAgdGhpcy5sb2FkU2tlbGV0b24oKTtcbiAgICAgICAgdGhpcy5sb2FkZWQuZW1pdCh0cnVlKTtcbiAgICAgICAgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHRoaXMuZHJhd0ZyYW1lKCkpO1xuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgLyogT3B0aW9uYWw6IHRoZSBkZWZhdWx0IG1peCB0aW1lIHVzZWQgdG8gc3dpdGNoIGJldHdlZW4gdHdvIGFuaW1hdGlvbnMuICovXG4gIEBJbnB1dCgpIGRlZmF1bHRNaXggPSAwLjI1O1xuXG4gIC8qIE9wdGlvbmFsOiB3aGV0aGVyIHRoZSBza2VsZXRvbiB1c2VzIHByZW11bHRpcGxpZWQgYWxwaGEuIERlZmF1bHQ6IHRydWUuICovXG4gIEBJbnB1dCgpIHByZW11bHRpcGxpZWRBbHBoYSA9IHRydWU7XG5cbiAgQElucHV0KCkgdHJhbnNpdGlvblRpbWUgPSAwLjI7XG5cbiAgQElucHV0KCkgc3BlZWQgPSAxO1xuXG4gIEBWaWV3Q2hpbGQoXCJjYW52YXNcIiwgeyBzdGF0aWM6IHRydWUsIHJlYWQ6IEVsZW1lbnRSZWYgfSlcbiAgcHJpdmF0ZSBjYW52YXM6IEVsZW1lbnRSZWY7XG5cbiAgLy8gVGhlIG5hbWUgb2YgdGhlIGFuaW1hdGlvbiB0byBiZSBwbGF5ZWQuIERlZmF1bHQ6IGZpcnN0IGFuaW1hdGlvbiBpbiB0aGUgc2tlbGV0b24uXG4gIHByaXZhdGUgYW5pbWF0aW9uVmFsdWUgPSBudWxsO1xuXG4gIEBPdXRwdXQoKSBhbmltYXRpb25DaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgQElucHV0KClcbiAgc2V0IGFuaW1hdGlvbih2YWw6IHN0cmluZykge1xuICAgIHRoaXMuYW5pbWF0aW9uVmFsdWUgPSB2YWw7XG4gICAgdGhpcy5hbmltYXRpb25DaGFuZ2UuZW1pdCh2YWwpO1xuXG4gICAgaWYgKHRoaXMuc2tlbGV0b24gJiYgdGhpcy5hbmltYXRpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgIHRoaXMucGxheVRpbWUgPSAwO1xuICAgICAgdGhpcy5zZXRBbmltYXRpb24odmFsKTtcbiAgICB9XG4gIH1cblxuICBnZXQgYW5pbWF0aW9uKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuYW5pbWF0aW9uVmFsdWU7XG4gIH1cblxuICAvKiBPcHRpb25hbDogbGlzdCBvZiBhbmltYXRpb24gbmFtZXMgZnJvbSB3aGljaCB0aGUgdXNlciBjYW4gY2hvb3NlLiAqL1xuICBwcml2YXRlIGFuaW1hdGlvbnNWYWx1ZSA9IFtdO1xuXG4gIEBPdXRwdXQoKSBhbmltYXRpb25zQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gIEBJbnB1dCgpXG4gIHNldCBhbmltYXRpb25zKHZhbDogc3RyaW5nW10pIHtcbiAgICB0aGlzLmFuaW1hdGlvbnNWYWx1ZSA9IHZhbDtcbiAgICB0aGlzLmFuaW1hdGlvbnNDaGFuZ2UuZW1pdCh2YWwpO1xuICB9XG5cbiAgZ2V0IGFuaW1hdGlvbnMoKTogc3RyaW5nW10ge1xuICAgIHJldHVybiB0aGlzLmFuaW1hdGlvbnNWYWx1ZTtcbiAgfVxuXG4gIC8qIE9wdGlvbmFsOiB0aGUgbmFtZSBvZiB0aGUgc2tpbiB0byBiZSBzZXQuIERlZmF1bHQ6IHRoZSBkZWZhdWx0IHNraW4uICovXG4gIHByaXZhdGUgc2tpblZhbHVlID0gbnVsbDtcblxuICBAT3V0cHV0KCkgc2tpbkNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICBASW5wdXQoKVxuICBzZXQgc2tpbih2YWw6IHN0cmluZykge1xuICAgIHRoaXMuc2tpblZhbHVlID0gdmFsO1xuICAgIHRoaXMuc2tpbkNoYW5nZS5lbWl0KHRoaXMuc2tpblZhbHVlKTtcblxuICAgIGlmICh0aGlzLnNrZWxldG9uICYmIHRoaXMuYW5pbWF0aW9ucy5sZW5ndGggPiAwKSB7XG4gICAgICB0aGlzLnNrZWxldG9uLnNldFNraW5CeU5hbWUodmFsKTtcbiAgICAgIHRoaXMuc2tlbGV0b24uc2V0U2xvdHNUb1NldHVwUG9zZSgpO1xuICAgIH1cbiAgfVxuXG4gIGdldCBza2luKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuc2tpblZhbHVlO1xuICB9XG5cbiAgLyogT3B0aW9uYWw6IGxpc3Qgb2Ygc2tpbiBuYW1lcyBmcm9tIHdoaWNoIHRoZSB1c2VyIGNhbiBjaG9vc2UuICovXG4gIHByaXZhdGUgc2tpbnNWYWx1ZSA9IFtdO1xuXG4gIEBPdXRwdXQoKSBza2luc0NoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICBASW5wdXQoKVxuICBzZXQgc2tpbnModmFsOiBzdHJpbmdbXSkge1xuICAgIHRoaXMuc2tpbnNWYWx1ZSA9IHZhbDtcbiAgICB0aGlzLnNraW5zQ2hhbmdlLmVtaXQodmFsKTtcbiAgfVxuXG4gIGdldCBza2lucygpOiBzdHJpbmdbXSB7XG4gICAgcmV0dXJuIHRoaXMuc2tpbnNWYWx1ZTtcbiAgfVxuXG4gIEBPdXRwdXQoKSBsb2FkZWQgPSBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XG5cbiAgcHJpdmF0ZSBzY2VuZVJlbmRlcmVyOiBTY2VuZVJlbmRlcmVyO1xuICBwcml2YXRlIGNvbnRleHQ6IE1hbmFnZWRXZWJHTFJlbmRlcmluZ0NvbnRleHQ7XG4gIHByaXZhdGUgYXNzZXRNYW5hZ2VyOiBBc3NldE1hbmFnZXI7XG4gIHByaXZhdGUgc2tlbGV0b246IFNrZWxldG9uO1xuICBwcml2YXRlIGFuaW1hdGlvblN0YXRlOiBBbmltYXRpb25TdGF0ZTtcbiAgcHJpdmF0ZSB0aW1lID0gbmV3IFRpbWVLZWVwZXIoKTtcbiAgcHJpdmF0ZSBwYXVzZWQgPSB0cnVlO1xuICBwcml2YXRlIHBsYXlUaW1lID0gMDtcbiAgcHJpdmF0ZSBjdXJyZW50Vmlld3BvcnQ6IFZpZXdwb3J0ID0gbnVsbDtcbiAgcHJpdmF0ZSBwcmV2aW91c1ZpZXdwb3J0OiBWaWV3cG9ydCA9IG51bGw7XG4gIHByaXZhdGUgdmlld3BvcnRUcmFuc2l0aW9uU3RhcnQgPSAwO1xuICBwcml2YXRlIGluaXQgPSBmYWxzZTtcblxuICBuZ0FmdGVyVmlld0luaXQoKSB7XG4gICAgdGhpcy5sb2FkZWQuZW1pdChmYWxzZSk7XG4gICAgLy8gd2ViZ2wgc2V0dXBcbiAgICB0aGlzLmNvbnRleHQgPSBuZXcgTWFuYWdlZFdlYkdMUmVuZGVyaW5nQ29udGV4dCh0aGlzLmNhbnZhcy5uYXRpdmVFbGVtZW50LCB7XG4gICAgICBhbHBoYTogdHJ1ZVxuICAgIH0pO1xuICAgIHRoaXMuc2NlbmVSZW5kZXJlciA9IG5ldyBTY2VuZVJlbmRlcmVyKFxuICAgICAgdGhpcy5jYW52YXMubmF0aXZlRWxlbWVudCxcbiAgICAgIHRoaXMuY29udGV4dCxcbiAgICAgIHRydWVcbiAgICApO1xuXG4gICAgLy8gbG9hZCB0aGUgYXNzZXRzXG4gICAgdGhpcy5hc3NldE1hbmFnZXIgPSBuZXcgQXNzZXRNYW5hZ2VyKHRoaXMuY29udGV4dCk7XG5cbiAgICB0aGlzLmluaXQgPSB0cnVlO1xuXG4gICAgdGhpcy5sb2FkQXNzZXQoKS50aGVuKCgpID0+IHtcbiAgICAgIGNvbnNvbGUubG9nKFwibG9hZCBhc3NldHNcIik7XG4gICAgICB0aGlzLmxvYWRTa2VsZXRvbigpO1xuICAgICAgdGhpcy5sb2FkZWQuZW1pdCh0cnVlKTtcbiAgICAgIHJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB0aGlzLmRyYXdGcmFtZSgpKTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgbG9hZEFzc2V0KCkge1xuICAgIGNvbnN0IHByb21pc2VzID0gW107XG4gICAgcHJvbWlzZXMucHVzaChcbiAgICAgIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgdGhpcy5hc3NldE1hbmFnZXIubG9hZFRleHR1cmVBdGxhcyhcbiAgICAgICAgICB0aGlzLmRhdGFVcmxzLmF0bGFzLFxuICAgICAgICAgIHJlc29sdmUsXG4gICAgICAgICAgcmVqZWN0XG4gICAgICAgICk7XG4gICAgICB9KVxuICAgICk7XG4gICAgaWYgKHRoaXMuZGF0YVVybHMuanNvbikge1xuICAgICAgcHJvbWlzZXMucHVzaChcbiAgICAgICAgbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgIHRoaXMuYXNzZXRNYW5hZ2VyLmxvYWRUZXh0KHRoaXMuZGF0YVVybHMuanNvbiwgcmVzb2x2ZSwgcmVqZWN0KTtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHByb21pc2VzLnB1c2goXG4gICAgICAgIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICB0aGlzLmFzc2V0TWFuYWdlci5sb2FkQmluYXJ5KHRoaXMuZGF0YVVybHMuc2tlbCwgcmVzb2x2ZSwgcmVqZWN0KTtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBQcm9taXNlLmFsbChwcm9taXNlcyk7XG4gIH1cblxuICBwcml2YXRlIGxvYWRTa2VsZXRvbigpIHtcbiAgICBjb25zdCBhdGxhcyA9IHRoaXMuYXNzZXRNYW5hZ2VyLmdldCh0aGlzLmRhdGFVcmxzLmF0bGFzKTtcbiAgICBsZXQgc2tlbGV0b25EYXRhOiBTa2VsZXRvbkRhdGE7XG5cbiAgICBpZiAodGhpcy5kYXRhVXJscy5qc29uKSB7XG4gICAgICBjb25zdCBqc29uID0gdGhpcy5hc3NldE1hbmFnZXIuZ2V0KHRoaXMuZGF0YVVybHMuanNvbik7XG4gICAgICBjb25zdCBza2VsZXRvbkpzb24gPSBuZXcgU2tlbGV0b25Kc29uKG5ldyBBdGxhc0F0dGFjaG1lbnRMb2FkZXIoYXRsYXMpKTtcbiAgICAgIHNrZWxldG9uRGF0YSA9IHNrZWxldG9uSnNvbi5yZWFkU2tlbGV0b25EYXRhKGpzb24pO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBiaW5hcnkgPSB0aGlzLmFzc2V0TWFuYWdlci5nZXQodGhpcy5kYXRhVXJ