@ngx-file-upload/ui
Version:
Angular 16 file upload components for @ngx-file-upload/core
118 lines • 25 kB
JavaScript
import { Component, Input, ViewChild, ElementRef } from "@angular/core";
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
class ProgressbarCircleData {
constructor() {
this.radius = 0;
this.circumferences = 0;
this.offset = 0;
this.progress = 0;
}
}
export class ProgressbarCircleComponent {
set radius(radius) {
this.data.radius = radius;
}
set parts(parts) {
this.circleParts = Math.max(parts, 1);
}
set gap(gap) {
this.circleGap = Math.max(gap, 1);
}
set progress(progressed) {
/** calculate new offset */
this.data.progress = progressed;
this.updateOffset();
}
constructor(zone) {
this.zone = zone;
this.data = new ProgressbarCircleData();
this.dashArray = `1`;
this.maskId = Math.random().toString(32);
this.circleParts = 1;
this.circleGap = 1;
}
ngOnInit() {
this.initializeData(performance.now());
}
/**
* initialize data, currently we running into a problem if data comes straight
* from storage, then the css properties are not set correctly but element is allready
* rendered. Seems it belongs to a document fragment but not the page / parent component.
*
* So we need to run into an loop to ensure we have all data we need, this loop will break
* after 100ms to ensure we dont run into infinite loop and take what we have.
*
* Neither zone.onStable nor afterViewInit are working for me here. Maybe afterViewChecked but this
* will trigger multiple times.
*
* @todo check for better ways to solve this without loop
* @todo think about second option make size and radius mandatory could be bad for responsive design but will work without loop
*/
initializeData(start, time = 0) {
if (!this.progressbar) {
return;
}
const { width, height } = this.progressbar.nativeElement.getBoundingClientRect();
const sideLength = Math.min(width, height);
// start work arround here, will only triggered if data comes from storage / cache
if (!this.data.radius && sideLength === 0 && (time - start) / 100 < 1) {
this.zone.runOutsideAngular(() => {
requestAnimationFrame((ellapsed) => this.initializeData(start, ellapsed));
});
}
else {
this.data.radius = this.data.radius || this.calcRadius(sideLength) || 0;
this.data.circumferences = 2 * Math.PI * this.data.radius;
this.updateOffset();
this.calcDashArray();
}
}
/** calculate dasharray offset for mask */
updateOffset() {
this.data.offset = ((100 - this.data.progress) / 100) * this.data.circumferences;
}
/**
* calculate circle radius if no one is passed
*/
calcRadius(sideLength) {
if (sideLength === 0 || !this.progressbar || !this.progressbar.nativeElement) {
return 0;
}
const svgElement = this.progressbar.nativeElement;
const strokeProgressEl = svgElement.querySelector("circle.progress");
const strokeBackgroundEl = svgElement.querySelector("circle.progress-bar");
console.log(strokeProgressEl);
console.log(strokeBackgroundEl);
if (!strokeProgressEl || !strokeBackgroundEl) {
return 0;
}
const strokeProgress = getComputedStyle(strokeProgressEl).strokeWidth;
const strokeBackground = getComputedStyle(strokeBackgroundEl).strokeWidth;
const strokeWidth = Math.max(parseFloat(strokeProgress), parseFloat(strokeBackground));
return sideLength / 2 - (strokeWidth / 2);
}
calcDashArray() {
const partWidth = (this.data.circumferences / this.circleParts);
const gap = this.circleParts === 1 ? 0 : partWidth - Math.floor(partWidth) + this.circleGap;
this.dashArray = `${partWidth - gap} ${gap}`;
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: ProgressbarCircleComponent, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.2", type: ProgressbarCircleComponent, selector: "ngx-file-upload-ui--progressbar-circle", inputs: { radius: "radius", parts: "parts", gap: "gap", progress: "progress" }, viewQueries: [{ propertyName: "progressbar", first: true, predicate: ["progressbar"], descendants: true, read: ElementRef, static: true }], ngImport: i0, template: "<svg xmlns=\"http://www.w3.org/2000/svg\" #progressbar>\r\n\r\n <circle class=\"progress-bar\"\r\n cx=\"50%\"\r\n cy=\"50%\"\r\n fill=\"transparent\"\r\n shape-rendering=\"geometricPrecision\"\r\n [attr.r]=\"data.radius\"\r\n [attr.stroke-dasharray]=\"dashArray\"\r\n [attr.mask]=\"'url(#inverted-' + maskId +')'\"></circle>\r\n\r\n <!-- progresssbar circle -->\r\n <circle class=\"progress\" \r\n cx=\"50%\"\r\n cy=\"50%\"\r\n [attr.r]=\"data.radius\"\r\n [attr.stroke-dasharray]=\"dashArray\"\r\n [attr.mask]=\"'url(#' + maskId +')'\"\r\n shape-rendering=\"geometricPrecision\"\r\n fill=\"transparent\">\r\n </circle>\r\n\r\n <!--\r\n declare masks for circles\r\n\r\n first mask show progress, second mask remove progressbar background\r\n if both circles overlap, the edges looks a bit ugly so ensure we only see one\r\n of both progressbar circles\r\n -->\r\n <defs>\r\n <mask id=\"{{maskId}}\" maskUnits=\"userSpaceOnUse\">\r\n <circle class=\"progress mask\" [ngClass]=\"data.progress > 0 ? 'animate' : ''\"\r\n shape-rendering=\"geometricPrecision\"\r\n cx=\"50%\"\r\n cy=\"50%\"\r\n [attr.r]=\"data.radius\"\r\n [attr.stroke-dasharray]=\"data.circumferences\"\r\n [attr.stroke-dashoffset]=\"data.offset\"\r\n stroke=\"white\"\r\n fill=\"black\">\r\n </circle>\r\n </mask>\r\n <mask id=\"inverted-{{maskId}}\" maskUnits=\"userSpaceOnUse\">\r\n <circle class=\"progress-bar mask\" [ngClass]=\"data.progress > 0 ? 'animate' : ''\"\r\n shape-rendering=\"geometricPrecision\"\r\n cx=\"50%\"\r\n cy=\"50%\"\r\n [attr.r]=\"data.radius\"\r\n [attr.stroke-dasharray]=\"data.circumferences\"\r\n [attr.stroke-dashoffset]=\"data.offset - data.circumferences\"\r\n fill=\"black\">\r\n </circle>\r\n </mask>\r\n </defs>\r\n</svg>\r\n\r\n<span>{{data.progress}} %</span>\r\n", styles: [":host{display:block;position:relative}:host svg{transform:rotate(-90deg)}:host svg circle.mask{stroke:#fff!important}:host svg circle.mask.animate{transition:stroke-dashoffset .15s linear}:host span{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.2", ngImport: i0, type: ProgressbarCircleComponent, decorators: [{
type: Component,
args: [{ selector: "ngx-file-upload-ui--progressbar-circle", template: "<svg xmlns=\"http://www.w3.org/2000/svg\" #progressbar>\r\n\r\n <circle class=\"progress-bar\"\r\n cx=\"50%\"\r\n cy=\"50%\"\r\n fill=\"transparent\"\r\n shape-rendering=\"geometricPrecision\"\r\n [attr.r]=\"data.radius\"\r\n [attr.stroke-dasharray]=\"dashArray\"\r\n [attr.mask]=\"'url(#inverted-' + maskId +')'\"></circle>\r\n\r\n <!-- progresssbar circle -->\r\n <circle class=\"progress\" \r\n cx=\"50%\"\r\n cy=\"50%\"\r\n [attr.r]=\"data.radius\"\r\n [attr.stroke-dasharray]=\"dashArray\"\r\n [attr.mask]=\"'url(#' + maskId +')'\"\r\n shape-rendering=\"geometricPrecision\"\r\n fill=\"transparent\">\r\n </circle>\r\n\r\n <!--\r\n declare masks for circles\r\n\r\n first mask show progress, second mask remove progressbar background\r\n if both circles overlap, the edges looks a bit ugly so ensure we only see one\r\n of both progressbar circles\r\n -->\r\n <defs>\r\n <mask id=\"{{maskId}}\" maskUnits=\"userSpaceOnUse\">\r\n <circle class=\"progress mask\" [ngClass]=\"data.progress > 0 ? 'animate' : ''\"\r\n shape-rendering=\"geometricPrecision\"\r\n cx=\"50%\"\r\n cy=\"50%\"\r\n [attr.r]=\"data.radius\"\r\n [attr.stroke-dasharray]=\"data.circumferences\"\r\n [attr.stroke-dashoffset]=\"data.offset\"\r\n stroke=\"white\"\r\n fill=\"black\">\r\n </circle>\r\n </mask>\r\n <mask id=\"inverted-{{maskId}}\" maskUnits=\"userSpaceOnUse\">\r\n <circle class=\"progress-bar mask\" [ngClass]=\"data.progress > 0 ? 'animate' : ''\"\r\n shape-rendering=\"geometricPrecision\"\r\n cx=\"50%\"\r\n cy=\"50%\"\r\n [attr.r]=\"data.radius\"\r\n [attr.stroke-dasharray]=\"data.circumferences\"\r\n [attr.stroke-dashoffset]=\"data.offset - data.circumferences\"\r\n fill=\"black\">\r\n </circle>\r\n </mask>\r\n </defs>\r\n</svg>\r\n\r\n<span>{{data.progress}} %</span>\r\n", styles: [":host{display:block;position:relative}:host svg{transform:rotate(-90deg)}:host svg circle.mask{stroke:#fff!important}:host svg circle.mask.animate{transition:stroke-dashoffset .15s linear}:host span{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}\n"] }]
}], ctorParameters: function () { return [{ type: i0.NgZone }]; }, propDecorators: { progressbar: [{
type: ViewChild,
args: ["progressbar", { read: ElementRef, static: true }]
}], radius: [{
type: Input
}], parts: [{
type: Input
}], gap: [{
type: Input
}], progress: [{
type: Input
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvZ3Jlc3NiYXItY2lyY2xlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvdWkvc3JjL2xpYi9wcm9ncmVzc2Jhci9zcmMvdWkvcHJvZ3Jlc3NiYXItY2lyY2xlLnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvdWkvc3JjL2xpYi9wcm9ncmVzc2Jhci9zcmMvdWkvcHJvZ3Jlc3NiYXItY2lyY2xlLmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBa0IsTUFBTSxlQUFlLENBQUM7OztBQUV4RixNQUFNLHFCQUFxQjtJQUEzQjtRQUNJLFdBQU0sR0FBRyxDQUFDLENBQUM7UUFDWCxtQkFBYyxHQUFHLENBQUMsQ0FBQztRQUNuQixXQUFNLEdBQUcsQ0FBQyxDQUFDO1FBQ1gsYUFBUSxHQUFHLENBQUMsQ0FBQztJQUNqQixDQUFDO0NBQUE7QUFPRCxNQUFNLE9BQU8sMEJBQTBCO0lBZW5DLElBQ1csTUFBTSxDQUFDLE1BQWM7UUFDNUIsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO0lBQzlCLENBQUM7SUFFRCxJQUNXLEtBQUssQ0FBQyxLQUFhO1FBQzFCLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDMUMsQ0FBQztJQUVELElBQ1csR0FBRyxDQUFDLEdBQVc7UUFDdEIsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUN0QyxDQUFDO0lBRUQsSUFDSSxRQUFRLENBQUMsVUFBa0I7UUFDM0IsMkJBQTJCO1FBQzNCLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxHQUFHLFVBQVUsQ0FBQztRQUNoQyxJQUFJLENBQUMs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QVE7c0JBRFgsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIFZpZXdDaGlsZCwgRWxlbWVudFJlZiwgT25Jbml0LCBOZ1pvbmUgfSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xyXG5cclxuY2xhc3MgUHJvZ3Jlc3NiYXJDaXJjbGVEYXRhIHtcclxuICAgIHJhZGl1cyA9IDA7XHJcbiAgICBjaXJjdW1mZXJlbmNlcyA9IDA7XHJcbiAgICBvZmZzZXQgPSAwO1xyXG4gICAgcHJvZ3Jlc3MgPSAwO1xyXG59XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICAgIHNlbGVjdG9yOiBcIm5neC1maWxlLXVwbG9hZC11aS0tcHJvZ3Jlc3NiYXItY2lyY2xlXCIsXHJcbiAgICB0ZW1wbGF0ZVVybDogXCJwcm9ncmVzc2Jhci1jaXJjbGUuaHRtbFwiLFxyXG4gICAgc3R5bGVVcmxzOiBbXCIuL3Byb2dyZXNzYmFyLWNpcmNsZS5zY3NzXCJdXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBQcm9ncmVzc2JhckNpcmNsZUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XHJcblxyXG4gICAgcHVibGljIGRhdGE6IFByb2dyZXNzYmFyQ2lyY2xlRGF0YSA9IG5ldyBQcm9ncmVzc2JhckNpcmNsZURhdGEoKTtcclxuXHJcbiAgICBwdWJsaWMgZGFzaEFycmF5ID0gYDFgO1xyXG5cclxuICAgIHB1YmxpYyBtYXNrSWQgPSBNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKDMyKTtcclxuXHJcbiAgICBwcml2YXRlIGNpcmNsZVBhcnRzID0gMTtcclxuXHJcbiAgICBwcml2YXRlIGNpcmNsZUdhcCA9IDE7XHJcblxyXG4gICAgQFZpZXdDaGlsZChcInByb2dyZXNzYmFyXCIsIHtyZWFkOiBFbGVtZW50UmVmLCBzdGF0aWM6IHRydWV9KVxyXG4gICAgcHJpdmF0ZSBwcm9ncmVzc2JhcjogRWxlbWVudFJlZjxTVkdFbGVtZW50PiB8IHVuZGVmaW5lZDtcclxuXHJcbiAgICBASW5wdXQoKVxyXG4gICAgcHVibGljIHNldCByYWRpdXMocmFkaXVzOiBudW1iZXIpIHtcclxuICAgICAgICB0aGlzLmRhdGEucmFkaXVzID0gcmFkaXVzO1xyXG4gICAgfVxyXG5cclxuICAgIEBJbnB1dCgpXHJcbiAgICBwdWJsaWMgc2V0IHBhcnRzKHBhcnRzOiBudW1iZXIpIHtcclxuICAgICAgICB0aGlzLmNpcmNsZVBhcnRzID0gTWF0aC5tYXgocGFydHMsIDEpO1xyXG4gICAgfVxyXG5cclxuICAgIEBJbnB1dCgpXHJcbiAgICBwdWJsaWMgc2V0IGdhcChnYXA6IG51bWJlcikge1xyXG4gICAgICAgIHRoaXMuY2lyY2xlR2FwID0gTWF0aC5tYXgoZ2FwLCAxKTtcclxuICAgIH1cclxuXHJcbiAgICBASW5wdXQoKVxyXG4gICAgc2V0IHByb2dyZXNzKHByb2dyZXNzZWQ6IG51bWJlcikge1xyXG4gICAgICAgIC8qKiBjYWxjdWxhdGUgbmV3IG9mZnNldCAqL1xyXG4gICAgICAgIHRoaXMuZGF0YS5wcm9ncmVzcyA9IHByb2dyZXNzZWQ7XHJcbiAgICAgICAgdGhpcy51cGRhdGVPZmZzZXQoKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgY29uc3RydWN0b3IoXHJcbiAgICAgICAgcHJpdmF0ZSB6b25lOiBOZ1pvbmVcclxuICAgICkge31cclxuXHJcbiAgICBwdWJsaWMgbmdPbkluaXQoKSB7XHJcbiAgICAgICAgdGhpcy5pbml0aWFsaXplRGF0YShwZXJmb3JtYW5jZS5ub3coKSk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBpbml0aWFsaXplIGRhdGEsIGN1cnJlbnRseSB3ZSBydW5uaW5nIGludG8gYSBwcm9ibGVtIGlmIGRhdGEgY29tZXMgc3RyYWlnaHRcclxuICAgICAqIGZyb20gc3RvcmFnZSwgdGhlbiB0aGUgY3NzIHByb3BlcnRpZXMgYXJlIG5vdCBzZXQgY29ycmVjdGx5IGJ1dCBlbGVtZW50IGlzIGFsbHJlYWR5XHJcbiAgICAgKiByZW5kZXJlZC4gU2VlbXMgaXQgYmVsb25ncyB0byBhIGRvY3VtZW50IGZyYWdtZW50IGJ1dCBub3QgdGhlIHBhZ2UgLyBwYXJlbnQgY29tcG9uZW50LlxyXG4gICAgICpcclxuICAgICAqIFNvIHdlIG5lZWQgdG8gcnVuIGludG8gYW4gbG9vcCB0byBlbnN1cmUgd2UgaGF2ZSBhbGwgZGF0YSB3ZSBuZWVkLCB0aGlzIGxvb3Agd2lsbCBicmVha1xyXG4gICAgICogYWZ0ZXIgMTAwbXMgdG8gZW5zdXJlIHdlIGRvbnQgcnVuIGludG8gaW5maW5pdGUgbG9vcCBhbmQgdGFrZSB3aGF0IHdlIGhhdmUuXHJcbiAgICAgKlxyXG4gICAgICogTmVpdGhlciB6b25lLm9uU3RhYmxlIG5vciBhZnRlclZpZXdJbml0IGFyZSB3b3JraW5nIGZvciBtZSBoZXJlLiBNYXliZSBhZnRlclZpZXdDaGVja2VkIGJ1dCB0aGlzXHJcbiAgICAgKiB3aWxsIHRyaWdnZXIgbXVsdGlwbGUgdGltZXMuXHJcbiAgICAgKlxyXG4gICAgICogQHRvZG8gY2hlY2sgZm9yIGJldHRlciB3YXlzIHRvIHNvbHZlIHRoaXMgd2l0aG91dCBsb29wXHJcbiAgICAgKiBAdG9kbyB0aGluayBhYm91dCBzZWNvbmQgb3B0aW9uIG1ha2Ugc2l6ZSBhbmQgcmFkaXVzIG1hbmRhdG9yeSBjb3VsZCBiZSBiYWQgZm9yIHJlc3BvbnNpdmUgZGVzaWduIGJ1dCB3aWxsIHdvcmsgd2l0aG91dCBsb29wXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgaW5pdGlhbGl6ZURhdGEoc3RhcnQ6IG51bWJlciwgdGltZSA9IDApIHtcclxuXHJcbiAgICAgICAgaWYgKCF0aGlzLnByb2dyZXNzYmFyKSB7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGNvbnN0IHt3aWR0aCwgaGVpZ2h0fSA9IHRoaXMucHJvZ3Jlc3NiYXIubmF0aXZlRWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgICAgICBjb25zdCBzaWRlTGVuZ3RoICA9IE1hdGgubWluKHdpZHRoLCBoZWlnaHQpO1xyXG5cclxuICAgICAgICAvLyBzdGFydCB3b3JrIGFycm91bmQgaGVyZSwgd2lsbCBvbmx5IHRyaWdnZXJlZCBpZiBkYXRhIGNvbWVzIGZyb20gc3RvcmFnZSAvIGNhY2hlXHJcbiAgICAgICAgaWYgKCF0aGlzLmRhdGEucmFkaXVzICYmIHNpZGVMZW5ndGggPT09IDAgJiYgKHRpbWUgLSBzdGFydCkgLyAxMDAgPCAxKSB7XHJcbiAgICAgICAgICAgIHRoaXMuem9uZS5ydW5PdXRzaWRlQW5ndWxhcigoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKGVsbGFwc2VkKSA9PiB0aGlzLmluaXRpYWxpemVEYXRhKHN0YXJ0LCBlbGxhcHNlZCkpO1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICB0aGlzLmRhdGEucmFkaXVzID0gdGhpcy5kYXRhLnJhZGl1cyB8fCB0aGlzLmNhbGNSYWRpdXMoc2lkZUxlbmd0aCkgfHwgMDtcclxuICAgICAgICAgICAgdGhpcy5kYXRhLmNpcmN1bWZlcmVuY2VzID0gMiAqIE1hdGguUEkgKiB0aGlzLmRhdGEucmFkaXVzO1xyXG5cclxuICAgICAgICAgICAgdGhpcy51cGRhdGVPZmZzZXQoKTtcclxuICAgICAgICAgICAgdGhpcy5jYWxjRGFzaEFycmF5KCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKiBjYWxjdWxhdGUgZGFzaGFycmF5IG9mZnNldCBmb3IgbWFzayAqL1xyXG4gICAgcHJpdmF0ZSB1cGRhdGVPZmZzZXQoKSB7XHJcbiAgICAgICAgdGhpcy5kYXRhLm9mZnNldCA9ICgoMTAwIC0gdGhpcy5kYXRhLnByb2dyZXNzKSAvIDEwMCkgKiB0aGlzLmRhdGEuY2lyY3VtZmVyZW5jZXM7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBjYWxjdWxhdGUgY2lyY2xlIHJhZGl1cyBpZiBubyBvbmUgaXMgcGFzc2VkXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgY2FsY1JhZGl1cyhzaWRlTGVuZ3RoOiBudW1iZXIpOiBudW1iZXIge1xyXG5cclxuICAgICAgICBpZiAoc2lkZUxlbmd0aCA9PT0gMCB8fCAhdGhpcy5wcm9ncmVzc2JhciB8fCAhdGhpcy5wcm9ncmVzc2Jhci5uYXRpdmVFbGVtZW50KSB7XHJcbiAgICAgICAgICAgIHJldHVybiAwO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgY29uc3Qgc3ZnRWxlbWVudDogU1ZHRWxlbWVudCA9IHRoaXMucHJvZ3Jlc3NiYXIubmF0aXZlRWxlbWVudDtcclxuICAgICAgICBjb25zdCBzdHJva2VQcm9ncmVzc0VsID0gc3ZnRWxlbWVudC5xdWVyeVNlbGVjdG9yKFwiY2lyY2xlLnByb2dyZXNzXCIpO1xyXG4gICAgICAgIGNvbnN0IHN0cm9rZUJhY2tncm91bmRFbCA9IHN2Z0VsZW1lbnQucXVlcnlTZWxlY3RvcihcImNpcmNsZS5wcm9ncmVzcy1iYXJcIik7XHJcblxyXG4gICAgICAgIGNvbnNvbGUubG9nKHN0cm9rZVByb2dyZXNzRWwpO1xyXG4gICAgICAgIGNvbnNvbGUubG9nKHN0cm9rZUJhY2tncm91bmRFbCk7XHJcblxyXG4gICAgICAgIGlmICghc3Ryb2tlUHJvZ3Jlc3NFbCB8fCAhc3Ryb2tlQmFja2dyb3VuZEVsKSB7XHJcbiAgICAgICAgICAgIHJldHVybiAwO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgY29uc3Qgc3Ryb2tlUHJvZ3Jlc3MgICA9IGdldENvbXB1dGVkU3R5bGUoc3Ryb2tlUHJvZ3Jlc3NFbCkuc3Ryb2tlV2lkdGg7XHJcbiAgICAgICAgY29uc3Qgc3Ryb2tlQmFja2dyb3VuZCA9IGdldENvbXB1dGVkU3R5bGUoc3Ryb2tlQmFja2dyb3VuZEVsKS5zdHJva2VXaWR0aDtcclxuICAgICAgICBjb25zdCBzdHJva2VXaWR0aCAgICAgID0gTWF0aC5tYXgocGFyc2VGbG9hdChzdHJva2VQcm9ncmVzcyksIHBhcnNlRmxvYXQoc3Ryb2tlQmFja2dyb3VuZCkpO1xyXG5cclxuICAgICAgICByZXR1cm4gc2lkZUxlbmd0aCAvIDIgLSAoc3Ryb2tlV2lkdGggLyAyKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGNhbGNEYXNoQXJyYXkoKSB7XHJcbiAgICAgICAgY29uc3QgcGFydFdpZHRoID0gKHRoaXMuZGF0YS5jaXJjdW1mZXJlbmNlcyAvIHRoaXMuY2lyY2xlUGFydHMpO1xyXG4gICAgICAgIGNvbnN0IGdhcCAgICAgICA9IHRoaXMuY2lyY2xlUGFydHMgPT09IDEgPyAwIDogcGFydFdpZHRoIC0gTWF0aC5mbG9vcihwYXJ0V2lkdGgpICsgdGhpcy5jaXJjbGVHYXA7XHJcbiAgICAgICAgdGhpcy5kYXNoQXJyYXkgPSBgJHtwYXJ0V2lkdGggLSBnYXB9ICR7Z2FwfWA7XHJcbiAgICB9XHJcbn1cclxuIiwiPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgI3Byb2dyZXNzYmFyPlxyXG5cclxuICAgIDxjaXJjbGUgY2xhc3M9XCJwcm9ncmVzcy1iYXJcIlxyXG4gICAgICAgIGN4PVwiNTAlXCJcclxuICAgICAgICBjeT1cIjUwJVwiXHJcbiAgICAgICAgZmlsbD1cInRyYW5zcGFyZW50XCJcclxuICAgICAgICBzaGFwZS1yZW5kZXJpbmc9XCJnZW9tZXRyaWNQcmVjaXNpb25cIlxyXG4gICAgICAgIFthdHRyLnJdPVwiZGF0YS5yYWRpdXNcIlxyXG4gICAgICAgIFthdHRyLnN0cm9rZS1kYXNoYXJyYXldPVwiZGFzaEFycmF5XCJcclxuICAgICAgICBbYXR0ci5tYXNrXT1cIid1cmwoI2ludmVydGVkLScgKyBtYXNrSWQgKycpJ1wiPjwvY2lyY2xlPlxyXG5cclxuICAgIDwhLS0gcHJvZ3Jlc3NzYmFyIGNpcmNsZSAtLT5cclxuICAgIDxjaXJjbGUgY2xhc3M9XCJwcm9ncmVzc1wiIFxyXG4gICAgICAgIGN4PVwiNTAlXCJcclxuICAgICAgICBjeT1cIjUwJVwiXHJcbiAgICAgICAgW2F0dHIucl09XCJkYXRhLnJhZGl1c1wiXHJcbiAgICAgICAgW2F0dHIuc3Ryb2tlLWRhc2hhcnJheV09XCJkYXNoQXJyYXlcIlxyXG4gICAgICAgIFthdHRyLm1hc2tdPVwiJ3VybCgjJyArIG1hc2tJZCArJyknXCJcclxuICAgICAgICBzaGFwZS1yZW5kZXJpbmc9XCJnZW9tZXRyaWNQcmVjaXNpb25cIlxyXG4gICAgICAgIGZpbGw9XCJ0cmFuc3BhcmVudFwiPlxyXG4gICAgPC9jaXJjbGU+XHJcblxyXG4gICAgPCEtLVxyXG4gICAgICAgIGRlY2xhcmUgbWFza3MgZm9yIGNpcmNsZXNcclxuXHJcbiAgICAgICAgZmlyc3QgbWFzayBzaG93IHByb2dyZXNzLCBzZWNvbmQgbWFzayByZW1vdmUgcHJvZ3Jlc3NiYXIgYmFja2dyb3VuZFxyXG4gICAgICAgIGlmIGJvdGggY2lyY2xlcyBvdmVybGFwLCB0aGUgZWRnZXMgbG9va3MgYSBiaXQgdWdseSBzbyBlbnN1cmUgd2Ugb25seSBzZWUgb25lXHJcbiAgICAgICAgb2YgYm90aCBwcm9ncmVzc2JhciBjaXJjbGVzXHJcbiAgICAtLT5cclxuICAgIDxkZWZzPlxyXG4gICAgICAgIDxtYXNrIGlkPVwie3ttYXNrSWR9fVwiIG1hc2tVbml0cz1cInVzZXJTcGFjZU9uVXNlXCI+XHJcbiAgICAgICAgICAgIDxjaXJjbGUgY2xhc3M9XCJwcm9ncmVzcyBtYXNrXCIgW25nQ2xhc3NdPVwiZGF0YS5wcm9ncmVzcyA+IDAgPyAnYW5pbWF0ZScgOiAnJ1wiXHJcbiAgICAgICAgICAgICAgICBzaGFwZS1yZW5kZXJpbmc9XCJnZW9tZXRyaWNQcmVjaXNpb25cIlxyXG4gICAgICAgICAgICAgICAgY3g9XCI1MCVcIlxyXG4gICAgICAgICAgICAgICAgY3k9XCI1MCVcIlxyXG4gICAgICAgICAgICAgICAgW2F0dHIucl09XCJkYXRhLnJhZGl1c1wiXHJcbiAgICAgICAgICAgICAgICBbYXR0ci5zdHJva2UtZGFzaGFycmF5XT1cImRhdGEuY2lyY3VtZmVyZW5jZXNcIlxyXG4gICAgICAgICAgICAgICAgW2F0dHIuc3Ryb2tlLWRhc2hvZmZzZXRdPVwiZGF0YS5vZmZzZXRcIlxyXG4gICAgICAgICAgICAgICAgc3Ryb2tlPVwid2hpdGVcIlxyXG4gICAgICAgICAgICAgICAgZmlsbD1cImJsYWNrXCI+XHJcbiAgICAgICAgICAgIDwvY2lyY2xlPlxyXG4gICAgICAgIDwvbWFzaz5cclxuICAgICAgICA8bWFzayBpZD1cImludmVydGVkLXt7bWFza0lkfX1cIiBtYXNrVW5pdHM9XCJ1c2VyU3BhY2VPblVzZVwiPlxyXG4gICAgICAgICAgICA8Y2lyY2xlIGNsYXNzPVwicHJvZ3Jlc3MtYmFyIG1hc2tcIiBbbmdDbGFzc109XCJkYXRhLnByb2dyZXNzID4gMCA/ICdhbmltYXRlJyA6ICcnXCJcclxuICAgICAgICAgICAgICAgIHNoYXBlLXJlbmRlcmluZz1cImdlb21ldHJpY1ByZWNpc2lvblwiXHJcbiAgICAgICAgICAgICAgICBjeD1cIjUwJVwiXHJcbiAgICAgICAgICAgICAgICBjeT1cIjUwJVwiXHJcbiAgICAgICAgICAgICAgICBbYXR0ci5yXT1cImRhdGEucmFkaXVzXCJcclxuICAgICAgICAgICAgICAgIFthdHRyLnN0cm9rZS1kYXNoYXJyYXldPVwiZGF0YS5jaXJjdW1mZXJlbmNlc1wiXHJcbiAgICAgICAgICAgICAgICBbYXR0ci5zdHJva2UtZGFzaG9mZnNldF09XCJkYXRhLm9mZnNldCAtIGRhdGEuY2lyY3VtZmVyZW5jZXNcIlxyXG4gICAgICAgICAgICAgICAgZmlsbD1cImJsYWNrXCI+XHJcbiAgICAgICAgICAgIDwvY2lyY2xlPlxyXG4gICAgICAgIDwvbWFzaz5cclxuICAgIDwvZGVmcz5cclxuPC9zdmc+XHJcblxyXG48c3Bhbj57e2RhdGEucHJvZ3Jlc3N9fSAlPC9zcGFuPlxyXG4iXX0=