UNPKG

@ngx-file-upload/ui

Version:

Angular 16 file upload components for @ngx-file-upload/core

118 lines 25 kB
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=