UNPKG

ngx-pwa

Version:

Provides functionality around the progressive web app functionality in angular. Most notably the an approach to cache POST, UPDATE and DELETE requests.

97 lines 19.2 kB
import { CommonModule } from '@angular/common'; import { Component, Inject } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; import { MatDividerModule } from '@angular/material/divider'; import { PurifyUtilities } from '../../encapsulation/purify.utilities'; import { SynchronizeDialogDataInternal } from '../../models/synchronize-dialog-data-internal.model'; import { NGX_PWA_OFFLINE_SERVICE } from '../../services/offline.service'; import * as i0 from "@angular/core"; import * as i1 from "@angular/platform-browser"; import * as i2 from "@angular/material/dialog"; import * as i3 from "@angular/material/button"; import * as i4 from "@angular/material/divider"; /** * The dialog for syncing cached requests to the server. */ export class NgxPwaSynchronizeDialogComponent { offlineService; sanitizer; dialogRef; data; // eslint-disable-next-line jsdoc/require-jsdoc PurifyUtilities = PurifyUtilities; /** * The provided dialog data filled up with default values. */ dialogData; constructor(offlineService, sanitizer, dialogRef, data) { this.offlineService = offlineService; this.sanitizer = sanitizer; this.dialogRef = dialogRef; this.data = data; } ngOnInit() { this.dialogData = new SynchronizeDialogDataInternal(this.data); } /** * Sends a specific cached request to the server. * @param request - The request that should be synced. */ async syncSingleRequest(request) { await this.offlineService.sync(request); if (!this.offlineService.cachedRequests.length) { this.dialogRef.close(); } } /** * Removes a single request from the cache. * @param request - The request that should be removed. */ removeSingleRequest(request) { this.offlineService.removeSingleRequest(request); if (!this.offlineService.cachedRequests.length) { this.dialogRef.close(); } } /** * Sends all cached requests to the server. Tries to handle dependencies of requests on each other. */ async syncAll() { await this.offlineService.syncAll(); if (!this.offlineService.cachedRequests.length) { this.dialogRef.close(); } } /** * Removes all locally cached requests. */ undoAll() { this.offlineService.cachedRequests = []; this.dialogRef.close(); } /** * Closes the dialog. */ close() { this.dialogRef.close(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NgxPwaSynchronizeDialogComponent, deps: [{ token: NGX_PWA_OFFLINE_SERVICE }, { token: i1.DomSanitizer }, { token: i2.MatDialogRef }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: NgxPwaSynchronizeDialogComponent, isStandalone: true, selector: "ngx-pwa-synchronize-dialog", ngImport: i0, template: "<h1 mat-dialog-title>{{dialogData.title}}</h1>\n<div mat-dialog-content>\n <div class=\"all-button-row\">\n <button type=\"button\" mat-raised-button [disabled]=\"offlineService.isOffline\" (click)=\"syncAll()\">\n {{dialogData.syncAllButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"undoAll()\">\n {{dialogData.undoAllButtonLabel}}\n </button>\n </div>\n <div class=\"mat-elevation-z4 request-box\">\n @for (request of offlineService.cachedRequests; track $index) {\n <div class=\"request-item\">\n <!-- eslint-disable-next-line angular/no-call-expression -->\n <div [innerHtml]=\"sanitizer.bypassSecurityTrustHtml(PurifyUtilities.sanitize(request.metadata.displayValue))\">\n </div>\n <span>\n <!-- eslint-disable-next-line angular/no-call-expression -->\n <button type=\"button\" mat-icon-button [disabled]=\"offlineService.isOffline || offlineService.hasUnresolvedDependency(request)\" (click)=\"syncSingleRequest(request)\">\n <i class=\"fas fa-upload\"></i>\n </button>\n <button type=\"button\" mat-icon-button color=\"warn\" (click)=\"removeSingleRequest(request)\">\n <i class=\"fas fa-trash\"></i>\n </button>\n </span>\n </div>\n <mat-divider></mat-divider>\n }\n </div>\n</div>\n<div mat-dialog-actions>\n <button type=\"button\" mat-raised-button class=\"cancel-button\" (click)=\"close()\">{{dialogData.closeButtonLabel}}</button>\n</div>", styles: ["h1{text-align:center}.all-button-row{margin-top:10px;margin-bottom:15px;display:flex;flex-wrap:nowrap;gap:10px}.all-button-row button{flex:50%}.request-box{border-radius:5px;margin-bottom:10px}.request-box .request-item{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;padding:15px;line-break:anywhere}.request-box i{font-size:22px;line-height:22px}.cancel-button{margin-left:auto;margin-right:auto}@media (max-width: 1200px){.all-button-row{flex-wrap:wrap}.all-button-row button{flex:100%}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i4.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i2.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i2.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i2.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NgxPwaSynchronizeDialogComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-pwa-synchronize-dialog', standalone: true, imports: [ CommonModule, MatButtonModule, MatDividerModule, MatDialogModule ], template: "<h1 mat-dialog-title>{{dialogData.title}}</h1>\n<div mat-dialog-content>\n <div class=\"all-button-row\">\n <button type=\"button\" mat-raised-button [disabled]=\"offlineService.isOffline\" (click)=\"syncAll()\">\n {{dialogData.syncAllButtonLabel}}\n </button>\n <button type=\"button\" mat-raised-button (click)=\"undoAll()\">\n {{dialogData.undoAllButtonLabel}}\n </button>\n </div>\n <div class=\"mat-elevation-z4 request-box\">\n @for (request of offlineService.cachedRequests; track $index) {\n <div class=\"request-item\">\n <!-- eslint-disable-next-line angular/no-call-expression -->\n <div [innerHtml]=\"sanitizer.bypassSecurityTrustHtml(PurifyUtilities.sanitize(request.metadata.displayValue))\">\n </div>\n <span>\n <!-- eslint-disable-next-line angular/no-call-expression -->\n <button type=\"button\" mat-icon-button [disabled]=\"offlineService.isOffline || offlineService.hasUnresolvedDependency(request)\" (click)=\"syncSingleRequest(request)\">\n <i class=\"fas fa-upload\"></i>\n </button>\n <button type=\"button\" mat-icon-button color=\"warn\" (click)=\"removeSingleRequest(request)\">\n <i class=\"fas fa-trash\"></i>\n </button>\n </span>\n </div>\n <mat-divider></mat-divider>\n }\n </div>\n</div>\n<div mat-dialog-actions>\n <button type=\"button\" mat-raised-button class=\"cancel-button\" (click)=\"close()\">{{dialogData.closeButtonLabel}}</button>\n</div>", styles: ["h1{text-align:center}.all-button-row{margin-top:10px;margin-bottom:15px;display:flex;flex-wrap:nowrap;gap:10px}.all-button-row button{flex:50%}.request-box{border-radius:5px;margin-bottom:10px}.request-box .request-item{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;padding:15px;line-break:anywhere}.request-box i{font-size:22px;line-height:22px}.cancel-button{margin-left:auto;margin-right:auto}@media (max-width: 1200px){.all-button-row{flex-wrap:wrap}.all-button-row button{flex:100%}}\n"] }] }], ctorParameters: () => [{ type: undefined, decorators: [{ type: Inject, args: [NGX_PWA_OFFLINE_SERVICE] }] }, { type: i1.DomSanitizer }, { type: i2.MatDialogRef }, { type: undefined, decorators: [{ type: Inject, args: [MAT_DIALOG_DATA] }] }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luY2hyb25pemUtZGlhbG9nLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1wd2Evc3JjL2NvbXBvbmVudHMvc3luY2hyb25pemUtZGlhbG9nL3N5bmNocm9uaXplLWRpYWxvZy5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtcHdhL3NyYy9jb21wb25lbnRzL3N5bmNocm9uaXplLWRpYWxvZy9zeW5jaHJvbml6ZS1kaWFsb2cuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFVLE1BQU0sZUFBZSxDQUFDO0FBQzFELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMzRCxPQUFPLEVBQUUsZUFBZSxFQUFFLGVBQWUsRUFBZ0IsTUFBTSwwQkFBMEIsQ0FBQztBQUMxRixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUc3RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sc0NBQXNDLENBQUM7QUFDdkUsT0FBTyxFQUFFLDZCQUE2QixFQUFFLE1BQU0scURBQXFELENBQUM7QUFFcEcsT0FBTyxFQUFpQix1QkFBdUIsRUFBd0IsTUFBTSxnQ0FBZ0MsQ0FBQzs7Ozs7O0FBRTlHOztHQUVHO0FBYUgsTUFBTSxPQUFPLGdDQUFnQztJQVk1QjtJQUNBO0lBQ1E7SUFFUjtJQWRiLCtDQUErQztJQUMvQyxlQUFlLEdBQTJCLGVBQWUsQ0FBQztJQUUxRDs7T0FFRztJQUNILFVBQVUsQ0FBaUM7SUFFM0MsWUFFYSxjQUFrQyxFQUNsQyxTQUF1QixFQUNmLFNBQTZFLEVBRXJGLElBQTJCO1FBSjNCLG1CQUFjLEdBQWQsY0FBYyxDQUFvQjtRQUNsQyxjQUFTLEdBQVQsU0FBUyxDQUFjO1FBQ2YsY0FBUyxHQUFULFNBQVMsQ0FBb0U7UUFFckYsU0FBSSxHQUFKLElBQUksQ0FBdUI7SUFDcEMsQ0FBQztJQUVMLFFBQVE7UUFDSixJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksNkJBQTZCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ25FLENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsaUJBQWlCLENBQUMsT0FBK0I7UUFDbkQsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN4QyxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxjQUFjLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDN0MsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUMzQixDQUFDO0lBQ0wsQ0FBQztJQUVEOzs7T0FHRztJQUNILG1CQUFtQixDQUFDLE9BQStCO1FBQy9DLElBQUksQ0FBQyxjQUFjLENBQUMsbUJBQW1CLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDakQsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsY0FBYyxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQzdDLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDM0IsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxPQUFPO1FBQ1QsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ3BDLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLGNBQWMsQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUM3QyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzNCLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxPQUFPO1FBQ0gsSUFBSSxDQUFDLGNBQWMsQ0FBQyxjQUFjLEdBQUcsRUFBRSxDQUFDO1FBQ3hDLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDM0IsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSztRQUNELElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDM0IsQ0FBQzt3R0FwRVEsZ0NBQWdDLGtCQVc3Qix1QkFBdUIscUVBSXZCLGVBQWU7NEZBZmxCLGdDQUFnQyxzRkMzQjdDLGlyREFnQ00sa2tCRFhFLFlBQVksOEJBQ1osZUFBZSx3VUFDZixnQkFBZ0Isa0lBQ2hCLGVBQWU7OzRGQUdWLGdDQUFnQztrQkFaNUMsU0FBUzsrQkFDSSw0QkFBNEIsY0FHMUIsSUFBSSxXQUNQO3dCQUNMLFlBQVk7d0JBQ1osZUFBZTt3QkFDZixnQkFBZ0I7d0JBQ2hCLGVBQWU7cUJBQ2xCOzswQkFhSSxNQUFNOzJCQUFDLHVCQUF1Qjs7MEJBSTlCLE1BQU07MkJBQUMsZUFBZSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBDb21wb25lbnQsIEluamVjdCwgT25Jbml0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBNYXRCdXR0b25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9idXR0b24nO1xuaW1wb3J0IHsgTUFUX0RJQUxPR19EQVRBLCBNYXREaWFsb2dNb2R1bGUsIE1hdERpYWxvZ1JlZiB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2RpYWxvZyc7XG5pbXBvcnQgeyBNYXREaXZpZGVyTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZGl2aWRlcic7XG5pbXBvcnQgeyBEb21TYW5pdGl6ZXIgfSBmcm9tICdAYW5ndWxhci9wbGF0Zm9ybS1icm93c2VyJztcblxuaW1wb3J0IHsgUHVyaWZ5VXRpbGl0aWVzIH0gZnJvbSAnLi4vLi4vZW5jYXBzdWxhdGlvbi9wdXJpZnkudXRpbGl0aWVzJztcbmltcG9ydCB7IFN5bmNocm9uaXplRGlhbG9nRGF0YUludGVybmFsIH0gZnJvbSAnLi4vLi4vbW9kZWxzL3N5bmNocm9uaXplLWRpYWxvZy1kYXRhLWludGVybmFsLm1vZGVsJztcbmltcG9ydCB7IFN5bmNocm9uaXplRGlhbG9nRGF0YSB9IGZyb20gJy4uLy4uL21vZGVscy9zeW5jaHJvbml6ZS1kaWFsb2ctZGF0YS5tb2RlbCc7XG5pbXBvcnQgeyBDYWNoZWRSZXF1ZXN0LCBOR1hfUFdBX09GRkxJTkVfU0VSVklDRSwgTmd4UHdhT2ZmbGluZVNlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9vZmZsaW5lLnNlcnZpY2UnO1xuXG4vKipcbiAqIFRoZSBkaWFsb2cgZm9yIHN5bmNpbmcgY2FjaGVkIHJlcXVlc3RzIHRvIHRoZSBzZXJ2ZXIuXG4gKi9cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAnbmd4LXB3YS1zeW5jaHJvbml6ZS1kaWFsb2cnLFxuICAgIHRlbXBsYXRlVXJsOiAnLi9zeW5jaHJvbml6ZS1kaWFsb2cuY29tcG9uZW50Lmh0bWwnLFxuICAgIHN0eWxlVXJsczogWycuL3N5bmNocm9uaXplLWRpYWxvZy5jb21wb25lbnQuc2NzcyddLFxuICAgIHN0YW5kYWxvbmU6IHRydWUsXG4gICAgaW1wb3J0czogW1xuICAgICAgICBDb21tb25Nb2R1bGUsXG4gICAgICAgIE1hdEJ1dHRvbk1vZHVsZSxcbiAgICAgICAgTWF0RGl2aWRlck1vZHVsZSxcbiAgICAgICAgTWF0RGlhbG9nTW9kdWxlXG4gICAgXVxufSlcbmV4cG9ydCBjbGFzcyBOZ3hQd2FTeW5jaHJvbml6ZURpYWxvZ0NvbXBvbmVudDxPZmZsaW5lU2VydmljZVR5cGUgZXh0ZW5kcyBOZ3hQd2FPZmZsaW5lU2VydmljZT4gaW1wbGVtZW50cyBPbkluaXQge1xuXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGpzZG9jL3JlcXVpcmUtanNkb2NcbiAgICBQdXJpZnlVdGlsaXRpZXM6IHR5cGVvZiBQdXJpZnlVdGlsaXRpZXMgPSBQdXJpZnlVdGlsaXRpZXM7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgcHJvdmlkZWQgZGlhbG9nIGRhdGEgZmlsbGVkIHVwIHdpdGggZGVmYXVsdCB2YWx1ZXMuXG4gICAgICovXG4gICAgZGlhbG9nRGF0YSE6IFN5bmNocm9uaXplRGlhbG9nRGF0YUludGVybmFsO1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIEBJbmplY3QoTkdYX1BXQV9PRkZMSU5FX1NFUlZJQ0UpXG4gICAgICAgIHJlYWRvbmx5IG9mZmxpbmVTZXJ2aWNlOiBPZmZsaW5lU2VydmljZVR5cGUsXG4gICAgICAgIHJlYWRvbmx5IHNhbml0aXplcjogRG9tU2FuaXRpemVyLFxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IGRpYWxvZ1JlZjogTWF0RGlhbG9nUmVmPE5neFB3YVN5bmNocm9uaXplRGlhbG9nQ29tcG9uZW50PE9mZmxpbmVTZXJ2aWNlVHlwZT4+LFxuICAgICAgICBASW5qZWN0KE1BVF9ESUFMT0dfREFUQSlcbiAgICAgICAgcmVhZG9ubHkgZGF0YTogU3luY2hyb25pemVEaWFsb2dEYXRhXG4gICAgKSB7IH1cblxuICAgIG5nT25Jbml0KCk6IHZvaWQge1xuICAgICAgICB0aGlzLmRpYWxvZ0RhdGEgPSBuZXcgU3luY2hyb25pemVEaWFsb2dEYXRhSW50ZXJuYWwodGhpcy5kYXRhKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZW5kcyBhIHNwZWNpZmljIGNhY2hlZCByZXF1ZXN0IHRvIHRoZSBzZXJ2ZXIuXG4gICAgICogQHBhcmFtIHJlcXVlc3QgLSBUaGUgcmVxdWVzdCB0aGF0IHNob3VsZCBiZSBzeW5jZWQuXG4gICAgICovXG4gICAgYXN5bmMgc3luY1NpbmdsZVJlcXVlc3QocmVxdWVzdDogQ2FjaGVkUmVxdWVzdDx1bmtub3duPik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLm9mZmxpbmVTZXJ2aWNlLnN5bmMocmVxdWVzdCk7XG4gICAgICAgIGlmICghdGhpcy5vZmZsaW5lU2VydmljZS5jYWNoZWRSZXF1ZXN0cy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHRoaXMuZGlhbG9nUmVmLmNsb3NlKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZW1vdmVzIGEgc2luZ2xlIHJlcXVlc3QgZnJvbSB0aGUgY2FjaGUuXG4gICAgICogQHBhcmFtIHJlcXVlc3QgLSBUaGUgcmVxdWVzdCB0aGF0IHNob3VsZCBiZSByZW1vdmVkLlxuICAgICAqL1xuICAgIHJlbW92ZVNpbmdsZVJlcXVlc3QocmVxdWVzdDogQ2FjaGVkUmVxdWVzdDx1bmtub3duPik6IHZvaWQge1xuICAgICAgICB0aGlzLm9mZmxpbmVTZXJ2aWNlLnJlbW92ZVNpbmdsZVJlcXVlc3QocmVxdWVzdCk7XG4gICAgICAgIGlmICghdGhpcy5vZmZsaW5lU2VydmljZS5jYWNoZWRSZXF1ZXN0cy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHRoaXMuZGlhbG9nUmVmLmNsb3NlKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZW5kcyBhbGwgY2FjaGVkIHJlcXVlc3RzIHRvIHRoZSBzZXJ2ZXIuIFRyaWVzIHRvIGhhbmRsZSBkZXBlbmRlbmNpZXMgb2YgcmVxdWVzdHMgb24gZWFjaCBvdGhlci5cbiAgICAgKi9cbiAgICBhc3luYyBzeW5jQWxsKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLm9mZmxpbmVTZXJ2aWNlLnN5bmNBbGwoKTtcbiAgICAgICAgaWYgKCF0aGlzLm9mZmxpbmVTZXJ2aWNlLmNhY2hlZFJlcXVlc3RzLmxlbmd0aCkge1xuICAgICAgICAgICAgdGhpcy5kaWFsb2dSZWYuY2xvc2UoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlbW92ZXMgYWxsIGxvY2FsbHkgY2FjaGVkIHJlcXVlc3RzLlxuICAgICAqL1xuICAgIHVuZG9BbGwoKTogdm9pZCB7XG4gICAgICAgIHRoaXMub2ZmbGluZVNlcnZpY2UuY2FjaGVkUmVxdWVzdHMgPSBbXTtcbiAgICAgICAgdGhpcy5kaWFsb2dSZWYuY2xvc2UoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDbG9zZXMgdGhlIGRpYWxvZy5cbiAgICAgKi9cbiAgICBjbG9zZSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5kaWFsb2dSZWYuY2xvc2UoKTtcbiAgICB9XG59IiwiPGgxIG1hdC1kaWFsb2ctdGl0bGU+e3tkaWFsb2dEYXRhLnRpdGxlfX08L2gxPlxuPGRpdiBtYXQtZGlhbG9nLWNvbnRlbnQ+XG4gICAgPGRpdiBjbGFzcz1cImFsbC1idXR0b24tcm93XCI+XG4gICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIG1hdC1yYWlzZWQtYnV0dG9uIFtkaXNhYmxlZF09XCJvZmZsaW5lU2VydmljZS5pc09mZmxpbmVcIiAoY2xpY2spPVwic3luY0FsbCgpXCI+XG4gICAgICAgICAgICB7e2RpYWxvZ0RhdGEuc3luY0FsbEJ1dHRvbkxhYmVsfX1cbiAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIG1hdC1yYWlzZWQtYnV0dG9uIChjbGljayk9XCJ1bmRvQWxsKClcIj5cbiAgICAgICAgICAgIHt7ZGlhbG9nRGF0YS51bmRvQWxsQnV0dG9uTGFiZWx9fVxuICAgICAgICA8L2J1dHRvbj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwibWF0LWVsZXZhdGlvbi16NCByZXF1ZXN0LWJveFwiPlxuICAgICAgICBAZm9yIChyZXF1ZXN0IG9mIG9mZmxpbmVTZXJ2aWNlLmNhY2hlZFJlcXVlc3RzOyB0cmFjayAkaW5kZXgpIHtcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJyZXF1ZXN0LWl0ZW1cIj5cbiAgICAgICAgICAgICAgICA8IS0tIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBhbmd1bGFyL25vLWNhbGwtZXhwcmVzc2lvbiAtLT5cbiAgICAgICAgICAgICAgICA8ZGl2IFtpbm5lckh0bWxdPVwic2FuaXRpemVyLmJ5cGFzc1NlY3VyaXR5VHJ1c3RIdG1sKFB1cmlmeVV0aWxpdGllcy5zYW5pdGl6ZShyZXF1ZXN0Lm1ldGFkYXRhLmRpc3BsYXlWYWx1ZSkpXCI+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgPHNwYW4+XG4gICAgICAgICAgICAgICAgICAgIDwhLS0gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGFuZ3VsYXIvbm8tY2FsbC1leHByZXNzaW9uIC0tPlxuICAgICAgICAgICAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBtYXQtaWNvbi1idXR0b24gW2Rpc2FibGVkXT1cIm9mZmxpbmVTZXJ2aWNlLmlzT2ZmbGluZSB8fCBvZmZsaW5lU2VydmljZS5oYXNVbnJlc29sdmVkRGVwZW5kZW5jeShyZXF1ZXN0KVwiIChjbGljayk9XCJzeW5jU2luZ2xlUmVxdWVzdChyZXF1ZXN0KVwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgPGkgY2xhc3M9XCJmYXMgZmEtdXBsb2FkXCI+PC9pPlxuICAgICAgICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgbWF0LWljb24tYnV0dG9uIGNvbG9yPVwid2FyblwiIChjbGljayk9XCJyZW1vdmVTaW5nbGVSZXF1ZXN0KHJlcXVlc3QpXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICA8aSBjbGFzcz1cImZhcyBmYS10cmFzaFwiPjwvaT5cbiAgICAgICAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8bWF0LWRpdmlkZXI+PC9tYXQtZGl2aWRlcj5cbiAgICAgICAgfVxuICAgIDwvZGl2PlxuPC9kaXY+XG48ZGl2IG1hdC1kaWFsb2ctYWN0aW9ucz5cbiAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBtYXQtcmFpc2VkLWJ1dHRvbiBjbGFzcz1cImNhbmNlbC1idXR0b25cIiAoY2xpY2spPVwiY2xvc2UoKVwiPnt7ZGlhbG9nRGF0YS5jbG9zZUJ1dHRvbkxhYmVsfX08L2J1dHRvbj5cbjwvZGl2PiJdfQ==