@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
172 lines • 20.3 kB
JavaScript
import { Component, Input, Optional, Output, EventEmitter, HostListener } from '@angular/core';
import { BsModalRef } from 'ngx-bootstrap/modal';
import { gettext } from '../i18n/gettext';
import { isEmpty } from 'lodash';
import * as i0 from "@angular/core";
import * as i1 from "ngx-bootstrap/modal";
import * as i2 from "@angular/common";
import * as i3 from "../i18n/c8y-translate.pipe";
/**
* C8Y component for creating modals.
*
* Creating custom modal:
* ```typescript
* import { Component } from "@angular/core";
* import { Subject } from 'rxjs';
*
* @Component({
* selector: "my-modal",
* template: `
* <c8y-modal title="CustomTitle"
* (onClose)="onClose($event)"
* (onDismiss)="onDismiss($event)"
* [labels]="labels"
* [disabled]="true" <- will disable ok button
* >
* <span>I am body of modal</span>
* <span>For simple string use body="string"</span>
* </c8y-modal>`
* })
*
* export class MyModalComponent {
*
* closeSubject: Subject<boolean> = new Subject();
* labels : ModalLabels = {ok: "customOK", cancel: "customCancel"};
*
* onDismiss(event){
* this.closeSubject.next(false);
* }
*
* onClose(event) {
* this.closeSubject.next(true);
* }
* }
* ```
*
* Showing modal:
* ```typescript
* import { BsModalService } from "ngx-bootstrap/modal";
*
* constructor(
* public bsModalService: BsModalService,
* ) {}
*
* showModal() {
* const modalRef = this.bsModalService.show(MyModalComponent);
* modalRef.content.closeSubject.subscribe(result => {
* console.log('results:', result);
* });
* }
* ```
*/
export class ModalComponent {
/**
* Custom labels for 'cancel' and 'ok' buttons.
*/
set labels({ ok, cancel }) {
this._labels = { ok, cancel };
}
get labels() {
return this._labels;
}
constructor(modal) {
this.modal = modal;
/**
* Emits 'true' when 'cancel' button is clicked.
*/
this.onDismiss = new EventEmitter();
/**
* Emits 'true' when 'ok' button is clicked.
*/
this.onClose = new EventEmitter();
/**
* Indicates if the 'ok' (confirmation) button is disabled.
*/
this.disabled = false;
/**
* Indicates if modal should use custom footer provided with content projection (or no footer at all).
* If false, default footer with 'cancel' and 'ok' buttons will be displayed.
*/
this.customFooter = false;
/**
* CSS classes for modal header.
*/
this.headerClasses = '';
this._labels = { ok: gettext('OK'), cancel: gettext('Cancel') };
}
/**
* Hides modal or calls 'dismiss' input callback, then emits 'onDismiss' output.
* Method is called when 'cancel' button is clicked, but can be also triggered by accessing 'ModalComponent' instance.
*/
_dismiss() {
let fn = this.dismiss;
if (!fn && this.modal) {
fn = () => this.modal.hide();
}
if (fn) {
fn();
}
this.onDismiss.emit(true);
}
/**
* Hides modal or calls 'close' input callback, then emits 'onClose' output.
* Method is called when 'ok' button is clicked, but can be also triggered by accessing 'ModalComponent' instance.
*/
_close() {
let fn = this.close;
if (!fn && this.modal) {
fn = () => this.modal.hide();
}
if (fn) {
fn();
}
this.onClose.emit(true);
}
/**
* 'Enter' keyboard button handler. Calls '_dismiss' or '_close' method when only one corresponding button exists.
* @param _event Enter keydown event
*/
onEnterKeyDown(_event) {
const hasOnlyOneButton = isEmpty(this.labels.ok) !== isEmpty(this.labels.cancel);
const isCancelClickable = !this.customFooter && this.labels.cancel;
const isOkClickable = !this.customFooter && !this.disabled && this.labels.ok;
if (hasOnlyOneButton && isCancelClickable) {
this._dismiss();
}
if (hasOnlyOneButton && isOkClickable) {
this._close();
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ModalComponent, deps: [{ token: i1.BsModalRef, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: ModalComponent, selector: "c8y-modal", inputs: { disabled: "disabled", close: "close", dismiss: "dismiss", title: "title", body: "body", customFooter: "customFooter", headerClasses: "headerClasses", labels: "labels" }, outputs: { onDismiss: "onDismiss", onClose: "onClose" }, host: { listeners: { "document:keydown.enter": "onEnterKeyDown($event)" } }, ngImport: i0, template: "<div class=\"viewport-modal\">\n <div class=\"modal-header {{ headerClasses }}\" [ngClass]=\"{ separator: title }\">\n <ng-content select=\"[c8y-modal-title]\"></ng-content>\n <div [hidden]=\"!title\" id=\"modal-title\" class=\"modal-title\">\n {{ title | translate }}\n </div>\n </div>\n <div class=\"modal-inner-scroll\" id=\"modal-body\">\n <div [ngClass]=\"{ 'modal-body': !customFooter, 'd-contents': customFooter }\">\n <p *ngIf=\"title\" class=\"text-center text-break-word\">\n {{ body }}\n </p>\n <ng-content></ng-content>\n </div>\n </div>\n <ng-content select=\"[c8y-modal-footer-custom]\"></ng-content>\n <div class=\"modal-footer\" *ngIf=\"!customFooter\">\n <ng-content select=\"[c8y-modal-footer]\"></ng-content>\n <button\n type=\"button\"\n title=\"{{ labels.cancel | translate }}\"\n *ngIf=\"labels.cancel\"\n class=\"btn btn-default\"\n (click)=\"_dismiss()\"\n >\n {{ labels.cancel | translate }}\n </button>\n <button\n type=\"button\"\n title=\"{{ labels.ok | translate }}\"\n *ngIf=\"labels.ok\"\n class=\"btn btn-primary\"\n (click)=\"_close()\"\n [disabled]=\"disabled\"\n >\n {{ labels.ok | translate }}\n </button>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i3.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ModalComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-modal', template: "<div class=\"viewport-modal\">\n <div class=\"modal-header {{ headerClasses }}\" [ngClass]=\"{ separator: title }\">\n <ng-content select=\"[c8y-modal-title]\"></ng-content>\n <div [hidden]=\"!title\" id=\"modal-title\" class=\"modal-title\">\n {{ title | translate }}\n </div>\n </div>\n <div class=\"modal-inner-scroll\" id=\"modal-body\">\n <div [ngClass]=\"{ 'modal-body': !customFooter, 'd-contents': customFooter }\">\n <p *ngIf=\"title\" class=\"text-center text-break-word\">\n {{ body }}\n </p>\n <ng-content></ng-content>\n </div>\n </div>\n <ng-content select=\"[c8y-modal-footer-custom]\"></ng-content>\n <div class=\"modal-footer\" *ngIf=\"!customFooter\">\n <ng-content select=\"[c8y-modal-footer]\"></ng-content>\n <button\n type=\"button\"\n title=\"{{ labels.cancel | translate }}\"\n *ngIf=\"labels.cancel\"\n class=\"btn btn-default\"\n (click)=\"_dismiss()\"\n >\n {{ labels.cancel | translate }}\n </button>\n <button\n type=\"button\"\n title=\"{{ labels.ok | translate }}\"\n *ngIf=\"labels.ok\"\n class=\"btn btn-primary\"\n (click)=\"_close()\"\n [disabled]=\"disabled\"\n >\n {{ labels.ok | translate }}\n </button>\n </div>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1.BsModalRef, decorators: [{
type: Optional
}] }], propDecorators: { onDismiss: [{
type: Output
}], onClose: [{
type: Output
}], disabled: [{
type: Input
}], close: [{
type: Input
}], dismiss: [{
type: Input
}], title: [{
type: Input
}], body: [{
type: Input
}], customFooter: [{
type: Input
}], headerClasses: [{
type: Input
}], labels: [{
type: Input
}], onEnterKeyDown: [{
type: HostListener,
args: ['document:keydown.enter', ['$event']]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kYWwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vY29yZS9tb2RhbC9tb2RhbC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9jb3JlL21vZGFsL21vZGFsLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMvRixPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDakQsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxRQUFRLENBQUM7Ozs7O0FBR2pDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBb0RHO0FBS0gsTUFBTSxPQUFPLGNBQWM7SUF1Q3pCOztPQUVHO0lBQ0gsSUFBYSxNQUFNLENBQUMsRUFBRSxFQUFFLEVBQUUsTUFBTSxFQUFlO1FBQzdDLElBQUksQ0FBQyxPQUFPLEdBQUcsRUFBRSxFQUFFLEVBQUUsTUFBTSxFQUFFLENBQUM7SUFDaEMsQ0FBQztJQUVELElBQUksTUFBTTtRQUNSLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQztJQUN0QixDQUFDO0lBSUQsWUFBZ0MsS0FBaUI7UUFBakIsVUFBSyxHQUFMLEtBQUssQ0FBWTtRQW5EakQ7O1dBRUc7UUFDTyxjQUFTLEdBQTBCLElBQUksWUFBWSxFQUFFLENBQUM7UUFDaEU7O1dBRUc7UUFDTyxZQUFPLEdBQTBCLElBQUksWUFBWSxFQUFFLENBQUM7UUFDOUQ7O1dBRUc7UUFDTSxhQUFRLEdBQUcsS0FBSyxDQUFDO1FBaUIxQjs7O1dBR0c7UUFDTSxpQkFBWSxHQUFHLEtBQUssQ0FBQztRQUM5Qjs7V0FFRztRQUNNLGtCQUFhLEdBQUcsRUFBRSxDQUFDO1FBYXBCLFlBQU8sR0FBZ0IsRUFBRSxFQUFFLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztJQUU1QixDQUFDO0lBRXJEOzs7T0FHRztJQUNILFFBQVE7UUFDTixJQUFJLEVBQUUsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDO1FBQ3RCLElBQUksQ0FBQyxFQUFFLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ3RCLEVBQUUsR0FBRyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDO1FBQy9CLENBQUM7UUFDRCxJQUFJLEVBQUUsRUFBRSxDQUFDO1lBQ1AsRUFBRSxFQUFFLENBQUM7UUFDUCxDQUFDO1FBQ0QsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDNUIsQ0FBQztJQUVEOzs7T0FHRztJQUNILE1BQU07UUFDSixJQUFJLEVBQUUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDO1FBQ3BCLElBQUksQ0FBQyxFQUFFLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ3RCLEVBQUUsR0FBRyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDO1FBQy9CLENBQUM7UUFDRCxJQUFJLEVBQUUsRUFBRSxDQUFDO1lBQ1AsRUFBRSxFQUFFLENBQUM7UUFDUCxDQUFDO1FBQ0QsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDMUIsQ0FBQztJQUVEOzs7T0FHRztJQUNpRCxjQUFjLENBQUMsTUFBcUI7UUFDdEYsTUFBTSxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsS0FBSyxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNqRixNQUFNLGlCQUFpQixHQUFHLENBQUMsSUFBSSxDQUFDLFlBQVksSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQztRQUNuRSxNQUFNLGFBQWEsR0FBRyxDQUFDLElBQUksQ0FBQyxZQUFZLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1FBQzdFLElBQUksZ0JBQWdCLElBQUksaUJBQWlCLEVBQUUsQ0FBQztZQUMxQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDbEIsQ0FBQztRQUNELElBQUksZ0JBQWdCLElBQUksYUFBYSxFQUFFLENBQUM7WUFDdEMsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ2hCLENBQUM7SUFDSCxDQUFDOytHQWxHVSxjQUFjO21HQUFkLGNBQWMsMldDL0QzQixpeENBdUNBOzs0RkR3QmEsY0FBYztrQkFKMUIsU0FBUzsrQkFDRSxXQUFXOzswQkF1RFIsUUFBUTt5Q0FoRFgsU0FBUztzQkFBbEIsTUFBTTtnQkFJRyxPQUFPO3NCQUFoQixNQUFNO2dCQUlFLFFBQVE7c0JBQWhCLEtBQUs7Z0JBSUcsS0FBSztzQkFBYixLQUFLO2dCQUlHLE9BQU87c0JBQWYsS0FBSztnQkFJRyxLQUFLO3NCQUFiLEtBQUs7Z0JBSUcsSUFBSTtzQkFBWixLQUFLO2dCQUtHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBSUcsYUFBYTtzQkFBckIsS0FBSztnQkFLTyxNQUFNO3NCQUFsQixLQUFLO2dCQThDOEMsY0FBYztzQkFBakUsWUFBWTt1QkFBQyx3QkFBd0IsRUFBRSxDQUFDLFFBQVEsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIE9wdGlvbmFsLCBPdXRwdXQsIEV2ZW50RW1pdHRlciwgSG9zdExpc3RlbmVyIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBCc01vZGFsUmVmIH0gZnJvbSAnbmd4LWJvb3RzdHJhcC9tb2RhbCc7XG5pbXBvcnQgeyBnZXR0ZXh0IH0gZnJvbSAnLi4vaTE4bi9nZXR0ZXh0JztcbmltcG9ydCB7IGlzRW1wdHkgfSBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHsgTW9kYWxMYWJlbHMgfSBmcm9tICcuLi9zZWxlY3QtbW9kYWwvc2VsZWN0LW1vZGFsLm1vZGVsJztcblxuLyoqXG4gKiBDOFkgY29tcG9uZW50IGZvciBjcmVhdGluZyBtb2RhbHMuXG4gKlxuICogQ3JlYXRpbmcgY3VzdG9tIG1vZGFsOlxuICogYGBgdHlwZXNjcmlwdFxuICogIGltcG9ydCB7IENvbXBvbmVudCB9IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG4gKiAgaW1wb3J0IHsgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuICpcbiAqIEBDb21wb25lbnQoe1xuICogIHNlbGVjdG9yOiBcIm15LW1vZGFsXCIsXG4gKiAgdGVtcGxhdGU6IGBcbiAqICAgIDxjOHktbW9kYWwgdGl0bGU9XCJDdXN0b21UaXRsZVwiXG4gKiAgICAgIChvbkNsb3NlKT1cIm9uQ2xvc2UoJGV2ZW50KVwiXG4gKiAgICAgIChvbkRpc21pc3MpPVwib25EaXNtaXNzKCRldmVudClcIlxuICogICAgICBbbGFiZWxzXT1cImxhYmVsc1wiXG4gKiAgICAgIFtkaXNhYmxlZF09XCJ0cnVlXCIgPC0gd2lsbCBkaXNhYmxlIG9rIGJ1dHRvblxuICogICAgICA+XG4gKiAgICAgICAgPHNwYW4+SSBhbSBib2R5IG9mIG1vZGFsPC9zcGFuPlxuICogICAgICAgIDxzcGFuPkZvciBzaW1wbGUgc3RyaW5nIHVzZSBib2R5PVwic3RyaW5nXCI8L3NwYW4+XG4gKiAgICA8L2M4eS1tb2RhbD5gXG4gKiB9KVxuICpcbiAqIGV4cG9ydCBjbGFzcyBNeU1vZGFsQ29tcG9uZW50IHtcbiAqXG4gKiAgY2xvc2VTdWJqZWN0OiBTdWJqZWN0PGJvb2xlYW4+ID0gbmV3IFN1YmplY3QoKTtcbiAqICBsYWJlbHMgOiBNb2RhbExhYmVscyA9IHtvazogXCJjdXN0b21PS1wiLCBjYW5jZWw6IFwiY3VzdG9tQ2FuY2VsXCJ9O1xuICpcbiAqICBvbkRpc21pc3MoZXZlbnQpe1xuICogICAgdGhpcy5jbG9zZVN1YmplY3QubmV4dChmYWxzZSk7XG4gKiAgfVxuICpcbiAqICBvbkNsb3NlKGV2ZW50KSB7XG4gKiAgICB0aGlzLmNsb3NlU3ViamVjdC5uZXh0KHRydWUpO1xuICogIH1cbiAqIH1cbiAqIGBgYFxuICpcbiAqIFNob3dpbmcgbW9kYWw6XG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBCc01vZGFsU2VydmljZSB9IGZyb20gXCJuZ3gtYm9vdHN0cmFwL21vZGFsXCI7XG4gKlxuICogY29uc3RydWN0b3IoXG4gKiAgcHVibGljIGJzTW9kYWxTZXJ2aWNlOiBCc01vZGFsU2VydmljZSxcbiAqICkge31cbiAqXG4gKiBzaG93TW9kYWwoKSB7XG4gKiAgY29uc3QgbW9kYWxSZWYgPSB0aGlzLmJzTW9kYWxTZXJ2aWNlLnNob3coTXlNb2RhbENvbXBvbmVudCk7XG4gKiAgbW9kYWxSZWYuY29udGVudC5jbG9zZVN1YmplY3Quc3Vic2NyaWJlKHJlc3VsdCA9PiB7XG4gKiAgICBjb25zb2xlLmxvZygncmVzdWx0czonLCByZXN1bHQpO1xuICogIH0pO1xuICogfVxuICogYGBgXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2M4eS1tb2RhbCcsXG4gIHRlbXBsYXRlVXJsOiAnLi9tb2RhbC5jb21wb25lbnQuaHRtbCdcbn0pXG5leHBvcnQgY2xhc3MgTW9kYWxDb21wb25lbnQge1xuICAvKipcbiAgICogRW1pdHMgJ3RydWUnIHdoZW4gJ2NhbmNlbCcgYnV0dG9uIGlzIGNsaWNrZWQuXG4gICAqL1xuICBAT3V0cHV0KCkgb25EaXNtaXNzOiBFdmVudEVtaXR0ZXI8Ym9vbGVhbj4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gIC8qKlxuICAgKiBFbWl0cyAndHJ1ZScgd2hlbiAnb2snIGJ1dHRvbiBpcyBjbGlja2VkLlxuICAgKi9cbiAgQE91dHB1dCgpIG9uQ2xvc2U6IEV2ZW50RW1pdHRlcjxib29sZWFuPiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcbiAgLyoqXG4gICAqIEluZGljYXRlcyBpZiB0aGUgJ29rJyAoY29uZmlybWF0aW9uKSBidXR0b24gaXMgZGlzYWJsZWQuXG4gICAqL1xuICBASW5wdXQoKSBkaXNhYmxlZCA9IGZhbHNlO1xuICAvKipcbiAgICogQ2FsbGJhY2sgZnVuY3Rpb24gd2hpY2ggaXMgY2FsbGVkIHJpZ2h0IGFmdGVyICdvaycgYnV0dG9uIGlzIGNsaWNrZWQsIGJlZm9yZSAnb25DbG9zZScgZW1pdHMuXG4gICAqL1xuICBASW5wdXQoKSBjbG9zZTogKCkgPT4gdm9pZDtcbiAgLyoqXG4gICAqIENhbGxiYWNrIGZ1bmN0aW9uIHdoaWNoIGlzIGNhbGxlZCByaWdodCBhZnRlciAnY2FuY2VsJyBidXR0b24gaXMgY2xpY2tlZCwgYmVmb3JlICdvbkRpc21pc3MnIGVtaXRzLlxuICAgKi9cbiAgQElucHV0KCkgZGlzbWlzczogKCkgPT4gdm9pZDtcbiAgLyoqXG4gICAqIFRpdGxlIG9mIG1vZGFsLlxuICAgKi9cbiAgQElucHV0KCkgdGl0bGU6IHN0cmluZztcbiAgLyoqXG4gICAqIE1vZGFsIGJvZHkuXG4gICAqL1xuICBASW5wdXQoKSBib2R5OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgbW9kYWwgc2hvdWxkIHVzZSBjdXN0b20gZm9vdGVyIHByb3ZpZGVkIHdpdGggY29udGVudCBwcm9qZWN0aW9uIChvciBubyBmb290ZXIgYXQgYWxsKS5cbiAgICogSWYgZmFsc2UsIGRlZmF1bHQgZm9vdGVyIHdpdGggJ2NhbmNlbCcgYW5kICdvaycgYnV0dG9ucyB3aWxsIGJlIGRpc3BsYXllZC5cbiAgICovXG4gIEBJbnB1dCgpIGN1c3RvbUZvb3RlciA9IGZhbHNlO1xuICAvKipcbiAgICogQ1NTIGNsYXNzZXMgZm9yIG1vZGFsIGhlYWRlci5cbiAgICovXG4gIEBJbnB1dCgpIGhlYWRlckNsYXNzZXMgPSAnJztcblxuICAvKipcbiAgICogQ3VzdG9tIGxhYmVscyBmb3IgJ2NhbmNlbCcgYW5kICdvaycgYnV0dG9ucy5cbiAgICovXG4gIEBJbnB1dCgpIHNldCBsYWJlbHMoeyBvaywgY2FuY2VsIH06IE1vZGFsTGFiZWxzKSB7XG4gICAgdGhpcy5fbGFiZWxzID0geyBvaywgY2FuY2VsIH07XG4gIH1cblxuICBnZXQgbGFiZWxzKCk6IE1vZGFsTGFiZWxzIHtcbiAgICByZXR1cm4gdGhpcy5fbGFiZWxzO1xuICB9XG5cbiAgcHJpdmF0ZSBfbGFiZWxzOiBNb2RhbExhYmVscyA9IHsgb2s6IGdldHRleHQoJ09LJyksIGNhbmNlbDogZ2V0dGV4dCgnQ2FuY2VsJykgfTtcblxuICBjb25zdHJ1Y3RvcihAT3B0aW9uYWwoKSBwcml2YXRlIG1vZGFsOiBCc01vZGFsUmVmKSB7fVxuXG4gIC8qKlxuICAgKiBIaWRlcyBtb2RhbCBvciBjYWxscyAnZGlzbWlzcycgaW5wdXQgY2FsbGJhY2ssIHRoZW4gZW1pdHMgJ29uRGlzbWlzcycgb3V0cHV0LlxuICAgKiBNZXRob2QgaXMgY2FsbGVkIHdoZW4gJ2NhbmNlbCcgYnV0dG9uIGlzIGNsaWNrZWQsIGJ1dCBjYW4gYmUgYWxzbyB0cmlnZ2VyZWQgYnkgYWNjZXNzaW5nICdNb2RhbENvbXBvbmVudCcgaW5zdGFuY2UuXG4gICAqL1xuICBfZGlzbWlzcygpIHtcbiAgICBsZXQgZm4gPSB0aGlzLmRpc21pc3M7XG4gICAgaWYgKCFmbiAmJiB0aGlzLm1vZGFsKSB7XG4gICAgICBmbiA9ICgpID0+IHRoaXMubW9kYWwuaGlkZSgpO1xuICAgIH1cbiAgICBpZiAoZm4pIHtcbiAgICAgIGZuKCk7XG4gICAgfVxuICAgIHRoaXMub25EaXNtaXNzLmVtaXQodHJ1ZSk7XG4gIH1cblxuICAvKipcbiAgICogSGlkZXMgbW9kYWwgb3IgY2FsbHMgJ2Nsb3NlJyBpbnB1dCBjYWxsYmFjaywgdGhlbiBlbWl0cyAnb25DbG9zZScgb3V0cHV0LlxuICAgKiBNZXRob2QgaXMgY2FsbGVkIHdoZW4gJ29rJyBidXR0b24gaXMgY2xpY2tlZCwgYnV0IGNhbiBiZSBhbHNvIHRyaWdnZXJlZCBieSBhY2Nlc3NpbmcgJ01vZGFsQ29tcG9uZW50JyBpbnN0YW5jZS5cbiAgICovXG4gIF9jbG9zZSgpIHtcbiAgICBsZXQgZm4gPSB0aGlzLmNsb3NlO1xuICAgIGlmICghZm4gJiYgdGhpcy5tb2RhbCkge1xuICAgICAgZm4gPSAoKSA9PiB0aGlzLm1vZGFsLmhpZGUoKTtcbiAgICB9XG4gICAgaWYgKGZuKSB7XG4gICAgICBmbigpO1xuICAgIH1cbiAgICB0aGlzLm9uQ2xvc2UuZW1pdCh0cnVlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiAnRW50ZXInIGtleWJvYXJkIGJ1dHRvbiBoYW5kbGVyLiBDYWxscyAnX2Rpc21pc3MnIG9yICdfY2xvc2UnIG1ldGhvZCB3aGVuIG9ubHkgb25lIGNvcnJlc3BvbmRpbmcgYnV0dG9uIGV4aXN0cy5cbiAgICogQHBhcmFtIF9ldmVudCBFbnRlciBrZXlkb3duIGV2ZW50XG4gICAqL1xuICBASG9zdExpc3RlbmVyKCdkb2N1bWVudDprZXlkb3duLmVudGVyJywgWyckZXZlbnQnXSkgb25FbnRlcktleURvd24oX2V2ZW50OiBLZXlib2FyZEV2ZW50KSB7XG4gICAgY29uc3QgaGFzT25seU9uZUJ1dHRvbiA9IGlzRW1wdHkodGhpcy5sYWJlbHMub2spICE9PSBpc0VtcHR5KHRoaXMubGFiZWxzLmNhbmNlbCk7XG4gICAgY29uc3QgaXNDYW5jZWxDbGlja2FibGUgPSAhdGhpcy5jdXN0b21Gb290ZXIgJiYgdGhpcy5sYWJlbHMuY2FuY2VsO1xuICAgIGNvbnN0IGlzT2tDbGlja2FibGUgPSAhdGhpcy5jdXN0b21Gb290ZXIgJiYgIXRoaXMuZGlzYWJsZWQgJiYgdGhpcy5sYWJlbHMub2s7XG4gICAgaWYgKGhhc09ubHlPbmVCdXR0b24gJiYgaXNDYW5jZWxDbGlja2FibGUpIHtcbiAgICAgIHRoaXMuX2Rpc21pc3MoKTtcbiAgICB9XG4gICAgaWYgKGhhc09ubHlPbmVCdXR0b24gJiYgaXNPa0NsaWNrYWJsZSkge1xuICAgICAgdGhpcy5fY2xvc2UoKTtcbiAgICB9XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJ2aWV3cG9ydC1tb2RhbFwiPlxuICA8ZGl2IGNsYXNzPVwibW9kYWwtaGVhZGVyIHt7IGhlYWRlckNsYXNzZXMgfX1cIiBbbmdDbGFzc109XCJ7IHNlcGFyYXRvcjogdGl0bGUgfVwiPlxuICAgIDxuZy1jb250ZW50IHNlbGVjdD1cIltjOHktbW9kYWwtdGl0bGVdXCI+PC9uZy1jb250ZW50PlxuICAgIDxkaXYgW2hpZGRlbl09XCIhdGl0bGVcIiBpZD1cIm1vZGFsLXRpdGxlXCIgY2xhc3M9XCJtb2RhbC10aXRsZVwiPlxuICAgICAge3sgdGl0bGUgfCB0cmFuc2xhdGUgfX1cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG4gIDxkaXYgY2xhc3M9XCJtb2RhbC1pbm5lci1zY3JvbGxcIiBpZD1cIm1vZGFsLWJvZHlcIj5cbiAgICA8ZGl2IFtuZ0NsYXNzXT1cInsgJ21vZGFsLWJvZHknOiAhY3VzdG9tRm9vdGVyLCAnZC1jb250ZW50cyc6IGN1c3RvbUZvb3RlciB9XCI+XG4gICAgICA8cCAqbmdJZj1cInRpdGxlXCIgY2xhc3M9XCJ0ZXh0LWNlbnRlciB0ZXh0LWJyZWFrLXdvcmRcIj5cbiAgICAgICAge3sgYm9keSB9fVxuICAgICAgPC9wPlxuICAgICAgPG5nLWNvbnRlbnQ+PC9uZy1jb250ZW50PlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbiAgPG5nLWNvbnRlbnQgc2VsZWN0PVwiW2M4eS1tb2RhbC1mb290ZXItY3VzdG9tXVwiPjwvbmctY29udGVudD5cbiAgPGRpdiBjbGFzcz1cIm1vZGFsLWZvb3RlclwiICpuZ0lmPVwiIWN1c3RvbUZvb3RlclwiPlxuICAgIDxuZy1jb250ZW50IHNlbGVjdD1cIltjOHktbW9kYWwtZm9vdGVyXVwiPjwvbmctY29udGVudD5cbiAgICA8YnV0dG9uXG4gICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgIHRpdGxlPVwie3sgbGFiZWxzLmNhbmNlbCB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAqbmdJZj1cImxhYmVscy5jYW5jZWxcIlxuICAgICAgY2xhc3M9XCJidG4gYnRuLWRlZmF1bHRcIlxuICAgICAgKGNsaWNrKT1cIl9kaXNtaXNzKClcIlxuICAgID5cbiAgICAgIHt7IGxhYmVscy5jYW5jZWwgfCB0cmFuc2xhdGUgfX1cbiAgICA8L2J1dHRvbj5cbiAgICA8YnV0dG9uXG4gICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgIHRpdGxlPVwie3sgbGFiZWxzLm9rIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICpuZ0lmPVwibGFiZWxzLm9rXCJcbiAgICAgIGNsYXNzPVwiYnRuIGJ0bi1wcmltYXJ5XCJcbiAgICAgIChjbGljayk9XCJfY2xvc2UoKVwiXG4gICAgICBbZGlzYWJsZWRdPVwiZGlzYWJsZWRcIlxuICAgID5cbiAgICAgIHt7IGxhYmVscy5vayB8IHRyYW5zbGF0ZSB9fVxuICAgIDwvYnV0dG9uPlxuICA8L2Rpdj5cbjwvZGl2PlxuIl19