UNPKG

ng-rating-pro

Version:

A powerful and customizable Angular rating component that allows full and half ratings with support for read-only mode, dynamic scaling, and SVG customization.<br/>Perfect for use in reviews, feedback forms, and rating-based applications.

148 lines 21.2 kB
import { Component, ContentChildren, EventEmitter, HostListener, Input, Output, ViewChild, ViewContainerRef, } from '@angular/core'; import { CustomRatingDirective } from './rating-icon/custom-rating.directive'; import { StarIconComponent } from './rating-icon/star-icon.component'; import { HeartIconComponent } from './rating-icon/heart-icon.component'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; export var State; (function (State) { State["Empty"] = "empty"; State["Half"] = "half"; State["Full"] = "full"; })(State || (State = {})); export class NgRatingProComponent { constructor() { this.scale = 5; this.rating = 0; this.allowHalf = true; this.size = 20; // Default size this.spacing = 8; // Spacing between stars in viewBox units this.readonly = false; this.iconName = 'star'; this.ratingChange = new EventEmitter(); this.states = []; this.starWidth = 24; this.starHeight = 24; this.containerWidth = 0; this.totalWidth = 0; } ngOnInit() { this.updateStates(this.allowHalf); } ngAfterContentInit() { if (this.ratingDirectives.length !== 3) { this.loadDynamicComponent(); } else { this.ratingDirectives.forEach((directive) => { directive.updateRating(this.iconName); }); this.starHeight = this.ratingDirectives.first.iconViewBox[3]; this.starWidth = this.ratingDirectives.first.iconViewBox[2]; } this.updateDimensions(); } loadDynamicComponent() { const component = this.getComponent(); this.dynamicContainer.clear(); this.dynamicContainer.createComponent(component); this.iconName = component.iconName; } getComponent() { switch (this.iconName) { case 'star': return StarIconComponent; case 'heart': return HeartIconComponent; default: return StarIconComponent; } } updateDimensions() { // Calculate total width in viewBox units this.totalWidth = this.starWidth * this.scale + this.spacing * (this.scale - 1); // Calculate container width maintaining aspect ratio const aspectRatio = this.totalWidth / this.starHeight; this.containerWidth = this.size * aspectRatio; } getStarPosition(index) { return index * (this.starWidth + this.spacing); } onClick(event) { if (this.readonly) return; if (event.target instanceof SVGElement && +event.target.id > 0) { const clickedIndex = +event.target.id - 1; this.toggleRating(clickedIndex); this.updateStates(this.allowHalf); } event.stopPropagation(); } toggleRating(index) { const isFull = this.rating === index + 1; const isHalf = this.rating === index + 0.5; if (this.allowHalf) { if (isFull) { this.rating = index; } else if (isHalf) { this.rating = index + 1; } else { this.rating = index + 0.5; } } else { if (isFull) { this.rating = index; } else { this.rating = index + 1; } } } updateStates(allowHalf) { this.ratingChange.emit(this.rating); this.rating = Math.round(this.rating * 2) / 2; this.states = Array.from({ length: this.scale }, (_, i) => { if (i < Math.floor(this.rating)) return State.Full; if (i === Math.floor(this.rating) && this.rating % 1 !== 0 && allowHalf) return State.Half; return State.Empty; }); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgRatingProComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: NgRatingProComponent, selector: "ngRatingPro", inputs: { scale: "scale", rating: "rating", allowHalf: "allowHalf", size: "size", spacing: "spacing", readonly: "readonly", iconName: "iconName" }, outputs: { ratingChange: "ratingChange" }, host: { listeners: { "click": "onClick($event)" } }, queries: [{ propertyName: "ratingDirectives", predicate: CustomRatingDirective }], viewQueries: [{ propertyName: "dynamicContainer", first: true, predicate: ["dynamicContainer"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: "<div\n [style.width]=\"containerWidth + 'px'\"\n [style.height]=\"size + 'px'\"\n class=\"rating-container\"\n>\n <!-- Define symbols -->\n <svg style=\"display: none\">\n <ng-container #dynamicContainer></ng-container>\n <ng-content select=\"half\"></ng-content>\n <ng-content select=\"full\"></ng-content>\n <ng-content select=\"empty\"></ng-content>\n </svg>\n\n <!-- Rating display -->\n <svg\n [attr.viewBox]=\"'0 0 ' + totalWidth + ' ' + starHeight\"\n [style.width]=\"'100%'\"\n [style.height]=\"'100%'\"\n aria-hidden=\"true\"\n focusable=\"false\"\n class=\"rating\"\n >\n <ng-container *ngFor=\"let state of states; let i = index\">\n <use\n [id]=\"i + 1\"\n [attr.x]=\"getStarPosition(i)\"\n [attr.y]=\"0\"\n [attr.width]=\"starWidth\"\n [attr.height]=\"starHeight\"\n [attr.xlink:href]=\"'#' + iconName + '-' + state\"\n [ngStyle]=\"{ cursor: !readonly ? 'pointer' : 'default' }\"\n />\n </ng-container>\n </svg>\n</div>\n", styles: [":host{-webkit-user-select:none;user-select:none}.rating-container{display:inline-block;position:relative}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgRatingProComponent, decorators: [{ type: Component, args: [{ selector: 'ngRatingPro', template: "<div\n [style.width]=\"containerWidth + 'px'\"\n [style.height]=\"size + 'px'\"\n class=\"rating-container\"\n>\n <!-- Define symbols -->\n <svg style=\"display: none\">\n <ng-container #dynamicContainer></ng-container>\n <ng-content select=\"half\"></ng-content>\n <ng-content select=\"full\"></ng-content>\n <ng-content select=\"empty\"></ng-content>\n </svg>\n\n <!-- Rating display -->\n <svg\n [attr.viewBox]=\"'0 0 ' + totalWidth + ' ' + starHeight\"\n [style.width]=\"'100%'\"\n [style.height]=\"'100%'\"\n aria-hidden=\"true\"\n focusable=\"false\"\n class=\"rating\"\n >\n <ng-container *ngFor=\"let state of states; let i = index\">\n <use\n [id]=\"i + 1\"\n [attr.x]=\"getStarPosition(i)\"\n [attr.y]=\"0\"\n [attr.width]=\"starWidth\"\n [attr.height]=\"starHeight\"\n [attr.xlink:href]=\"'#' + iconName + '-' + state\"\n [ngStyle]=\"{ cursor: !readonly ? 'pointer' : 'default' }\"\n />\n </ng-container>\n </svg>\n</div>\n", styles: [":host{-webkit-user-select:none;user-select:none}.rating-container{display:inline-block;position:relative}\n"] }] }], propDecorators: { scale: [{ type: Input }], rating: [{ type: Input }], allowHalf: [{ type: Input }], size: [{ type: Input }], spacing: [{ type: Input }], readonly: [{ type: Input }], iconName: [{ type: Input }], ratingDirectives: [{ type: ContentChildren, args: [CustomRatingDirective] }], dynamicContainer: [{ type: ViewChild, args: ['dynamicContainer', { read: ViewContainerRef, static: true }] }], ratingChange: [{ type: Output }], onClick: [{ type: HostListener, args: ['click', ['$event']] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmctcmF0aW5nLXByby5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZy1yYXRpbmctcHJvL3NyYy9saWIvbmctcmF0aW5nLXByby5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZy1yYXRpbmctcHJvL3NyYy9saWIvbmctcmF0aW5nLXByby5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUVULGVBQWUsRUFDZixZQUFZLEVBQ1osWUFBWSxFQUNaLEtBQUssRUFFTCxNQUFNLEVBRU4sU0FBUyxFQUNULGdCQUFnQixHQUNqQixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQztBQUM5RSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUN0RSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQzs7O0FBRXhFLE1BQU0sQ0FBTixJQUFZLEtBSVg7QUFKRCxXQUFZLEtBQUs7SUFDZix3QkFBZSxDQUFBO0lBQ2Ysc0JBQWEsQ0FBQTtJQUNiLHNCQUFhLENBQUE7QUFDZixDQUFDLEVBSlcsS0FBSyxLQUFMLEtBQUssUUFJaEI7QUFPRCxNQUFNLE9BQU8sb0JBQW9CO0lBTGpDO1FBTVcsVUFBSyxHQUFXLENBQUMsQ0FBQztRQUNsQixXQUFNLEdBQVcsQ0FBQyxDQUFDO1FBQ25CLGNBQVMsR0FBWSxJQUFJLENBQUM7UUFDMUIsU0FBSSxHQUFXLEVBQUUsQ0FBQyxDQUFDLGVBQWU7UUFDbEMsWUFBTyxHQUFXLENBQUMsQ0FBQyxDQUFDLHlDQUF5QztRQUM5RCxhQUFRLEdBQVksS0FBSyxDQUFDO1FBQzFCLGFBQVEsR0FBVyxNQUFNLENBQUM7UUFPekIsaUJBQVksR0FBeUIsSUFBSSxZQUFZLEVBQVUsQ0FBQztRQUVuRSxXQUFN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RyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUM7Z0JBQUUsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDO1lBQ25ELElBQUksQ0FBQyxLQUFLLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxLQUFLLENBQUMsSUFBSSxTQUFTO2dCQUNyRSxPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUM7WUFDcEIsT0FBTyxLQUFLLENBQUMsS0FBSyxDQUFDO1FBQ3JCLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQzsrR0FqSFUsb0JBQW9CO21HQUFwQixvQkFBb0Isd1VBU2QscUJBQXFCLDhIQUVDLGdCQUFnQiwyQ0N2Q3pELGloQ0FtQ0E7OzRGRFBhLG9CQUFvQjtrQkFMaEMsU0FBUzsrQkFDRSxhQUFhOzhCQUtkLEtBQUs7c0JBQWIsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUs7Z0JBQ0csU0FBUztzQkFBakIsS0FBSztnQkFDRyxJQUFJO3NCQUFaLEtBQUs7Z0JBQ0csT0FBTztzQkFBZixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csUUFBUTtzQkFBaEIsS0FBSztnQkFHTixnQkFBZ0I7c0JBRGYsZUFBZTt1QkFBQyxxQkFBcUI7Z0JBR3RDLGdCQUFnQjtzQkFEZixTQUFTO3VCQUFDLGtCQUFrQixFQUFFLEVBQUUsSUFBSSxFQUFFLGdCQUFnQixFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUU7Z0JBRzdELFlBQVk7c0JBQXJCLE1BQU07Z0JBMkRQLE9BQU87c0JBRE4sWUFBWTt1QkFBQyxPQUFPLEVBQUUsQ0FBQyxRQUFRLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDb21wb25lbnQsXG4gIENvbXBvbmVudEZhY3RvcnlSZXNvbHZlcixcbiAgQ29udGVudENoaWxkcmVuLFxuICBFdmVudEVtaXR0ZXIsXG4gIEhvc3RMaXN0ZW5lcixcbiAgSW5wdXQsXG4gIE9uSW5pdCxcbiAgT3V0cHV0LFxuICBRdWVyeUxpc3QsXG4gIFZpZXdDaGlsZCxcbiAgVmlld0NvbnRhaW5lclJlZixcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDdXN0b21SYXRpbmdEaXJlY3RpdmUgfSBmcm9tICcuL3JhdGluZy1pY29uL2N1c3RvbS1yYXRpbmcuZGlyZWN0aXZlJztcbmltcG9ydCB7IFN0YXJJY29uQ29tcG9uZW50IH0gZnJvbSAnLi9yYXRpbmctaWNvbi9zdGFyLWljb24uY29tcG9uZW50JztcbmltcG9ydCB7IEhlYXJ0SWNvbkNvbXBvbmVudCB9IGZyb20gJy4vcmF0aW5nLWljb24vaGVhcnQtaWNvbi5jb21wb25lbnQnO1xuXG5leHBvcnQgZW51bSBTdGF0ZSB7XG4gIEVtcHR5ID0gJ2VtcHR5JyxcbiAgSGFsZiA9ICdoYWxmJyxcbiAgRnVsbCA9ICdmdWxsJyxcbn1cblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnbmdSYXRpbmdQcm8nLFxuICB0ZW1wbGF0ZVVybDogJy4vbmctcmF0aW5nLXByby5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL25nLXJhdGluZy1wcm8uY29tcG9uZW50LmNzcyddLFxufSlcbmV4cG9ydCBjbGFzcyBOZ1JhdGluZ1Byb0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG4gIEBJbnB1dCgpIHNjYWxlOiBudW1iZXIgPSA1O1xuICBASW5wdXQoKSByYXRpbmc6IG51bWJlciA9IDA7XG4gIEBJbnB1dCgpIGFsbG93SGFsZjogYm9vbGVhbiA9IHRydWU7XG4gIEBJbnB1dCgpIHNpemU6IG51bWJlciA9IDIwOyAvLyBEZWZhdWx0IHNpemVcbiAgQElucHV0KCkgc3BhY2luZzogbnVtYmVyID0gODsgLy8gU3BhY2luZyBiZXR3ZWVuIHN0YXJzIGluIHZpZXdCb3ggdW5pdHNcbiAgQElucHV0KCkgcmVhZG9ubHk6IGJvb2xlYW4gPSBmYWxzZTtcbiAgQElucHV0KCkgaWNvbk5hbWU6IHN0cmluZyA9ICdzdGFyJztcblxuICBAQ29udGVudENoaWxkcmVuKEN1c3RvbVJhdGluZ0RpcmVjdGl2ZSlcbiAgcmF0aW5nRGlyZWN0aXZlcyE6IFF1ZXJ5TGlzdDxDdXN0b21SYXRpbmdEaXJlY3RpdmU+O1xuICBAVmlld0NoaWxkKCdkeW5hbWljQ29udGFpbmVyJywgeyByZWFkOiBWaWV3Q29udGFpbmVyUmVmLCBzdGF0aWM6IHRydWUgfSlcbiAgZHluYW1pY0NvbnRhaW5lciE6IFZpZXdDb250YWluZXJSZWY7XG5cbiAgQE91dHB1dCgpIHJhdGluZ0NoYW5nZTogRXZlbnRFbWl0dGVyPG51bWJlcj4gPSBuZXcgRXZlbnRFbWl0dGVyPG51bWJlcj4oKTtcblxuICBwdWJsaWMgc3RhdGVzOiBTdGF0ZVtdID0gW107XG5cbiAgc3RhcldpZHRoOiBudW1iZXIgPSAyNDtcbiAgc3RhckhlaWdodDogbnVtYmVyID0gMjQ7XG4gIGNvbnRhaW5lcldpZHRoOiBudW1iZXIgPSAwO1xuICB0b3RhbFdpZHRoOiBudW1iZXIgPSAwO1xuXG4gIG5nT25Jbml0KCkge1xuICAgIHRoaXMudXBkYXRlU3RhdGVzKHRoaXMuYWxsb3dIYWxmKTtcbiAgfVxuXG4gIG5nQWZ0ZXJDb250ZW50SW5pdCgpIHtcbiAgICBpZiAodGhpcy5yYXRpbmdEaXJlY3RpdmVzLmxlbmd0aCAhPT0gMykge1xuICAgICAgdGhpcy5sb2FkRHluYW1pY0NvbXBvbmVudCgpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnJhdGluZ0RpcmVjdGl2ZXMuZm9yRWFjaCgoZGlyZWN0aXZlKSA9PiB7XG4gICAgICAgIGRpcmVjdGl2ZS51cGRhdGVSYXRpbmcodGhpcy5pY29uTmFtZSk7XG4gICAgICB9KTtcbiAgICAgIHRoaXMuc3RhckhlaWdodCA9IHRoaXMucmF0aW5nRGlyZWN0aXZlcy5maXJzdC5pY29uVmlld0JveFszXTtcbiAgICAgIHRoaXMuc3RhcldpZHRoID0gdGhpcy5yYXRpbmdEaXJlY3RpdmVzLmZpcnN0Lmljb25WaWV3Qm94WzJdO1xuICAgIH1cbiAgICB0aGlzLnVwZGF0ZURpbWVuc2lvbnMoKTtcbiAgfVxuXG4gIHByaXZhdGUgbG9hZER5bmFtaWNDb21wb25lbnQoKSB7XG4gICAgY29uc3QgY29tcG9uZW50ID0gdGhpcy5nZXRDb21wb25lbnQoKTtcbiAgICB0aGlzLmR5bmFtaWNDb250YWluZXIuY2xlYXIoKTtcbiAgICB0aGlzLmR5bmFtaWNDb250YWluZXIuY3JlYXRlQ29tcG9uZW50KGNvbXBvbmVudCk7XG4gICAgdGhpcy5pY29uTmFtZSA9IGNvbXBvbmVudC5pY29uTmFtZTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0Q29tcG9uZW50KCkge1xuICAgIHN3aXRjaCAodGhpcy5pY29uTmFtZSkge1xuICAgICAgY2FzZSAnc3Rhcic6XG4gICAgICAgIHJldHVybiBTdGFySWNvbkNvbXBvbmVudDtcbiAgICAgIGNhc2UgJ2hlYXJ0JzpcbiAgICAgICAgcmV0dXJuIEhlYXJ0SWNvbkNvbXBvbmVudDtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiBTdGFySWNvbkNvbXBvbmVudDtcbiAgICB9XG4gIH1cblxuICB1cGRhdGVEaW1lbnNpb25zKCkge1xuICAgIC8vIENhbGN1bGF0ZSB0b3RhbCB3aWR0aCBpbiB2aWV3Qm94IHVuaXRzXG4gICAgdGhpcy50b3RhbFdpZHRoID1cbiAgICAgIHRoaXMuc3RhcldpZHRoICogdGhpcy5zY2FsZSArIHRoaXMuc3BhY2luZyAqICh0aGlzLnNjYWxlIC0gMSk7XG5cbiAgICAvLyBDYWxjdWxhdGUgY29udGFpbmVyIHdpZHRoIG1haW50YWluaW5nIGFzcGVjdCByYXRpb1xuICAgIGNvbnN0IGFzcGVjdFJhdGlvID0gdGhpcy50b3RhbFdpZHRoIC8gdGhpcy5zdGFySGVpZ2h0O1xuICAgIHRoaXMuY29udGFpbmVyV2lkdGggPSB0aGlzLnNpemUgKiBhc3BlY3RSYXRpbztcbiAgfVxuXG4gIGdldFN0YXJQb3NpdGlvbihpbmRleDogbnVtYmVyKTogbnVtYmVyIHtcbiAgICByZXR1cm4gaW5kZXggKiAodGhpcy5zdGFyV2lkdGggKyB0aGlzLnNwYWNpbmcpO1xuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcignY2xpY2snLCBbJyRldmVudCddKVxuICBvbkNsaWNrKGV2ZW50OiBNb3VzZUV2ZW50KSB7XG4gICAgaWYgKHRoaXMucmVhZG9ubHkpIHJldHVybjtcbiAgICBpZiAoZXZlbnQudGFyZ2V0IGluc3RhbmNlb2YgU1ZHRWxlbWVudCAmJiArZXZlbnQudGFyZ2V0LmlkID4gMCkge1xuICAgICAgY29uc3QgY2xpY2tlZEluZGV4ID0gK2V2ZW50LnRhcmdldC5pZCAtIDE7XG4gICAgICB0aGlzLnRvZ2dsZVJhdGluZyhjbGlja2VkSW5kZXgpO1xuICAgICAgdGhpcy51cGRhdGVTdGF0ZXModGhpcy5hbGxvd0hhbGYpO1xuICAgIH1cbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgfVxuXG4gIHByaXZhdGUgdG9nZ2xlUmF0aW5nKGluZGV4OiBudW1iZXIpIHtcbiAgICBjb25zdCBpc0Z1bGwgPSB0aGlzLnJhdGluZyA9PT0gaW5kZXggKyAxO1xuICAgIGNvbnN0IGlzSGFsZiA9IHRoaXMucmF0aW5nID09PSBpbmRleCArIDAuNTtcblxuICAgIGlmICh0aGlzLmFsbG93SGFsZikge1xuICAgICAgaWYgKGlzRnVsbCkge1xuICAgICAgICB0aGlzLnJhdGluZyA9IGluZGV4O1xuICAgICAgfSBlbHNlIGlmIChpc0hhbGYpIHtcbiAgICAgICAgdGhpcy5yYXRpbmcgPSBpbmRleCArIDE7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnJhdGluZyA9IGluZGV4ICsgMC41O1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBpZiAoaXNGdWxsKSB7XG4gICAgICAgIHRoaXMucmF0aW5nID0gaW5kZXg7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnJhdGluZyA9IGluZGV4ICsgMTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwdWJsaWMgdXBkYXRlU3RhdGVzKGFsbG93SGFsZjogYm9vbGVhbikge1xuICAgIHRoaXMucmF0aW5nQ2hhbmdlLmVtaXQodGhpcy5yYXRpbmcpO1xuICAgIHRoaXMucmF0aW5nID0gTWF0aC5yb3VuZCh0aGlzLnJhdGluZyAqIDIpIC8gMjtcbiAgICB0aGlzLnN0YXRlcyA9IEFycmF5LmZyb20oeyBsZW5ndGg6IHRoaXMuc2NhbGUgfSwgKF8sIGkpID0+IHtcbiAgICAgIGlmIChpIDwgTWF0aC5mbG9vcih0aGlzLnJhdGluZykpIHJldHVybiBTdGF0ZS5GdWxsO1xuICAgICAgaWYgKGkgPT09IE1hdGguZmxvb3IodGhpcy5yYXRpbmcpICYmIHRoaXMucmF0aW5nICUgMSAhPT0gMCAmJiBhbGxvd0hhbGYpXG4gICAgICAgIHJldHVybiBTdGF0ZS5IYWxmO1xuICAgICAgcmV0dXJuIFN0YXRlLkVtcHR5O1xuICAgIH0pO1xuICB9XG59XG4iLCI8ZGl2XG4gIFtzdHlsZS53aWR0aF09XCJjb250YWluZXJXaWR0aCArICdweCdcIlxuICBbc3R5bGUuaGVpZ2h0XT1cInNpemUgKyAncHgnXCJcbiAgY2xhc3M9XCJyYXRpbmctY29udGFpbmVyXCJcbj5cbiAgPCEtLSBEZWZpbmUgc3ltYm9scyAtLT5cbiAgPHN2ZyBzdHlsZT1cImRpc3BsYXk6IG5vbmVcIj5cbiAgICA8bmctY29udGFpbmVyICNkeW5hbWljQ29udGFpbmVyPjwvbmctY29udGFpbmVyPlxuICAgIDxuZy1jb250ZW50IHNlbGVjdD1cImhhbGZcIj48L25nLWNvbnRlbnQ+XG4gICAgPG5nLWNvbnRlbnQgc2VsZWN0PVwiZnVsbFwiPjwvbmctY29udGVudD5cbiAgICA8bmctY29udGVudCBzZWxlY3Q9XCJlbXB0eVwiPjwvbmctY29udGVudD5cbiAgPC9zdmc+XG5cbiAgPCEtLSBSYXRpbmcgZGlzcGxheSAtLT5cbiAgPHN2Z1xuICAgIFthdHRyLnZpZXdCb3hdPVwiJzAgMCAnICsgdG90YWxXaWR0aCArICcgJyArIHN0YXJIZWlnaHRcIlxuICAgIFtzdHlsZS53aWR0aF09XCInMTAwJSdcIlxuICAgIFtzdHlsZS5oZWlnaHRdPVwiJzEwMCUnXCJcbiAgICBhcmlhLWhpZGRlbj1cInRydWVcIlxuICAgIGZvY3VzYWJsZT1cImZhbHNlXCJcbiAgICBjbGFzcz1cInJhdGluZ1wiXG4gID5cbiAgICA8bmctY29udGFpbmVyICpuZ0Zvcj1cImxldCBzdGF0ZSBvZiBzdGF0ZXM7IGxldCBpID0gaW5kZXhcIj5cbiAgICAgIDx1c2VcbiAgICAgICAgW2lkXT1cImkgKyAxXCJcbiAgICAgICAgW2F0dHIueF09XCJnZXRTdGFyUG9zaXRpb24oaSlcIlxuICAgICAgICBbYXR0ci55XT1cIjBcIlxuICAgICAgICBbYXR0ci53aWR0aF09XCJzdGFyV2lkdGhcIlxuICAgICAgICBbYXR0ci5oZWlnaHRdPVwic3RhckhlaWdodFwiXG4gICAgICAgIFthdHRyLnhsaW5rOmhyZWZdPVwiJyMnICsgaWNvbk5hbWUgKyAnLScgKyBzdGF0ZVwiXG4gICAgICAgIFtuZ1N0eWxlXT1cInsgY3Vyc29yOiAhcmVhZG9ubHkgPyAncG9pbnRlcicgOiAnZGVmYXVsdCcgfVwiXG4gICAgICAvPlxuICAgIDwvbmctY29udGFpbmVyPlxuICA8L3N2Zz5cbjwvZGl2PlxuIl19