xng-breadcrumb
Version:
A declarative and reactive breadcrumb approach for Angular 6 and beyond https://www.npmjs.com/package/xng-breadcrumb
110 lines • 24.9 kB
JavaScript
import { Component, ContentChild, Input, TemplateRef, ViewEncapsulation, } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { map } from 'rxjs/operators';
import { BreadcrumbItemDirective } from './breadcrumb-item.directive';
import { BreadcrumbService } from './breadcrumb.service';
import * as i0 from "@angular/core";
import * as i1 from "./breadcrumb.service";
import * as i2 from "@angular/router";
import * as i3 from "@angular/common";
export class BreadcrumbComponent {
constructor(breadcrumbService, activateRoute) {
this.breadcrumbService = breadcrumbService;
this._separator = '/';
/**
* If true, breadcrumb is auto generated even without any mapping label
* Default label is same as route segment
*/
this.autoGenerate = true;
/**
* By default query params will be preserved with breadcrumbs
*/
this.preserveQueryParams = true;
/**
* By default query fragments will be preserved with breadcrumbs
*/
this.preserveFragment = true;
/**
* custom class provided by consumer to increase specificity
* This will benefit to override styles that are conflicting
*/
this.class = '';
this.setupMessage = 'not set up yet';
this.someParameterValue = null;
// breadcrumb inside ngIf works only this way
activateRoute.params.subscribe((params) => {
this.setupComponent(params['someParam']);
});
}
/**
* separator between breadcrumbs, defaults to '/'.
* User can customize separator either by passing a String or Template
*
* String --> Ex: <xng-breadcrumb separator="-"> </xng-breadcrumb>
*
* Template --> Ex: <xng-breadcrumb [separator]="separatorTemplate"> </xng-breadcrumb>
* <ng-template #separatorTemplate><mat-icon>arrow_right</mat-icon></ng-template>
*/
set separator(value) {
if (value instanceof TemplateRef) {
this.separatorTemplate = value;
this._separator = undefined;
}
else {
this.separatorTemplate = undefined;
this._separator = value || '/';
}
}
get separator() {
return this._separator;
}
setupComponent(someParam) {
this.setupMessage = 'set up at ' + new Date();
this.someParameterValue = someParam;
}
ngOnInit() {
this.breadcrumbs$ = this.breadcrumbService.breadcrumbs$.pipe(map((breadcrumbs) => {
return breadcrumbs
.filter((breadcrumb) => {
// Usually, breadcrumb list can contain a combination of auto generated and user specified labels
// this filters autogenerated labels in case of "[autoGenerate]: false"
if (this.autoGenerate) {
return true;
}
return !breadcrumb.isAutoGeneratedLabel;
})
.map((breadcrumb) => {
// Do not mutate breadcrumb as its source of truth.
// There can be scenarios where we can have multiple xng-breadcrumb instances in page
const { routeInterceptor, routeLink } = breadcrumb;
return {
...breadcrumb,
routeLink: routeInterceptor?.(routeLink, breadcrumb) || routeLink,
};
});
}));
}
}
BreadcrumbComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: BreadcrumbComponent, deps: [{ token: i1.BreadcrumbService }, { token: i2.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component });
BreadcrumbComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.0", type: BreadcrumbComponent, selector: "xng-breadcrumb", inputs: { autoGenerate: "autoGenerate", preserveQueryParams: "preserveQueryParams", preserveFragment: "preserveFragment", class: "class", anchorTarget: "anchorTarget", separator: "separator" }, queries: [{ propertyName: "itemTemplate", first: true, predicate: BreadcrumbItemDirective, descendants: true, read: TemplateRef }], ngImport: i0, template: "<nav aria-label=\"breadcrumb\" class=\"xng-breadcrumb-root\" [ngClass]=\"class\">\n <ol class=\"xng-breadcrumb-list\">\n <ng-container\n *ngFor=\"\n let breadcrumb of breadcrumbs$ | async;\n last as isLast;\n first as isFirst;\n index as index;\n count as count\n \"\n >\n <li class=\"xng-breadcrumb-item\">\n <a\n *ngIf=\"!isLast\"\n class=\"xng-breadcrumb-link\"\n [ngClass]=\"{ 'xng-breadcrumb-link-disabled': breadcrumb.disable }\"\n [attr.aria-disabled]=\"breadcrumb.disable\"\n [attr.tabIndex]=\"breadcrumb.disable ? -1 : 0\"\n role=\"button\"\n rel=\"noopener noreferrer\"\n [routerLink]=\"\n breadcrumb.routeInterceptor\n ? breadcrumb.routeInterceptor(breadcrumb.routeLink, breadcrumb)\n : breadcrumb.routeLink\n \"\n [queryParams]=\"\n preserveQueryParams ? breadcrumb.queryParams : undefined\n \"\n [fragment]=\"preserveFragment ? breadcrumb.fragment : undefined\"\n [target]=\"anchorTarget ? anchorTarget : '_self'\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n itemTemplate;\n context: {\n $implicit: breadcrumb.label,\n info: breadcrumb.info,\n last: isLast,\n first: isFirst,\n index: index,\n count: count\n }\n \"\n ></ng-container>\n <ng-container *ngIf=\"!itemTemplate\">{{\n breadcrumb.label\n }}</ng-container>\n </a>\n\n <label *ngIf=\"isLast\" class=\"xng-breadcrumb-trail\">\n <ng-container\n *ngTemplateOutlet=\"\n itemTemplate;\n context: {\n $implicit: breadcrumb.label,\n info: breadcrumb.info,\n last: isLast,\n first: isFirst,\n index: index,\n count: count\n }\n \"\n ></ng-container>\n <ng-container *ngIf=\"!itemTemplate\">{{\n breadcrumb.label\n }}</ng-container>\n </label>\n </li>\n\n <li *ngIf=\"!isLast\" class=\"xng-breadcrumb-separator\" aria-hidden=\"true\">\n <ng-container *ngTemplateOutlet=\"separatorTemplate\"></ng-container>\n <ng-container *ngIf=\"!separatorTemplate\">{{ separator }}</ng-container>\n </li>\n </ng-container>\n </ol>\n</nav>\n", styles: [".xng-breadcrumb-root{margin:0;color:#0009}.xng-breadcrumb-list{display:flex;align-items:center;flex-wrap:wrap;margin:0;padding:0}.xng-breadcrumb-item{list-style:none}.xng-breadcrumb-trail{display:flex;align-items:center;color:#000000e6}.xng-breadcrumb-link{display:flex;align-items:center;white-space:nowrap;color:inherit;text-decoration:none;transition:-webkit-text-decoration .3s;transition:text-decoration .3s;transition:text-decoration .3s,-webkit-text-decoration .3s;cursor:pointer}.xng-breadcrumb-link:hover{text-decoration:underline}.xng-breadcrumb-link-disabled{pointer-events:none;cursor:disabled}.xng-breadcrumb-separator{display:flex;-webkit-user-select:none;user-select:none;margin-left:8px;margin-right:8px}\n"], dependencies: [{ kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }], encapsulation: i0.ViewEncapsulation.None });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: BreadcrumbComponent, decorators: [{
type: Component,
args: [{ selector: 'xng-breadcrumb', encapsulation: ViewEncapsulation.None, template: "<nav aria-label=\"breadcrumb\" class=\"xng-breadcrumb-root\" [ngClass]=\"class\">\n <ol class=\"xng-breadcrumb-list\">\n <ng-container\n *ngFor=\"\n let breadcrumb of breadcrumbs$ | async;\n last as isLast;\n first as isFirst;\n index as index;\n count as count\n \"\n >\n <li class=\"xng-breadcrumb-item\">\n <a\n *ngIf=\"!isLast\"\n class=\"xng-breadcrumb-link\"\n [ngClass]=\"{ 'xng-breadcrumb-link-disabled': breadcrumb.disable }\"\n [attr.aria-disabled]=\"breadcrumb.disable\"\n [attr.tabIndex]=\"breadcrumb.disable ? -1 : 0\"\n role=\"button\"\n rel=\"noopener noreferrer\"\n [routerLink]=\"\n breadcrumb.routeInterceptor\n ? breadcrumb.routeInterceptor(breadcrumb.routeLink, breadcrumb)\n : breadcrumb.routeLink\n \"\n [queryParams]=\"\n preserveQueryParams ? breadcrumb.queryParams : undefined\n \"\n [fragment]=\"preserveFragment ? breadcrumb.fragment : undefined\"\n [target]=\"anchorTarget ? anchorTarget : '_self'\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n itemTemplate;\n context: {\n $implicit: breadcrumb.label,\n info: breadcrumb.info,\n last: isLast,\n first: isFirst,\n index: index,\n count: count\n }\n \"\n ></ng-container>\n <ng-container *ngIf=\"!itemTemplate\">{{\n breadcrumb.label\n }}</ng-container>\n </a>\n\n <label *ngIf=\"isLast\" class=\"xng-breadcrumb-trail\">\n <ng-container\n *ngTemplateOutlet=\"\n itemTemplate;\n context: {\n $implicit: breadcrumb.label,\n info: breadcrumb.info,\n last: isLast,\n first: isFirst,\n index: index,\n count: count\n }\n \"\n ></ng-container>\n <ng-container *ngIf=\"!itemTemplate\">{{\n breadcrumb.label\n }}</ng-container>\n </label>\n </li>\n\n <li *ngIf=\"!isLast\" class=\"xng-breadcrumb-separator\" aria-hidden=\"true\">\n <ng-container *ngTemplateOutlet=\"separatorTemplate\"></ng-container>\n <ng-container *ngIf=\"!separatorTemplate\">{{ separator }}</ng-container>\n </li>\n </ng-container>\n </ol>\n</nav>\n", styles: [".xng-breadcrumb-root{margin:0;color:#0009}.xng-breadcrumb-list{display:flex;align-items:center;flex-wrap:wrap;margin:0;padding:0}.xng-breadcrumb-item{list-style:none}.xng-breadcrumb-trail{display:flex;align-items:center;color:#000000e6}.xng-breadcrumb-link{display:flex;align-items:center;white-space:nowrap;color:inherit;text-decoration:none;transition:-webkit-text-decoration .3s;transition:text-decoration .3s;transition:text-decoration .3s,-webkit-text-decoration .3s;cursor:pointer}.xng-breadcrumb-link:hover{text-decoration:underline}.xng-breadcrumb-link-disabled{pointer-events:none;cursor:disabled}.xng-breadcrumb-separator{display:flex;-webkit-user-select:none;user-select:none;margin-left:8px;margin-right:8px}\n"] }]
}], ctorParameters: function () { return [{ type: i1.BreadcrumbService }, { type: i2.ActivatedRoute }]; }, propDecorators: { itemTemplate: [{
type: ContentChild,
args: [BreadcrumbItemDirective, { static: false, read: TemplateRef }]
}], autoGenerate: [{
type: Input
}], preserveQueryParams: [{
type: Input
}], preserveFragment: [{
type: Input
}], class: [{
type: Input
}], anchorTarget: [{
type: Input
}], separator: [{
type: Input,
args: ['separator']
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnJlYWRjcnVtYi5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9saWJzL3huZy1icmVhZGNydW1iL3NyYy9saWIvYnJlYWRjcnVtYi5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9saWJzL3huZy1icmVhZGNydW1iL3NyYy9saWIvYnJlYWRjcnVtYi5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUNULFlBQVksRUFDWixLQUFLLEVBRUwsV0FBVyxFQUNYLGlCQUFpQixHQUNsQixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFakQsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3JDLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ3RFLE9BQU8sRUFBd0IsaUJBQWlCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQzs7Ozs7QUFRL0UsTUFBTSxPQUFPLG1CQUFtQjtJQXFFOUIsWUFDVSxpQkFBb0MsRUFDNUMsYUFBNkI7UUFEckIsc0JBQWlCLEdBQWpCLGlCQUFpQixDQUFtQjtRQW5FdEMsZUFBVSxHQUFHLEdBQUcsQ0FBQztRQWF6Qjs7O1dBR0c7UUFDTSxpQkFBWSxHQUFHLElBQUksQ0FBQztRQUU3Qjs7V0FFRztRQUNNLHdCQUFtQixHQUFHLElBQUksQ0FBQztRQUVwQzs7V0FFRztRQUNNLHFCQUFnQixHQUFHLElBQUksQ0FBQztRQUVqQzs7O1dBR0c7UUFDTSxVQUFLLEdBQUcsRUFBRSxDQUFDO1FBOEJwQixpQkFBWSxHQUFHLGdCQUFnQixDQUFDO1FBQ2hDLHVCQUFrQixHQUFHLElBQUksQ0FBQztRQU14Qiw2Q0FBNkM7UUFDN0MsYUFBYSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRTtZQUN4QyxJQUFJLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDO1FBQzNDLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQWxDRDs7Ozs7Ozs7T0FRRztJQUNILElBQ0ksU0FBUyxDQUFDLEtBQWlDO1FBQzdDLElBQUksS0FBSyxZQUFZLFdBQVcsRUFBRTtZQUNoQyxJQUFJLENBQUMsaUJBQWlCLEdBQUcsS0FBSyxDQUFDO1lBQy9CLElBQUksQ0FBQyxVQUFVLEdBQUcsU0FBUyxDQUFDO1NBQzdCO2FBQU07WUFDTCxJQUFJLENBQUMsaUJBQWlCLEdBQUcsU0FBUyxDQUFDO1lBQ25DLElBQUksQ0FBQyxVQUFVLEdBQUcsS0FBSyxJQUFJLEdBQUcsQ0FBQztTQUNoQztJQUNILENBQUM7SUFDRCxJQUFJLFNBQVM7UUFDWCxPQUFPLElBQUksQ0FBQyxVQUFVLENBQUM7SUFDekIsQ0FBQztJQWVELGNBQWMsQ0FBQyxTQUFTO1FBQ3RCLElBQUksQ0FBQyxZQUFZLEdBQUcsWUFBWSxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7UUFDOUMsSUFBSSxDQUFDLGtCQUFrQixHQUFHLFNBQVMsQ0FBQztJQUN0QyxDQUFDO0lBRUQsUUFBUTtRQUNOLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLFlBQVksQ0FBQyxJQUFJLENBQzFELEdBQUcsQ0FBQyxDQUFDLFdBQW1DLEVBQUUsRUFBRTtZQUMxQyxPQUFPLFdBQVc7aUJBQ2YsTUFBTSxDQUFDLENBQUMsVUFBZ0MsRUFBRSxFQUFFO2dCQUMzQyxpR0FBaUc7Z0JBQ2pHLHVFQUF1RTtnQkFDdkUsSUFBSSxJQUFJLENBQUMsWUFBWSxFQUFFO29CQUNyQixPQUFPLElBQUksQ0FBQztpQkFDYjtnQkFDRCxPQUFPLENBQUMsVUFBVSxDQUFDLG9CQUFvQixDQUFDO1lBQzFDLENBQUMsQ0FBQztpQkFDRCxHQUFHLENBQUMsQ0FBQyxVQUFnQyxFQUFFLEVBQUU7Z0JBQ3hDLG1EQUFtRDtnQkFDbkQscUZBQXFGO2dCQUNyRixNQUFNLEVBQUUsZ0JBQWdCLEVBQUUsU0FBUyxFQUFFLEdBQUcsVUFBVSxDQUFDO2dCQUNuRCxPQUFPO29CQUNMLEdBQUcsVUFBVTtvQkFDYixTQUFTLEVBQUUsZ0JBQWdCLEVBQUUsQ0FBQyxTQUFTLEVBQUUsVUFBVSxDQUFDLElBQUksU0FBUztpQkFDbEUsQ0FBQztZQUNKLENBQUMsQ0FBQyxDQUFDO1FBQ1AsQ0FBQyxDQUFDLENBQ0gsQ0FBQztJQUNKLENBQUM7O2dIQTNHVSxtQkFBbUI7b0dBQW5CLG1CQUFtQixrU0FhaEIsdUJBQXVCLDJCQUF5QixXQUFXLDZCQ2pDM0Usa2hGQTRFQTsyRkR4RGEsbUJBQW1CO2tCQU4vQixTQUFTOytCQUNFLGdCQUFnQixpQkFHWCxpQkFBaUIsQ0FBQyxJQUFJO3FJQWdCckMsWUFBWTtzQkFEWCxZQUFZO3VCQUFDLHVCQUF1QixFQUFFLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFO2dCQU9sRSxZQUFZO3NCQUFwQixLQUFLO2dCQUtHLG1CQUFtQjtzQkFBM0IsS0FBSztnQkFLRyxnQkFBZ0I7c0JBQXhCLEtBQUs7Z0JBTUcsS0FBSztzQkFBYixLQUFLO2dCQUtHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBWUYsU0FBUztzQkFEWixLQUFLO3VCQUFDLFdBQVciLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDb21wb25lbnQsXG4gIENvbnRlbnRDaGlsZCxcbiAgSW5wdXQsXG4gIE9uSW5pdCxcbiAgVGVtcGxhdGVSZWYsXG4gIFZpZXdFbmNhcHN1bGF0aW9uLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEFjdGl2YXRlZFJvdXRlIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IE9ic2VydmFibGUgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IG1hcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IEJyZWFkY3J1bWJJdGVtRGlyZWN0aXZlIH0gZnJvbSAnLi9icmVhZGNydW1iLWl0ZW0uZGlyZWN0aXZlJztcbmltcG9ydCB7IEJyZWFkY3J1bWJEZWZpbml0aW9uLCBCcmVhZGNydW1iU2VydmljZSB9IGZyb20gJy4vYnJlYWRjcnVtYi5zZXJ2aWNlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAneG5nLWJyZWFkY3J1bWInLFxuICB0ZW1wbGF0ZVVybDogJy4vYnJlYWRjcnVtYi5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL2JyZWFkY3J1bWIuY29tcG9uZW50LmNzcyddLFxuICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lLFxufSlcbmV4cG9ydCBjbGFzcyBCcmVhZGNydW1iQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcbiAgYnJlYWRjcnVtYnMkOiBPYnNlcnZhYmxlPEJyZWFkY3J1bWJEZWZpbml0aW9uW10+O1xuICBzZXBhcmF0b3JUZW1wbGF0ZTogVGVtcGxhdGVSZWY8dm9pZD47XG4gIHByaXZhdGUgX3NlcGFyYXRvciA9ICcvJztcblxuICAvKipcbiAgICogQnJlYWRjcnVtYiBpdGVtIGNhbiBiZSBjdXN0b21pemVkIHdpdGggdGhpcyB0ZW1wbGF0ZVxuICAgKiBUZW1wbGF0ZSBjb250ZXh0IGlzIHByb3ZpZGVkIGxhYmVsLCBhZGRpdGlvbmFsIGluZm8sIGZpcnN0IGFuZCBsYXN0IGluZGV4ZXNcbiAgICogVXNlIGNhc2VzOlxuICAgKiAxKSBBZGQgYW4gaWNvbiBhbG9uZyB3aXRoIGxhYmVsXG4gICAqIDIpIGkxOG4uIHt7YnJlYWRjcnVtYiB8IHRyYW5zbGF0ZX19IG9yIHt7YnJlYWRjcnVtYiB8IHRyYW5zbG9jb319XG4gICAqIDMpIENoYW5nZSB0ZXh0IGNhc2Uge3ticmVhZGNydW1iIHwgdGl0bGVjYXNlfX1cbiAgICovXG4gIEBDb250ZW50Q2hpbGQoQnJlYWRjcnVtYkl0ZW1EaXJlY3RpdmUsIHsgc3RhdGljOiBmYWxzZSwgcmVhZDogVGVtcGxhdGVSZWYgfSlcbiAgaXRlbVRlbXBsYXRlO1xuXG4gIC8qKlxuICAgKiBJZiB0cnVlLCBicmVhZGNydW1iIGlzIGF1dG8gZ2VuZXJhdGVkIGV2ZW4gd2l0aG91dCBhbnkgbWFwcGluZyBsYWJlbFxuICAgKiBEZWZhdWx0IGxhYmVsIGlzIHNhbWUgYXMgcm91dGUgc2VnbWVudFxuICAgKi9cbiAgQElucHV0KCkgYXV0b0dlbmVyYXRlID0gdHJ1ZTtcblxuICAvKipcbiAgICogQnkgZGVmYXVsdCBxdWVyeSBwYXJhbXMgd2lsbCBiZSBwcmVzZXJ2ZWQgd2l0aCBicmVhZGNydW1ic1xuICAgKi9cbiAgQElucHV0KCkgcHJlc2VydmVRdWVyeVBhcmFtcyA9IHRydWU7XG5cbiAgLyoqXG4gICAqIEJ5IGRlZmF1bHQgcXVlcnkgZnJhZ21lbnRzIHdpbGwgYmUgcHJlc2VydmVkIHdpdGggYnJlYWRjcnVtYnNcbiAgICovXG4gIEBJbnB1dCgpIHByZXNlcnZlRnJhZ21lbnQgPSB0cnVlO1xuXG4gIC8qKlxuICAgKiBjdXN0b20gY2xhc3MgcHJvdmlkZWQgYnkgY29uc3VtZXIgdG8gaW5jcmVhc2Ugc3BlY2lmaWNpdHlcbiAgICogVGhpcyB3aWxsIGJlbmVmaXQgdG8gb3ZlcnJpZGUgc3R5bGVzIHRoYXQgYXJlIGNvbmZsaWN0aW5nXG4gICAqL1xuICBASW5wdXQoKSBjbGFzcyA9ICcnO1xuXG4gIC8qKlxuICAgKiBhbmNob3JUYXJnZXQgPSBcIl9ibGFua1wiIG1ha2VzIHRoZSBicmVhZGNydW1iIGxpbmsgb3BlbiBpbiBhIG5ldyB0YWJcbiAgICovXG4gIEBJbnB1dCgpIGFuY2hvclRhcmdldDogJ19ibGFuaycgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIHNlcGFyYXRvciBiZXR3ZWVuIGJyZWFkY3J1bWJzLCBkZWZhdWx0cyB0byAnLycuXG4gICAqIFVzZXIgY2FuIGN1c3RvbWl6ZSBzZXBhcmF0b3IgZWl0aGVyIGJ5IHBhc3NpbmcgYSBTdHJpbmcgb3IgVGVtcGxhdGVcbiAgICpcbiAgICogU3RyaW5nIC0tPiBFeDogPHhuZy1icmVhZGNydW1iIHNlcGFyYXRvcj1cIi1cIj4gPC94bmctYnJlYWRjcnVtYj5cbiAgICpcbiAgICogVGVtcGxhdGUgLS0+IEV4OiA8eG5nLWJyZWFkY3J1bWIgW3NlcGFyYXRvcl09XCJzZXBhcmF0b3JUZW1wbGF0ZVwiPiA8L3huZy1icmVhZGNydW1iPlxuICAgKiA8bmctdGVtcGxhdGUgI3NlcGFyYXRvclRlbXBsYXRlPjxtYXQtaWNvbj5hcnJvd19yaWdodDwvbWF0LWljb24+PC9uZy10ZW1wbGF0ZT5cbiAgICovXG4gIEBJbnB1dCgnc2VwYXJhdG9yJylcbiAgc2V0IHNlcGFyYXRvcih2YWx1ZTogc3RyaW5nIHwgVGVtcGxhdGVSZWY8dm9pZD4pIHtcbiAgICBpZiAodmFsdWUgaW5zdGFuY2VvZiBUZW1wbGF0ZVJlZikge1xuICAgICAgdGhpcy5zZXBhcmF0b3JUZW1wbGF0ZSA9IHZhbHVlO1xuICAgICAgdGhpcy5fc2VwYXJhdG9yID0gdW5kZWZpbmVkO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnNlcGFyYXRvclRlbXBsYXRlID0gdW5kZWZpbmVkO1xuICAgICAgdGhpcy5fc2VwYXJhdG9yID0gdmFsdWUgfHwgJy8nO1xuICAgIH1cbiAgfVxuICBnZXQgc2VwYXJhdG9yKCkge1xuICAgIHJldHVybiB0aGlzLl9zZXBhcmF0b3I7XG4gIH1cblxuICBzZXR1cE1lc3NhZ2UgPSAnbm90IHNldCB1cCB5ZXQnO1xuICBzb21lUGFyYW1ldGVyVmFsdWUgPSBudWxsO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgYnJlYWRjcnVtYlNlcnZpY2U6IEJyZWFkY3J1bWJTZXJ2aWNlLFxuICAgIGFjdGl2YXRlUm91dGU6IEFjdGl2YXRlZFJvdXRlXG4gICkge1xuICAgIC8vIGJyZWFkY3J1bWIgaW5zaWRlIG5nSWYgd29ya3Mgb25seSB0aGlzIHdheVxuICAgIGFjdGl2YXRlUm91dGUucGFyYW1zLnN1YnNjcmliZSgocGFyYW1zKSA9PiB7XG4gICAgICB0aGlzLnNldHVwQ29tcG9uZW50KHBhcmFtc1snc29tZVBhcmFtJ10pO1xuICAgIH0pO1xuICB9XG5cbiAgc2V0dXBDb21wb25lbnQoc29tZVBhcmFtKSB7XG4gICAgdGhpcy5zZXR1cE1lc3NhZ2UgPSAnc2V0IHVwIGF0ICcgKyBuZXcgRGF0ZSgpO1xuICAgIHRoaXMuc29tZVBhcmFtZXRlclZhbHVlID0gc29tZVBhcmFtO1xuICB9XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgdGhpcy5icmVhZGNydW1icyQgPSB0aGlzLmJyZWFkY3J1bWJTZXJ2aWNlLmJyZWFkY3J1bWJzJC5waXBlKFxuICAgICAgbWFwKChicmVhZGNydW1iczogQnJlYWRjcnVtYkRlZmluaXRpb25bXSkgPT4ge1xuICAgICAgICByZXR1cm4gYnJlYWRjcnVtYnNcbiAgICAgICAgICAuZmlsdGVyKChicmVhZGNydW1iOiBCcmVhZGNydW1iRGVmaW5pdGlvbikgPT4ge1xuICAgICAgICAgICAgLy8gVXN1YWxseSwgYnJlYWRjcnVtYiBsaXN0IGNhbiBjb250YWluIGEgY29tYmluYXRpb24gb2YgYXV0byBnZW5lcmF0ZWQgYW5kIHVzZXIgc3BlY2lmaWVkIGxhYmVsc1xuICAgICAgICAgICAgLy8gdGhpcyBmaWx0ZXJzIGF1dG9nZW5lcmF0ZWQgbGFiZWxzIGluIGNhc2Ugb2YgXCJbYXV0b0dlbmVyYXRlXTogZmFsc2VcIlxuICAgICAgICAgICAgaWYgKHRoaXMuYXV0b0dlbmVyYXRlKSB7XG4gICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuICFicmVhZGNydW1iLmlzQXV0b0dlbmVyYXRlZExhYmVsO1xuICAgICAgICAgIH0pXG4gICAgICAgICAgLm1hcCgoYnJlYWRjcnVtYjogQnJlYWRjcnVtYkRlZmluaXRpb24pID0+IHtcbiAgICAgICAgICAgIC8vIERvIG5vdCBtdXRhdGUgYnJlYWRjcnVtYiBhcyBpdHMgc291cmNlIG9mIHRydXRoLlxuICAgICAgICAgICAgLy8gVGhlcmUgY2FuIGJlIHNjZW5hcmlvcyB3aGVyZSB3ZSBjYW4gaGF2ZSBtdWx0aXBsZSB4bmctYnJlYWRjcnVtYiBpbnN0YW5jZXMgaW4gcGFnZVxuICAgICAgICAgICAgY29uc3QgeyByb3V0ZUludGVyY2VwdG9yLCByb3V0ZUxpbmsgfSA9IGJyZWFkY3J1bWI7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAuLi5icmVhZGNydW1iLFxuICAgICAgICAgICAgICByb3V0ZUxpbms6IHJvdXRlSW50ZXJjZXB0b3I/Lihyb3V0ZUxpbmssIGJyZWFkY3J1bWIpIHx8IHJvdXRlTGluayxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfSk7XG4gICAgICB9KVxuICAgICk7XG4gIH1cbn1cbiIsIjxuYXYgYXJpYS1sYWJlbD1cImJyZWFkY3J1bWJcIiBjbGFzcz1cInhuZy1icmVhZGNydW1iLXJvb3RcIiBbbmdDbGFzc109XCJjbGFzc1wiPlxuICA8b2wgY2xhc3M9XCJ4bmctYnJlYWRjcnVtYi1saXN0XCI+XG4gICAgPG5nLWNvbnRhaW5lclxuICAgICAgKm5nRm9yPVwiXG4gICAgICAgIGxldCBicmVhZGNydW1iIG9mIGJyZWFkY3J1bWJzJCB8IGFzeW5jO1xuICAgICAgICBsYXN0IGFzIGlzTGFzdDtcbiAgICAgICAgZmlyc3QgYXMgaXNGaXJzdDtcbiAgICAgICAgaW5kZXggYXMgaW5kZXg7XG4gICAgICAgIGNvdW50IGFzIGNvdW50XG4gICAgICBcIlxuICAgID5cbiAgICAgIDxsaSBjbGFzcz1cInhuZy1icmVhZGNydW1iLWl0ZW1cIj5cbiAgICAgICAgPGFcbiAgICAgICAgICAqbmdJZj1cIiFpc0xhc3RcIlxuICAgICAgICAgIGNsYXNzPVwieG5nLWJyZWFkY3J1bWItbGlua1wiXG4gICAgICAgICAgW25nQ2xhc3NdPVwieyAneG5nLWJyZWFkY3J1bWItbGluay1kaXNhYmxlZCc6IGJyZWFkY3J1bWIuZGlzYWJsZSB9XCJcbiAgICAgICAgICBbYXR0ci5hcmlhLWRpc2FibGVkXT1cImJyZWFkY3J1bWIuZGlzYWJsZVwiXG4gICAgICAgICAgW2F0dHIudGFiSW5kZXhdPVwiYnJlYWRjcnVtYi5kaXNhYmxlID8gLTEgOiAwXCJcbiAgICAgICAgICByb2xlPVwiYnV0dG9uXCJcbiAgICAgICAgICByZWw9XCJub29wZW5lciBub3JlZmVycmVyXCJcbiAgICAgICAgICBbcm91dGVyTGlua109XCJcbiAgICAgICAgICAgIGJyZWFkY3J1bWIucm91dGVJbnRlcmNlcHRvclxuICAgICAgICAgICAgICA/IGJyZWFkY3J1bWIucm91dGVJbnRlcmNlcHRvcihicmVhZGNydW1iLnJvdXRlTGluaywgYnJlYWRjcnVtYilcbiAgICAgICAgICAgICAgOiBicmVhZGNydW1iLnJvdXRlTGlua1xuICAgICAgICAgIFwiXG4gICAgICAgICAgW3F1ZXJ5UGFyYW1zXT1cIlxuICAgICAgICAgICAgcHJlc2VydmVRdWVyeVBhcmFtcyA/IGJyZWFkY3J1bWIucXVlcnlQYXJhbXMgOiB1bmRlZmluZWRcbiAgICAgICAgICBcIlxuICAgICAgICAgIFtmcmFnbWVudF09XCJwcmVzZXJ2ZUZyYWdtZW50ID8gYnJlYWRjcnVtYi5mcmFnbWVudCA6IHVuZGVmaW5lZFwiXG4gICAgICAgICAgW3RhcmdldF09XCJhbmNob3JUYXJnZXQgPyBhbmNob3JUYXJnZXQgOiAnX3NlbGYnXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxuZy1jb250YWluZXJcbiAgICAgICAgICAgICpuZ1RlbXBsYXRlT3V0bGV0PVwiXG4gICAgICAgICAgICAgIGl0ZW1UZW1wbGF0ZTtcbiAgICAgICAgICAgICAgY29udGV4dDoge1xuICAgICAgICAgICAgICAgICRpbXBsaWNpdDogYnJlYWRjcnVtYi5sYWJlbCxcbiAgICAgICAgICAgICAgICBpbmZvOiBicmVhZGNydW1iLmluZm8sXG4gICAgICAgICAgICAgICAgbGFzdDogaXNMYXN0LFxuICAgICAgICAgICAgICAgIGZpcnN0OiBpc0ZpcnN0LFxuICAgICAgICAgICAgICAgIGluZGV4OiBpbmRleCxcbiAgICAgICAgICAgICAgICBjb3VudDogY291bnRcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgXCJcbiAgICAgICAgICA+PC9uZy1jb250YWluZXI+XG4gICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIiFpdGVtVGVtcGxhdGVcIj57e1xuICAgICAgICAgICAgYnJlYWRjcnVtYi5sYWJlbFxuICAgICAgICAgIH19PC9uZy1jb250YWluZXI+XG4gICAgICAgIDwvYT5cblxuICAgICAgICA8bGFiZWwgKm5nSWY9XCJpc0xhc3RcIiBjbGFzcz1cInhuZy1icmVhZGNydW1iLXRyYWlsXCI+XG4gICAgICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICAgICAgKm5nVGVtcGxhdGVPdXRsZXQ9XCJcbiAgICAgICAgICAgICAgaXRlbVRlbXBsYXRlO1xuICAgICAgICAgICAgICBjb250ZXh0OiB7XG4gICAgICAgICAgICAgICAgJGltcGxpY2l0OiBicmVhZGNydW1iLmxhYmVsLFxuICAgICAgICAgICAgICAgIGluZm86IGJyZWFkY3J1bWIuaW5mbyxcbiAgICAgICAgICAgICAgICBsYXN0OiBpc0xhc3QsXG4gICAgICAgICAgICAgICAgZmlyc3Q6IGlzRmlyc3QsXG4gICAgICAgICAgICAgICAgaW5kZXg6IGluZGV4LFxuICAgICAgICAgICAgICAgIGNvdW50OiBjb3VudFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICBcIlxuICAgICAgICAgID48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiIWl0ZW1UZW1wbGF0ZVwiPnt7XG4gICAgICAgICAgICBicmVhZGNydW1iLmxhYmVsXG4gICAgICAgICAgfX08L25nLWNvbnRhaW5lcj5cbiAgICAgICAgPC9sYWJlbD5cbiAgICAgIDwvbGk+XG5cbiAgICAgIDxsaSAqbmdJZj1cIiFpc0xhc3RcIiBjbGFzcz1cInhuZy1icmVhZGNydW1iLXNlcGFyYXRvclwiIGFyaWEtaGlkZGVuPVwidHJ1ZVwiPlxuICAgICAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwic2VwYXJhdG9yVGVtcGxhdGVcIj48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIiFzZXBhcmF0b3JUZW1wbGF0ZVwiPnt7IHNlcGFyYXRvciB9fTwvbmctY29udGFpbmVyPlxuICAgICAgPC9saT5cbiAgICA8L25nLWNvbnRhaW5lcj5cbiAgPC9vbD5cbjwvbmF2PlxuIl19