ngx-techlify-core 18.54.1 → 18.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,8 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { Component, Input } from '@angular/core';
3
3
  import { UserFormComponent } from './user-form.component';
4
- import { debounceTime, distinctUntilChanged, finalize } from 'rxjs/operators';
4
+ import { finalize } from 'rxjs/operators';
5
5
  import { UntilDestroy } from '@ngneat/until-destroy';
6
- import { ActionPopupComponent } from '../action-popup';
7
6
  import { UserTypeEnum } from './user-type.enum';
8
7
  import { TechlifyListingControllerInterface } from '../base-model';
9
8
  import * as i0 from "@angular/core";
@@ -13,8 +12,8 @@ import * as i3 from "../user-config";
13
12
  import * as i4 from "@angular/material/dialog";
14
13
  import * as i5 from "./user.service";
15
14
  import * as i6 from "@angular/forms";
16
- import * as i7 from "@angular/router";
17
- import * as i8 from "@angular/common";
15
+ import * as i7 from "@angular/common";
16
+ import * as i8 from "@angular/router";
18
17
  import * as i9 from "@angular/material/button";
19
18
  import * as i10 from "@angular/material/form-field";
20
19
  import * as i11 from "@angular/material/icon";
@@ -25,26 +24,23 @@ import * as i15 from "@angular/material/card";
25
24
  import * as i16 from "@angular/material/tooltip";
26
25
  import * as i17 from "@angular/material/button-toggle";
27
26
  import * as i18 from "@angular/material/progress-bar";
28
- import * as i19 from "@angular/flex-layout/flex";
29
- import * as i20 from "@angular/flex-layout/extended";
30
- import * as i21 from "ngx-infinite-scroll";
31
- import * as i22 from "../searchable-selector/searchable-selector.component";
32
- import * as i23 from "./user-enable-button-component/user-enable-button.component";
27
+ import * as i19 from "@angular/flex-layout/extended";
28
+ import * as i20 from "ngx-infinite-scroll";
29
+ import * as i21 from "../searchable-selector/searchable-selector.component";
30
+ import * as i22 from "./user-enable-button-component/user-enable-button.component";
31
+ import * as i23 from "../techlify-icon/techlify-icon.component";
32
+ import * as i24 from "../delete-button/techlify-delete-button.component";
33
33
  let UsersViewAllComponent = class UsersViewAllComponent extends TechlifyListingControllerInterface {
34
- constructor(http, alertService, currentUserService, userConfigService, dialog, userService, fb, activatedRoute) {
34
+ constructor(alertService, currentUserService, userConfigService, dialog, service, fb) {
35
35
  super();
36
- this.http = http;
37
36
  this.alertService = alertService;
38
37
  this.currentUserService = currentUserService;
39
38
  this.userConfigService = userConfigService;
40
39
  this.dialog = dialog;
41
- this.userService = userService;
40
+ this.service = service;
42
41
  this.fb = fb;
43
- this.activatedRoute = activatedRoute;
44
42
  this.userTypeIds = [];
45
- this.isWorking = false;
46
43
  this.title = 'User Management';
47
- this.pageEvent = { page: 1, perPage: 25, lastPage: 1 };
48
44
  this.displayedColumns = [
49
45
  'index',
50
46
  'name',
@@ -58,40 +54,12 @@ let UsersViewAllComponent = class UsersViewAllComponent extends TechlifyListingC
58
54
  this.scrollContainer = '.mat-sidenav-content';
59
55
  this.models = [];
60
56
  this.isAppAdminUser = false;
61
- this.lastPage = 0;
62
57
  this.config = this.userConfigService.getConfig();
63
- if (this.config?.scrollContainer) {
64
- // Set to null if scroll has to be done from root
65
- this.scrollContainer = this.config?.scrollContainer === 'root' ? null : this.config?.scrollContainer;
66
- }
67
- }
68
- // tslint:disable-next-line:typedef
69
- ngOnInit() {
70
- // create the filter form
71
- this.createForm();
72
- this.currentUser = this.currentUserService.getUser();
73
- this.filterForm.valueChanges.subscribe({
74
- next: (value) => {
75
- const params = this.requestHelperService.convertToFormData(value);
76
- this.requestHelperService.updateQueryParams(params);
77
- }
78
- });
79
- // update form with query params
80
- this.requestHelperService.updateFormWithQueryParams(this.filterForm, {
58
+ this.filterFormConfiguration = {
81
59
  role_ids: { multiple: true },
82
60
  status: { multiple: true },
83
- });
84
- // listen for route change
85
- this.activatedRoute.queryParams
86
- .pipe(debounceTime(800), distinctUntilChanged())
87
- .subscribe(() => {
88
- this.reload();
89
- });
90
- }
91
- getUserViewRoute(user) {
92
- return this.isAppAdminUser ? `${user.id}/app-admin-view` : user.id;
93
- }
94
- createForm() {
61
+ user_type_ids: { multiple: true }
62
+ };
95
63
  this.filterForm = this.fb.group({
96
64
  search: [''],
97
65
  role_ids: [''],
@@ -99,20 +67,37 @@ let UsersViewAllComponent = class UsersViewAllComponent extends TechlifyListingC
99
67
  sort_by: ['id|ASC'],
100
68
  relations: ['roles,type,userClients.type,creator,userClient'],
101
69
  appends: ['last_login'],
102
- client_id: [this.clientId]
70
+ client_id: [this.clientId],
71
+ user_type_ids: this.userTypeIds.toString()
103
72
  });
73
+ if (this.config?.scrollContainer) {
74
+ // Set to null if scroll has to be done from root
75
+ this.scrollContainer = this.config?.scrollContainer === 'root' ? null : this.config?.scrollContainer;
76
+ }
77
+ }
78
+ ngOnInit() {
79
+ this.currentUser = this.currentUserService.getUser();
80
+ this.patchFiltersFromRoute();
81
+ this.listenFilterChanges();
82
+ this.loadData();
83
+ }
84
+ getUserViewRoute(user) {
85
+ return this.isAppAdminUser ? `${user.id}/app-admin-view` : user.id;
104
86
  }
105
87
  loadData() {
106
88
  this.isWorking = true;
107
- let params = this.requestHelperService.convertToFormData(this.filterForm.value);
108
89
  const clientId = this.clientId ?? this.currentUser?.client_id;
109
- params = { ...params, num_items: `${this.pageEvent.perPage}|${this.pageEvent.page}`, user_type_ids: this.userTypeIds.toString() };
110
- this.http.get('api/users', { params }).subscribe({
90
+ const params = {
91
+ ...this.filterForm.value,
92
+ status: this.filterForm.value.status ? this.filterForm.value.status.toString() : '',
93
+ page: this.page,
94
+ perPage: this.perPage
95
+ };
96
+ this.service.index(params).subscribe({
111
97
  next: (result) => {
112
98
  this.isWorking = false;
113
99
  this.models = this.models.concat(result?.data);
114
- this.pageEvent.page = result.current_page;
115
- this.pageEvent.lastPage = result.last_page;
100
+ this.lastPage = result?.last_page;
116
101
  this.models.forEach((userData) => {
117
102
  const client = (userData?.user_clients || [])
118
103
  .find((userClient) => userClient.client_id === clientId && userClient.user_id === userData.id);
@@ -140,48 +125,6 @@ let UsersViewAllComponent = class UsersViewAllComponent extends TechlifyListingC
140
125
  }
141
126
  });
142
127
  }
143
- deleteUser(user) {
144
- if (this.currentUser.id !== user?.id) {
145
- const dialogRef = this.dialog.open(ActionPopupComponent, {
146
- width: '400px',
147
- data: {
148
- title: 'Deleting User',
149
- message: `Are you sure to proceed deleting the user ${user.name}?`
150
- },
151
- autoFocus: false
152
- });
153
- dialogRef.afterClosed().subscribe(async (result) => {
154
- if (result) {
155
- // Action confirmed
156
- await this.userService.deleteUser(user.id, { client_id: user.client_id });
157
- this.reload();
158
- }
159
- });
160
- }
161
- else {
162
- this.alertService.addAlert('Current user cannot be deleted', 'warn');
163
- }
164
- }
165
- /**
166
- * Handle the sort change event.
167
- * @param sort Sort
168
- */
169
- onSortChange(sort) {
170
- const direction = sort.direction ? sort.direction : 'asc';
171
- const column = sort.active ? sort.active : 'id';
172
- this.filterForm.get('sort_by').setValue(column + '|' + direction);
173
- }
174
- reload() {
175
- this.models = [];
176
- this.pageEvent = { page: 1, perPage: 25, lastPage: 1 };
177
- this.loadData();
178
- }
179
- onScroll() {
180
- if (this.pageEvent.lastPage > this.pageEvent.page) {
181
- this.pageEvent.page += 1;
182
- this.loadData();
183
- }
184
- }
185
128
  /**
186
129
  * Get the user type for the current client.
187
130
  *
@@ -199,12 +142,12 @@ let UsersViewAllComponent = class UsersViewAllComponent extends TechlifyListingC
199
142
  }
200
143
  resetPassword(user) {
201
144
  this.isWorking = true;
202
- this.userService.resetPassword(user)
145
+ this.service.resetPassword(user)
203
146
  .pipe(finalize(() => this.isWorking = false))
204
147
  .subscribe(_ => this.alertService.addAlert('Password reset email sent', 'success'));
205
148
  }
206
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UsersViewAllComponent, deps: [{ token: i1.HttpService }, { token: i1.AlertService }, { token: i2.CurrentUserService }, { token: i3.UserConfigService }, { token: i4.MatDialog }, { token: i5.UserService }, { token: i6.UntypedFormBuilder }, { token: i7.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component }); }
207
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: UsersViewAllComponent, selector: "app-users-view-all", inputs: { clientId: "clientId", userTypeIds: "userTypeIds", title: "title", isAppAdminUser: "isAppAdminUser" }, usesInheritance: true, ngImport: i0, template: "<div [ngClass]=\"{'m-4':config?.userConfig?.showDefaultMargin}\">\n <mat-card class=\"mb-2\">\n <mat-card-content class=\"d-flex justify-content-between align-items center gap-2\">\n <section class=\"d-flex justify-content-start align-items-center gap-2\">\n <h3 class=\"mb-0\">\n {{ title }}\n </h3>\n <mat-icon class=\"cursor-pointer\" matTooltip=\"New User\"\n *ngIf=\"config?.userConfig?.showAddUser && currentUserService?.hasPermission('user_create')\"\n (click)=\"createOrEditUser()\">add</mat-icon>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../import']\"\n *ngIf=\"config?.userConfig?.showImportButton && currentUserService?.hasPermission('user_create')\">\n Import User\n </button>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../roles']\" *ngIf=\"config?.userConfig?.showRoles\">\n <mat-icon>people</mat-icon>\n Roles\n </button>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../role-permissions']\"\n *ngIf=\"config?.userConfig?.showPermissions\">\n <mat-icon>lock</mat-icon>\n Role Permissions\n </button>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../configurations']\"\n *ngIf=\"config?.userConfig?.showConfigurations && currentUser?.user_type_id === 2\">\n <mat-icon>\n <span class=\"material-icons-outlined\">\n toggle_on\n </span>\n </mat-icon>\n Configurations\n </button>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../restrictors']\"\n *ngIf=\"config?.userConfig?.showRestrictors && currentUser?.user_type_id === 2\">\n <mat-icon>\n <span class=\"material-icons-outlined\">\n vpn_lock\n </span>\n </mat-icon>\n Restrictors\n </button>\n </section>\n <form [formGroup]=\"filterForm\" fxLayout fxLayoutAlign=\"end start\" fxLayoutGap=\"0.3rem\">\n <mat-form-field appearance=\"outline\" style=\"max-width: 150px;\">\n <mat-label>Search</mat-label>\n <input autocomplete=\"off\" matInput type=\"text\" name=\"search\" placeholder=\"Search by name, email\"\n formControlName=\"search\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\" style=\"max-width: 150px;\">\n <mat-label>Role</mat-label>\n <app-searchable-selector apiUrl=\"api/roles\" [multiple]=\"true\" formControlName=\"role_ids\"\n titleField=\"label\"></app-searchable-selector>\n </mat-form-field>\n <mat-button-toggle-group [hideSingleSelectionIndicator]=\"true\" [hideMultipleSelectionIndicator]=\"true\"\n formControlName=\"status\" multiple>\n <mat-button-toggle value=\"enabled\">Enabled</mat-button-toggle>\n <mat-button-toggle value=\"disabled\">Disabled</mat-button-toggle>\n </mat-button-toggle-group>\n </form>\n </mat-card-content>\n </mat-card>\n <mat-card class=\"mt-2 p-0\">\n <mat-card-content>\n <table mat-table [dataSource]=\"models\" class=\"w-100\" aria-describedby=\"Users\" infiniteScroll\n [infiniteScrollDistance]=\"2\" [infiniteScrollThrottle]=\"50\" [infiniteScrollContainer]=\"scrollContainer\"\n [fromRoot]=\"true\" (scrolled)=\"onScroll()\" matSort (matSortChange)=\"onSortChange($event)\">\n <!-- Index Column -->\n <ng-container matColumnDef=\"index\">\n <th mat-header-cell *matHeaderCellDef> # </th>\n <td mat-cell *matCellDef=\"let element; let i = index;\"> {{ i + 1 }} </td>\n </ng-container>\n\n <!-- Name Column -->\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell mat-sort-header=\"name\" *matHeaderCellDef> Name </th>\n <td mat-cell *matCellDef=\"let element\">\n <a [routerLink]=\"[element?.id]\" class=\"text-decoration-none\">\n {{ element.name }}\n </a>\n <p class=\"mb-0 text-secondary\">\n <!-- !element?.user_client condition added to check if user has user_client record -->\n {{ !element?.user_client ? '' : element?.user_client?.is_enabled ? 'Enabled' : 'Disabled' }}\n </p>\n </td>\n </ng-container>\n\n <!-- Email Column -->\n <ng-container matColumnDef=\"email\">\n <th mat-header-cell mat-sort-header=\"email\" *matHeaderCellDef> Email </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.email}} </td>\n </ng-container>\n\n <!-- Type Column -->\n <ng-container matColumnDef=\"type\">\n <th mat-header-cell mat-sort-header=\"user_type_id\" *matHeaderCellDef> User Type </th>\n <td mat-cell *matCellDef=\"let element\"> {{ getUserType(element) }} </td>\n </ng-container>\n\n <!-- Roles Column -->\n <ng-container matColumnDef=\"roles\">\n <th mat-header-cell *matHeaderCellDef> Role </th>\n <td mat-cell *matCellDef=\"let element\">\n <div class=\"d-flex justify-content-start align-items-center gap-1 flex-wrap text-light\">\n <span *ngFor=\"let role of element?.roles\" class=\"badge bg-secondary\">\n {{ role?.label }}\n </span>\n </div>\n </td>\n </ng-container>\n\n <!-- Last Login Column -->\n <ng-container matColumnDef=\"last_login\">\n <th mat-header-cell *matHeaderCellDef> Last Login </th>\n <td mat-cell *matCellDef=\"let element\">{{ element?.last_login | date:'medium' }}</td>\n </ng-container>\n\n <!-- Added By Column -->\n <ng-container matColumnDef=\"added_by\">\n <th mat-header-cell *matHeaderCellDef> Added By </th>\n <td mat-cell *matCellDef=\"let element\">\n <p class=\"mb-0\">{{ element?.creator?.name }}</p>\n <p class=\"text-secondary\">{{ element?.created_at | date }}</p>\n </td>\n </ng-container>\n\n <!-- Actions Column -->\n <ng-container matColumnDef=\"actions\">\n <th mat-header-cell *matHeaderCellDef> Action </th>\n <td mat-cell *matCellDef=\"let element\">\n <div fxLayout fxLayoutAlign=\"start center\" fxLayoutGap=\"5px\">\n <button type=\"button\" mat-icon-button [routerLink]=\"[getUserViewRoute(element)]\">\n <mat-icon>visibility</mat-icon>\n </button>\n\n <button *ngIf=\"currentUserService.hasPermission('user_update')\" type=\"button\" mat-icon-button\n (click)=\"createOrEditUser(element)\">\n <mat-icon>edit</mat-icon>\n </button>\n\n <button *ngIf=\"currentUserService.hasPermission('user_delete')\" type=\"button\" mat-icon-button\n (click)=\"deleteUser(element)\">\n <mat-icon>delete</mat-icon>\n </button>\n\n <button *ngIf=\"currentUserService.hasPermission('techlify_rbac.user.reset_password')\" type=\"button\"\n mat-icon-button (click)=\"resetPassword(element)\" matTooltip=\"Reset User Password\">\n <mat-icon>refresh</mat-icon>\n </button>\n\n <app-user-enable-button [user]=\"element\" (onSave)=\"reload()\"></app-user-enable-button>\n </div>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"></tr>\n </table>\n <mat-progress-bar *ngIf=\"isWorking\" mode=\"indeterminate\"></mat-progress-bar>\n </mat-card-content>\n </mat-card>\n</div>", dependencies: [{ kind: "directive", type: i8.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i8.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i8.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i7.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: i9.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i9.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i10.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i10.MatLabel, selector: "mat-label" }, { kind: "component", type: i11.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i12.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "directive", type: i13.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i13.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "component", type: i14.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i14.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i14.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i14.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i14.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i14.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i14.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i14.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i14.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i14.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i15.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i15.MatCardContent, selector: "mat-card-content" }, { kind: "directive", type: i16.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: i17.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i17.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "component", type: i18.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "directive", type: i19.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i19.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { kind: "directive", type: i19.DefaultLayoutAlignDirective, selector: " [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]", inputs: ["fxLayoutAlign", "fxLayoutAlign.xs", "fxLayoutAlign.sm", "fxLayoutAlign.md", "fxLayoutAlign.lg", "fxLayoutAlign.xl", "fxLayoutAlign.lt-sm", "fxLayoutAlign.lt-md", "fxLayoutAlign.lt-lg", "fxLayoutAlign.lt-xl", "fxLayoutAlign.gt-xs", "fxLayoutAlign.gt-sm", "fxLayoutAlign.gt-md", "fxLayoutAlign.gt-lg"] }, { kind: "directive", type: i20.DefaultClassDirective, selector: " [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]", inputs: ["ngClass", "ngClass.xs", "ngClass.sm", "ngClass.md", "ngClass.lg", "ngClass.xl", "ngClass.lt-sm", "ngClass.lt-md", "ngClass.lt-lg", "ngClass.lt-xl", "ngClass.gt-xs", "ngClass.gt-sm", "ngClass.gt-md", "ngClass.gt-lg"] }, { kind: "directive", type: i6.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i6.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i6.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i6.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i21.InfiniteScrollDirective, selector: "[infiniteScroll], [infinite-scroll], [data-infinite-scroll]", inputs: ["infiniteScrollDistance", "infiniteScrollUpDistance", "infiniteScrollThrottle", "infiniteScrollDisabled", "infiniteScrollContainer", "scrollWindow", "immediateCheck", "horizontal", "alwaysCallback", "fromRoot"], outputs: ["scrolled", "scrolledUp"] }, { kind: "component", type: i22.SearchableSelectorComponent, selector: "app-searchable-selector", inputs: ["valueField", "titleField", "subtitleField", "apiUrl", "multiple", "selectedValue", "enableSearch", "add", "addConfig", "edit", "editConfig", "sort", "sortBy", "searchField", "itemComponent", "items", "apiDataProperty", "cache", "perPage", "inDataSearch", "panelWidth", "focusSearchOnOpen", "isEmitInitialEvent", "required", "disabled", "value"], outputs: ["selectedValueChange", "selectionChange", "itemsChange"] }, { kind: "component", type: i23.UserEnableButtonComponent, selector: "app-user-enable-button", inputs: ["user", "isUseIcons"], outputs: ["onSave"] }, { kind: "pipe", type: i8.DatePipe, name: "date" }] }); }
149
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UsersViewAllComponent, deps: [{ token: i1.AlertService }, { token: i2.CurrentUserService }, { token: i3.UserConfigService }, { token: i4.MatDialog }, { token: i5.UserService }, { token: i6.UntypedFormBuilder }], target: i0.ɵɵFactoryTarget.Component }); }
150
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: UsersViewAllComponent, selector: "app-users-view-all", inputs: { clientId: "clientId", userTypeIds: "userTypeIds", title: "title", isAppAdminUser: "isAppAdminUser" }, usesInheritance: true, ngImport: i0, template: "<div [ngClass]=\"{'m-4':config?.userConfig?.showDefaultMargin}\">\n <mat-card class=\"mb-2\">\n <mat-card-content class=\"d-flex justify-content-between align-items-center gap-2\">\n <section class=\"d-flex justify-content-start align-items-center gap-2\">\n <h5 class=\"mb-0\"> {{ title }} </h5>\n <mat-icon class=\"cursor-pointer\" matTooltip=\"New User\"\n *ngIf=\"config?.userConfig?.showAddUser && currentUserService?.hasPermission('user_create')\"\n (click)=\"createOrEditUser()\">add</mat-icon>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../import']\"\n *ngIf=\"config?.userConfig?.showImportButton && currentUserService?.hasPermission('user_create')\">\n Import User\n </button>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../roles']\" *ngIf=\"config?.userConfig?.showRoles\">\n <mat-icon>people</mat-icon>\n Roles\n </button>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../role-permissions']\"\n *ngIf=\"config?.userConfig?.showPermissions\">\n <mat-icon>lock</mat-icon>\n Role Permissions\n </button>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../configurations']\"\n *ngIf=\"config?.userConfig?.showConfigurations && currentUser?.user_type_id === 2\">\n <mat-icon>\n <span class=\"material-icons-outlined\">\n toggle_on\n </span>\n </mat-icon>\n Configurations\n </button>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../restrictors']\"\n *ngIf=\"config?.userConfig?.showRestrictors && currentUser?.user_type_id === 2\">\n <mat-icon>\n <span class=\"material-icons-outlined\">\n vpn_lock\n </span>\n </mat-icon>\n Restrictors\n </button>\n </section>\n <form [formGroup]=\"filterForm\" class=\"d-flex flex-row justify-content-center align-items-center gap-2\">\n <mat-form-field appearance=\"outline\" class='fl-md'>\n <mat-label>Search</mat-label>\n <input autocomplete=\"off\" matInput type=\"text\" name=\"search\" placeholder=\"Search by name, email\"\n formControlName=\"search\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class='fl-sm'>\n <mat-label>Role</mat-label>\n <app-searchable-selector apiUrl=\"api/roles\" [multiple]=\"true\" formControlName=\"role_ids\"\n titleField=\"label\"></app-searchable-selector>\n </mat-form-field>\n <mat-button-toggle-group class='mb-3' [hideSingleSelectionIndicator]=\"true\" [hideMultipleSelectionIndicator]=\"true\"\n formControlName=\"status\" multiple>\n <mat-button-toggle value=\"enabled\">Enabled</mat-button-toggle>\n <mat-button-toggle value=\"disabled\">Disabled</mat-button-toggle>\n </mat-button-toggle-group>\n </form>\n </mat-card-content>\n </mat-card>\n <mat-card class=\"mt-2 p-0\">\n <mat-card-content>\n <table mat-table [dataSource]=\"models\" class=\"w-100\" aria-describedby=\"Users\" infiniteScroll\n [infiniteScrollDistance]=\"2\" [infiniteScrollThrottle]=\"50\" [infiniteScrollContainer]=\"scrollContainer\"\n [fromRoot]=\"true\" (scrolled)=\"onScroll()\" matSort (matSortChange)=\"sortColumn($event)\">\n <!-- Index Column -->\n <ng-container matColumnDef=\"index\">\n <th mat-header-cell *matHeaderCellDef> # </th>\n <td mat-cell *matCellDef=\"let element; let i = index;\"> {{ i + 1 }} </td>\n </ng-container>\n\n <!-- Name Column -->\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell mat-sort-header=\"name\" *matHeaderCellDef> Name </th>\n <td mat-cell *matCellDef=\"let element\">\n <a [routerLink]=\"[element?.id]\" class=\"text-decoration-none\">\n {{ element.name }}\n </a>\n <p class=\"mb-0 text-secondary\">\n <!-- !element?.user_client condition added to check if user has user_client record -->\n {{ !element?.user_client ? '' : element?.user_client?.is_enabled ? 'Enabled' : 'Disabled' }}\n </p>\n </td>\n </ng-container>\n\n <!-- Email Column -->\n <ng-container matColumnDef=\"email\">\n <th mat-header-cell mat-sort-header=\"email\" *matHeaderCellDef> Email </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.email}} </td>\n </ng-container>\n\n <!-- Type Column -->\n <ng-container matColumnDef=\"type\">\n <th mat-header-cell mat-sort-header=\"user_type_id\" *matHeaderCellDef> User Type </th>\n <td mat-cell *matCellDef=\"let element\"> {{ getUserType(element) }} </td>\n </ng-container>\n\n <!-- Roles Column -->\n <ng-container matColumnDef=\"roles\">\n <th mat-header-cell *matHeaderCellDef> Role </th>\n <td mat-cell *matCellDef=\"let element\">\n <div class=\"d-flex justify-content-start align-items-center gap-1 flex-wrap text-light\">\n <span *ngFor=\"let role of element?.roles\" class=\"badge bg-secondary\">\n {{ role?.label }}\n </span>\n </div>\n </td>\n </ng-container>\n\n <!-- Last Login Column -->\n <ng-container matColumnDef=\"last_login\">\n <th mat-header-cell *matHeaderCellDef> Last Login </th>\n <td mat-cell *matCellDef=\"let element\">{{ element?.last_login | date:'medium' }}</td>\n </ng-container>\n\n <!-- Added By Column -->\n <ng-container matColumnDef=\"added_by\">\n <th mat-header-cell *matHeaderCellDef> Added By </th>\n <td mat-cell *matCellDef=\"let element\">\n <p class=\"mb-0\">{{ element?.creator?.name }}</p>\n <p class=\"text-secondary\">{{ element?.created_at | date }}</p>\n </td>\n </ng-container>\n\n <!-- Actions Column -->\n <ng-container matColumnDef=\"actions\">\n <th mat-header-cell *matHeaderCellDef> Action </th>\n <td mat-cell *matCellDef=\"let element\">\n <div class=\"d-flex flex-row justify-content-start align-items-center gap-2 text-secondary\">\n <app-techlify-icon role='button' name=\"view\" class=\"clickable\" [routerLink]=\"[getUserViewRoute(element)]\"\n matTooltip=\"View\"></app-techlify-icon>\n\n <app-techlify-icon role='button' *ngIf=\"currentUserService.hasPermission('user_update')\" name=\"edit\"\n class=\"clickable\" (click)=\"createOrEditUser(element)\" matTooltip=\"Edit\"></app-techlify-icon>\n\n <app-techlify-delete-button\n *ngIf=\"currentUserService.hasPermission('user_delete') && element?.id !== currentUser?.id\"\n [model]=\"element\" [service]=\"service\" [data]=\"{title: element?.name, type: 'user'}\"\n (deleted)=\"reload()\"></app-techlify-delete-button>\n\n <app-techlify-icon role='button'\n *ngIf=\"currentUserService.hasPermission('techlify_rbac.user.reset_password')\" name=\"reset\"\n class=\"clickable\" (click)=\"resetPassword(element)\" matTooltip=\"Reset User Password\"></app-techlify-icon>\n\n <app-user-enable-button [user]=\"element\" (onSave)=\"reload()\"></app-user-enable-button>\n </div>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"></tr>\n </table>\n <mat-progress-bar *ngIf=\"isWorking\" mode=\"indeterminate\"></mat-progress-bar>\n </mat-card-content>\n </mat-card>\n</div>", dependencies: [{ kind: "directive", type: i7.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i8.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: i9.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i10.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i10.MatLabel, selector: "mat-label" }, { kind: "component", type: i11.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i12.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "directive", type: i13.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i13.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "component", type: i14.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i14.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i14.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i14.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i14.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i14.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i14.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i14.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i14.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i14.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i15.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i15.MatCardContent, selector: "mat-card-content" }, { kind: "directive", type: i16.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: i17.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i17.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "component", type: i18.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "directive", type: i19.DefaultClassDirective, selector: " [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]", inputs: ["ngClass", "ngClass.xs", "ngClass.sm", "ngClass.md", "ngClass.lg", "ngClass.xl", "ngClass.lt-sm", "ngClass.lt-md", "ngClass.lt-lg", "ngClass.lt-xl", "ngClass.gt-xs", "ngClass.gt-sm", "ngClass.gt-md", "ngClass.gt-lg"] }, { kind: "directive", type: i6.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i6.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i6.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i6.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i20.InfiniteScrollDirective, selector: "[infiniteScroll], [infinite-scroll], [data-infinite-scroll]", inputs: ["infiniteScrollDistance", "infiniteScrollUpDistance", "infiniteScrollThrottle", "infiniteScrollDisabled", "infiniteScrollContainer", "scrollWindow", "immediateCheck", "horizontal", "alwaysCallback", "fromRoot"], outputs: ["scrolled", "scrolledUp"] }, { kind: "component", type: i21.SearchableSelectorComponent, selector: "app-searchable-selector", inputs: ["valueField", "titleField", "subtitleField", "apiUrl", "multiple", "selectedValue", "enableSearch", "add", "addConfig", "edit", "editConfig", "sort", "sortBy", "searchField", "itemComponent", "items", "apiDataProperty", "cache", "perPage", "inDataSearch", "panelWidth", "focusSearchOnOpen", "isEmitInitialEvent", "required", "disabled", "value"], outputs: ["selectedValueChange", "selectionChange", "itemsChange"] }, { kind: "component", type: i22.UserEnableButtonComponent, selector: "app-user-enable-button", inputs: ["user", "isUseIcons"], outputs: ["onSave"] }, { kind: "component", type: i23.TechlifyIconComponent, selector: "app-techlify-icon", inputs: ["name", "size"] }, { kind: "component", type: i24.TechlifyDeleteButtonComponent, selector: "app-techlify-delete-button", inputs: ["data", "model", "message", "service"], outputs: ["deleted"] }, { kind: "pipe", type: i7.DatePipe, name: "date" }] }); }
208
151
  };
209
152
  UsersViewAllComponent = __decorate([
210
153
  UntilDestroy()
@@ -212,8 +155,8 @@ UsersViewAllComponent = __decorate([
212
155
  export { UsersViewAllComponent };
213
156
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UsersViewAllComponent, decorators: [{
214
157
  type: Component,
215
- args: [{ selector: 'app-users-view-all', template: "<div [ngClass]=\"{'m-4':config?.userConfig?.showDefaultMargin}\">\n <mat-card class=\"mb-2\">\n <mat-card-content class=\"d-flex justify-content-between align-items center gap-2\">\n <section class=\"d-flex justify-content-start align-items-center gap-2\">\n <h3 class=\"mb-0\">\n {{ title }}\n </h3>\n <mat-icon class=\"cursor-pointer\" matTooltip=\"New User\"\n *ngIf=\"config?.userConfig?.showAddUser && currentUserService?.hasPermission('user_create')\"\n (click)=\"createOrEditUser()\">add</mat-icon>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../import']\"\n *ngIf=\"config?.userConfig?.showImportButton && currentUserService?.hasPermission('user_create')\">\n Import User\n </button>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../roles']\" *ngIf=\"config?.userConfig?.showRoles\">\n <mat-icon>people</mat-icon>\n Roles\n </button>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../role-permissions']\"\n *ngIf=\"config?.userConfig?.showPermissions\">\n <mat-icon>lock</mat-icon>\n Role Permissions\n </button>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../configurations']\"\n *ngIf=\"config?.userConfig?.showConfigurations && currentUser?.user_type_id === 2\">\n <mat-icon>\n <span class=\"material-icons-outlined\">\n toggle_on\n </span>\n </mat-icon>\n Configurations\n </button>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../restrictors']\"\n *ngIf=\"config?.userConfig?.showRestrictors && currentUser?.user_type_id === 2\">\n <mat-icon>\n <span class=\"material-icons-outlined\">\n vpn_lock\n </span>\n </mat-icon>\n Restrictors\n </button>\n </section>\n <form [formGroup]=\"filterForm\" fxLayout fxLayoutAlign=\"end start\" fxLayoutGap=\"0.3rem\">\n <mat-form-field appearance=\"outline\" style=\"max-width: 150px;\">\n <mat-label>Search</mat-label>\n <input autocomplete=\"off\" matInput type=\"text\" name=\"search\" placeholder=\"Search by name, email\"\n formControlName=\"search\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\" style=\"max-width: 150px;\">\n <mat-label>Role</mat-label>\n <app-searchable-selector apiUrl=\"api/roles\" [multiple]=\"true\" formControlName=\"role_ids\"\n titleField=\"label\"></app-searchable-selector>\n </mat-form-field>\n <mat-button-toggle-group [hideSingleSelectionIndicator]=\"true\" [hideMultipleSelectionIndicator]=\"true\"\n formControlName=\"status\" multiple>\n <mat-button-toggle value=\"enabled\">Enabled</mat-button-toggle>\n <mat-button-toggle value=\"disabled\">Disabled</mat-button-toggle>\n </mat-button-toggle-group>\n </form>\n </mat-card-content>\n </mat-card>\n <mat-card class=\"mt-2 p-0\">\n <mat-card-content>\n <table mat-table [dataSource]=\"models\" class=\"w-100\" aria-describedby=\"Users\" infiniteScroll\n [infiniteScrollDistance]=\"2\" [infiniteScrollThrottle]=\"50\" [infiniteScrollContainer]=\"scrollContainer\"\n [fromRoot]=\"true\" (scrolled)=\"onScroll()\" matSort (matSortChange)=\"onSortChange($event)\">\n <!-- Index Column -->\n <ng-container matColumnDef=\"index\">\n <th mat-header-cell *matHeaderCellDef> # </th>\n <td mat-cell *matCellDef=\"let element; let i = index;\"> {{ i + 1 }} </td>\n </ng-container>\n\n <!-- Name Column -->\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell mat-sort-header=\"name\" *matHeaderCellDef> Name </th>\n <td mat-cell *matCellDef=\"let element\">\n <a [routerLink]=\"[element?.id]\" class=\"text-decoration-none\">\n {{ element.name }}\n </a>\n <p class=\"mb-0 text-secondary\">\n <!-- !element?.user_client condition added to check if user has user_client record -->\n {{ !element?.user_client ? '' : element?.user_client?.is_enabled ? 'Enabled' : 'Disabled' }}\n </p>\n </td>\n </ng-container>\n\n <!-- Email Column -->\n <ng-container matColumnDef=\"email\">\n <th mat-header-cell mat-sort-header=\"email\" *matHeaderCellDef> Email </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.email}} </td>\n </ng-container>\n\n <!-- Type Column -->\n <ng-container matColumnDef=\"type\">\n <th mat-header-cell mat-sort-header=\"user_type_id\" *matHeaderCellDef> User Type </th>\n <td mat-cell *matCellDef=\"let element\"> {{ getUserType(element) }} </td>\n </ng-container>\n\n <!-- Roles Column -->\n <ng-container matColumnDef=\"roles\">\n <th mat-header-cell *matHeaderCellDef> Role </th>\n <td mat-cell *matCellDef=\"let element\">\n <div class=\"d-flex justify-content-start align-items-center gap-1 flex-wrap text-light\">\n <span *ngFor=\"let role of element?.roles\" class=\"badge bg-secondary\">\n {{ role?.label }}\n </span>\n </div>\n </td>\n </ng-container>\n\n <!-- Last Login Column -->\n <ng-container matColumnDef=\"last_login\">\n <th mat-header-cell *matHeaderCellDef> Last Login </th>\n <td mat-cell *matCellDef=\"let element\">{{ element?.last_login | date:'medium' }}</td>\n </ng-container>\n\n <!-- Added By Column -->\n <ng-container matColumnDef=\"added_by\">\n <th mat-header-cell *matHeaderCellDef> Added By </th>\n <td mat-cell *matCellDef=\"let element\">\n <p class=\"mb-0\">{{ element?.creator?.name }}</p>\n <p class=\"text-secondary\">{{ element?.created_at | date }}</p>\n </td>\n </ng-container>\n\n <!-- Actions Column -->\n <ng-container matColumnDef=\"actions\">\n <th mat-header-cell *matHeaderCellDef> Action </th>\n <td mat-cell *matCellDef=\"let element\">\n <div fxLayout fxLayoutAlign=\"start center\" fxLayoutGap=\"5px\">\n <button type=\"button\" mat-icon-button [routerLink]=\"[getUserViewRoute(element)]\">\n <mat-icon>visibility</mat-icon>\n </button>\n\n <button *ngIf=\"currentUserService.hasPermission('user_update')\" type=\"button\" mat-icon-button\n (click)=\"createOrEditUser(element)\">\n <mat-icon>edit</mat-icon>\n </button>\n\n <button *ngIf=\"currentUserService.hasPermission('user_delete')\" type=\"button\" mat-icon-button\n (click)=\"deleteUser(element)\">\n <mat-icon>delete</mat-icon>\n </button>\n\n <button *ngIf=\"currentUserService.hasPermission('techlify_rbac.user.reset_password')\" type=\"button\"\n mat-icon-button (click)=\"resetPassword(element)\" matTooltip=\"Reset User Password\">\n <mat-icon>refresh</mat-icon>\n </button>\n\n <app-user-enable-button [user]=\"element\" (onSave)=\"reload()\"></app-user-enable-button>\n </div>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"></tr>\n </table>\n <mat-progress-bar *ngIf=\"isWorking\" mode=\"indeterminate\"></mat-progress-bar>\n </mat-card-content>\n </mat-card>\n</div>" }]
216
- }], ctorParameters: () => [{ type: i1.HttpService }, { type: i1.AlertService }, { type: i2.CurrentUserService }, { type: i3.UserConfigService }, { type: i4.MatDialog }, { type: i5.UserService }, { type: i6.UntypedFormBuilder }, { type: i7.ActivatedRoute }], propDecorators: { clientId: [{
158
+ args: [{ selector: 'app-users-view-all', template: "<div [ngClass]=\"{'m-4':config?.userConfig?.showDefaultMargin}\">\n <mat-card class=\"mb-2\">\n <mat-card-content class=\"d-flex justify-content-between align-items-center gap-2\">\n <section class=\"d-flex justify-content-start align-items-center gap-2\">\n <h5 class=\"mb-0\"> {{ title }} </h5>\n <mat-icon class=\"cursor-pointer\" matTooltip=\"New User\"\n *ngIf=\"config?.userConfig?.showAddUser && currentUserService?.hasPermission('user_create')\"\n (click)=\"createOrEditUser()\">add</mat-icon>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../import']\"\n *ngIf=\"config?.userConfig?.showImportButton && currentUserService?.hasPermission('user_create')\">\n Import User\n </button>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../roles']\" *ngIf=\"config?.userConfig?.showRoles\">\n <mat-icon>people</mat-icon>\n Roles\n </button>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../role-permissions']\"\n *ngIf=\"config?.userConfig?.showPermissions\">\n <mat-icon>lock</mat-icon>\n Role Permissions\n </button>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../configurations']\"\n *ngIf=\"config?.userConfig?.showConfigurations && currentUser?.user_type_id === 2\">\n <mat-icon>\n <span class=\"material-icons-outlined\">\n toggle_on\n </span>\n </mat-icon>\n Configurations\n </button>\n <button mat-raised-button type=\"button\" [routerLink]=\"['../restrictors']\"\n *ngIf=\"config?.userConfig?.showRestrictors && currentUser?.user_type_id === 2\">\n <mat-icon>\n <span class=\"material-icons-outlined\">\n vpn_lock\n </span>\n </mat-icon>\n Restrictors\n </button>\n </section>\n <form [formGroup]=\"filterForm\" class=\"d-flex flex-row justify-content-center align-items-center gap-2\">\n <mat-form-field appearance=\"outline\" class='fl-md'>\n <mat-label>Search</mat-label>\n <input autocomplete=\"off\" matInput type=\"text\" name=\"search\" placeholder=\"Search by name, email\"\n formControlName=\"search\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class='fl-sm'>\n <mat-label>Role</mat-label>\n <app-searchable-selector apiUrl=\"api/roles\" [multiple]=\"true\" formControlName=\"role_ids\"\n titleField=\"label\"></app-searchable-selector>\n </mat-form-field>\n <mat-button-toggle-group class='mb-3' [hideSingleSelectionIndicator]=\"true\" [hideMultipleSelectionIndicator]=\"true\"\n formControlName=\"status\" multiple>\n <mat-button-toggle value=\"enabled\">Enabled</mat-button-toggle>\n <mat-button-toggle value=\"disabled\">Disabled</mat-button-toggle>\n </mat-button-toggle-group>\n </form>\n </mat-card-content>\n </mat-card>\n <mat-card class=\"mt-2 p-0\">\n <mat-card-content>\n <table mat-table [dataSource]=\"models\" class=\"w-100\" aria-describedby=\"Users\" infiniteScroll\n [infiniteScrollDistance]=\"2\" [infiniteScrollThrottle]=\"50\" [infiniteScrollContainer]=\"scrollContainer\"\n [fromRoot]=\"true\" (scrolled)=\"onScroll()\" matSort (matSortChange)=\"sortColumn($event)\">\n <!-- Index Column -->\n <ng-container matColumnDef=\"index\">\n <th mat-header-cell *matHeaderCellDef> # </th>\n <td mat-cell *matCellDef=\"let element; let i = index;\"> {{ i + 1 }} </td>\n </ng-container>\n\n <!-- Name Column -->\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell mat-sort-header=\"name\" *matHeaderCellDef> Name </th>\n <td mat-cell *matCellDef=\"let element\">\n <a [routerLink]=\"[element?.id]\" class=\"text-decoration-none\">\n {{ element.name }}\n </a>\n <p class=\"mb-0 text-secondary\">\n <!-- !element?.user_client condition added to check if user has user_client record -->\n {{ !element?.user_client ? '' : element?.user_client?.is_enabled ? 'Enabled' : 'Disabled' }}\n </p>\n </td>\n </ng-container>\n\n <!-- Email Column -->\n <ng-container matColumnDef=\"email\">\n <th mat-header-cell mat-sort-header=\"email\" *matHeaderCellDef> Email </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.email}} </td>\n </ng-container>\n\n <!-- Type Column -->\n <ng-container matColumnDef=\"type\">\n <th mat-header-cell mat-sort-header=\"user_type_id\" *matHeaderCellDef> User Type </th>\n <td mat-cell *matCellDef=\"let element\"> {{ getUserType(element) }} </td>\n </ng-container>\n\n <!-- Roles Column -->\n <ng-container matColumnDef=\"roles\">\n <th mat-header-cell *matHeaderCellDef> Role </th>\n <td mat-cell *matCellDef=\"let element\">\n <div class=\"d-flex justify-content-start align-items-center gap-1 flex-wrap text-light\">\n <span *ngFor=\"let role of element?.roles\" class=\"badge bg-secondary\">\n {{ role?.label }}\n </span>\n </div>\n </td>\n </ng-container>\n\n <!-- Last Login Column -->\n <ng-container matColumnDef=\"last_login\">\n <th mat-header-cell *matHeaderCellDef> Last Login </th>\n <td mat-cell *matCellDef=\"let element\">{{ element?.last_login | date:'medium' }}</td>\n </ng-container>\n\n <!-- Added By Column -->\n <ng-container matColumnDef=\"added_by\">\n <th mat-header-cell *matHeaderCellDef> Added By </th>\n <td mat-cell *matCellDef=\"let element\">\n <p class=\"mb-0\">{{ element?.creator?.name }}</p>\n <p class=\"text-secondary\">{{ element?.created_at | date }}</p>\n </td>\n </ng-container>\n\n <!-- Actions Column -->\n <ng-container matColumnDef=\"actions\">\n <th mat-header-cell *matHeaderCellDef> Action </th>\n <td mat-cell *matCellDef=\"let element\">\n <div class=\"d-flex flex-row justify-content-start align-items-center gap-2 text-secondary\">\n <app-techlify-icon role='button' name=\"view\" class=\"clickable\" [routerLink]=\"[getUserViewRoute(element)]\"\n matTooltip=\"View\"></app-techlify-icon>\n\n <app-techlify-icon role='button' *ngIf=\"currentUserService.hasPermission('user_update')\" name=\"edit\"\n class=\"clickable\" (click)=\"createOrEditUser(element)\" matTooltip=\"Edit\"></app-techlify-icon>\n\n <app-techlify-delete-button\n *ngIf=\"currentUserService.hasPermission('user_delete') && element?.id !== currentUser?.id\"\n [model]=\"element\" [service]=\"service\" [data]=\"{title: element?.name, type: 'user'}\"\n (deleted)=\"reload()\"></app-techlify-delete-button>\n\n <app-techlify-icon role='button'\n *ngIf=\"currentUserService.hasPermission('techlify_rbac.user.reset_password')\" name=\"reset\"\n class=\"clickable\" (click)=\"resetPassword(element)\" matTooltip=\"Reset User Password\"></app-techlify-icon>\n\n <app-user-enable-button [user]=\"element\" (onSave)=\"reload()\"></app-user-enable-button>\n </div>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"></tr>\n </table>\n <mat-progress-bar *ngIf=\"isWorking\" mode=\"indeterminate\"></mat-progress-bar>\n </mat-card-content>\n </mat-card>\n</div>" }]
159
+ }], ctorParameters: () => [{ type: i1.AlertService }, { type: i2.CurrentUserService }, { type: i3.UserConfigService }, { type: i4.MatDialog }, { type: i5.UserService }, { type: i6.UntypedFormBuilder }], propDecorators: { clientId: [{
217
160
  type: Input
218
161
  }], userTypeIds: [{
219
162
  type: Input
@@ -222,4 +165,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
222
165
  }], isAppAdminUser: [{
223
166
  type: Input
224
167
  }] } });
225
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNlcnMtdmlldy1hbGwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LXRlY2hsaWZ5LWNvcmUvc3JjL2xpYi91c2VyL3VzZXJzLXZpZXctYWxsLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC10ZWNobGlmeS1jb3JlL3NyYy9saWIvdXNlci91c2Vycy12aWV3LWFsbC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFVLEtBQUssRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUt6RCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUcxRCxPQUFPLEVBQUUsWUFBWSxFQUFFLG9CQUFvQixFQUFFLFFBQVEsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzlFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUtyRCxPQUFPLEVBQWUsb0JBQW9CLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNwRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDaEQsT0FBTyxFQUFFLGtDQUFrQyxFQUFFLE1BQU0sZUFBZSxDQUFDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBUzVELElBQU0scUJBQXFCLEdBQTNCLE1BQU0scUJBQXNCLFNBQVEsa0NBQWtDO0lBMkIzRSxZQUNVLElBQWlCLEVBQ2pCLFlBQTBCLEVBQzNCLGtCQUFzQyxFQUN0QyxpQkFBb0MsRUFDbkMsTUFBaUIsRUFDakIsV0FBd0IsRUFDeEIsRUFBc0IsRUFDdEIsY0FBOEI7UUFFdEMsS0FBSyxFQUFFLENBQUM7UUFUQSxTQUFJLEdBQUosSUFBSSxDQUFhO1FBQ2pCLGlCQUFZLEdBQVosWUFBWSxDQUFjO1FBQzNCLHVCQUFrQixHQUFsQixrQkFBa0IsQ0FBb0I7UUFDdEMsc0JBQWlCLEdBQWpCLGlC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QUMsSUFBSSxFQUFFLFNBQVMsS0FBSyxJQUFJLENBQUMsV0FBVyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBQy9HLENBQUM7UUFDRCxPQUFPLFVBQVUsRUFBRSxJQUFJLEVBQUUsS0FBSyxJQUFJLEVBQUUsQ0FBQztJQUN2QyxDQUFDO0lBRUQsYUFBYSxDQUFDLElBQVM7UUFDckIsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUM7UUFDdEIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDO2FBQ2pDLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsR0FBRyxLQUFLLENBQUMsQ0FBQzthQUM1QyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsQ0FBQywyQkFBMkIsRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDO0lBQ3hGLENBQUM7K0dBMU1VLHFCQUFxQjttR0FBckIscUJBQXFCLGlNQ3pCbEMsbXFQQWdLTTs7QUR2SU8scUJBQXFCO0lBTmpDLFlBQVksRUFBRTtHQU1GLHFCQUFxQixDQTJNakM7OzRGQTNNWSxxQkFBcUI7a0JBTGpDLFNBQVM7K0JBRUUsb0JBQW9COzRSQU1yQixRQUFRO3NCQUFoQixLQUFLO2dCQUNHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBTUcsS0FBSztzQkFBYixLQUFLO2dCQWVHLGNBQWM7c0JBQXRCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIE9uSW5pdCwgSW5wdXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFVzZXIgfSBmcm9tICcuL3VzZXIubW9kZWwnO1xuaW1wb3J0IHsgQ3VycmVudFVzZXJTZXJ2aWNlIH0gZnJvbSAnLi9jdXJyZW50LXVzZXIuc2VydmljZSc7XG5pbXBvcnQgeyBNYXREaWFsb2cgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9kaWFsb2cnO1xuaW1wb3J0IHsgVXNlclNlcnZpY2UgfSBmcm9tICcuL3VzZXIuc2VydmljZSc7XG5pbXBvcnQgeyBVc2VyRm9ybUNvbXBvbmVudCB9IGZyb20gJy4vdXNlci1mb3JtLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBNdWx0aVVzZXJDb25maWcsIFVzZXJDb25maWdTZXJ2aWNlIH0gZnJvbSAnLi4vdXNlci1jb25maWcnO1xuaW1wb3J0IHsgVW50eXBlZEZvcm1CdWlsZGVyIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgZGVib3VuY2VUaW1lLCBkaXN0aW5jdFVudGlsQ2hhbmdlZCwgZmluYWxpemUgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBVbnRpbERlc3Ryb3kgfSBmcm9tICdAbmduZWF0L3VudGlsLWRlc3Ryb3knO1xuaW1wb3J0IHsgU29ydCB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3NvcnQnO1xuaW1wb3J0IHsgUGFnZUV2ZW50IH0gZnJvbSAnLi4vZGF0YS10YWJsZSc7XG5pbXBvcnQgeyBBbGVydFNlcnZpY2UsIEh0dHBTZXJ2aWNlIH0gZnJvbSAnLi4vY29yZSc7XG5pbXBvcnQgeyBSZXF1ZXN0SGVscGVyU2VydmljZSB9IGZyb20gJy4uL3JlcXVlc3QtaGVscGVyL3JlcXVlc3QtaGVscGVyLnNlcnZpY2UnO1xuaW1wb3J0IHsgQWN0aW9uUG9wdXAsIEFjdGlvblBvcHVwQ29tcG9uZW50IH0gZnJvbSAnLi4vYWN0aW9uLXBvcHVwJztcbmltcG9ydCB7IFVzZXJUeXBlRW51bSB9IGZyb20gJy4vdXNlci10eXBlLmVudW0nO1xuaW1wb3J0IHsgVGVjaGxpZnlMaXN0aW5nQ29udHJvbGxlckludGVyZmFjZSB9IGZyb20gJy4uL2Jhc2UtbW9kZWwnO1xuaW1wb3J0IHsgQWN0aXZhdGVkUm91dGUgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xuXG5AVW50aWxEZXN0cm95KClcbkBDb21wb25lbnQoe1xuICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6Y29tcG9uZW50LXNlbGVjdG9yXG4gIHNlbGVjdG9yOiAnYXBwLXVzZXJzLXZpZXctYWxsJyxcbiAgdGVtcGxhdGVVcmw6ICcuL3VzZXJzLXZpZXctYWxsLmh0bWwnXG59KVxuZXhwb3J0IGNsYXNzIFVzZXJzVmlld0FsbENvbXBvbmVudCBleHRlbmRzIFRlY2hsaWZ5TGlzdGluZ0NvbnRyb2xsZXJJbnRlcmZhY2UgaW1wbGVtZW50cyBPbkluaXQge1xuXG4gIC8vIEZvciBhZG1pbiBwYWdlIHdlIG5lZWQgdG8gcGFzcyB0aGUgY2xpZW50IElkXG4gIEBJbnB1dCgpIGNsaWVudElkOiBudW1iZXI7XG4gIEBJbnB1dCgpIHVzZXJUeXBlSWRzOiBudW1iZXJbXSA9IFtdO1xuXG4gIGN1cnJlbnRVc2VyOiBVc2VyO1xuICBpc1dvcmtpbmcgPSBmYWxzZTtcbiAgY29uZmlnOiBNdWx0aVVzZXJDb25maWc7XG4gIHVzZXI6IFVzZXI7XG4gIEBJbnB1dCgpIHRpdGxlID0gJ1VzZXIgTWFuYWdlbWVudCc7XG4gIHBhZ2VFdmVudDogUGFnZUV2ZW50ID0geyBwYWdlOiAxLCBwZXJQYWdlOiAyNSwgbGFzdFBhZ2U6IDEgfTtcbiAgZGlzcGxheWVkQ29sdW1uczogc3RyaW5nW10gPSBbXG4gICAgJ2luZGV4JyxcbiAgICAnbmFtZScsXG4gICAgJ2VtYWlsJyxcbiAgICAndHlwZScsXG4gICAgJ3JvbGVzJyxcbiAgICAnbGFzdF9sb2dpbicsXG4gICAgJ2FkZGVkX2J5JyxcbiAgICAnYWN0aW9ucydcbiAgXTtcblxuICBzY3JvbGxDb250YWluZXIgPSAnLm1hdC1zaWRlbmF2LWNvbnRlbnQnO1xuICBtb2RlbHM6IGFueVtdID0gW107XG4gIEBJbnB1dCgpIGlzQXBwQWRtaW5Vc2VyOiBib29sZWFuID0gZmFsc2U7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBodHRwOiBIdHRwU2VydmljZSxcbiAgICBwcml2YXRlIGFsZXJ0U2VydmljZTogQWxlcnRTZXJ2aWNlLFxuICAgIHB1YmxpYyBjdXJyZW50VXNlclNlcnZpY2U6IEN1cnJlbnRVc2VyU2VydmljZSxcbiAgICBwdWJsaWMgdXNlckNvbmZpZ1NlcnZpY2U6IFVzZXJDb25maWdTZXJ2aWNlLFxuICAgIHByaXZhdGUgZGlhbG9nOiBNYXREaWFsb2csXG4gICAgcHJpdmF0ZSB1c2VyU2VydmljZTogVXNlclNlcnZpY2UsXG4gICAgcHJpdmF0ZSBmYjogVW50eXBlZEZvcm1CdWlsZGVyLFxuICAgIHByaXZhdGUgYWN0aXZhdGVkUm91dGU6IEFjdGl2YXRlZFJvdXRlXG4gICkge1xuICAgIHN1cGVyKCk7XG4gICAgdGhpcy5sYXN0UGFnZSA9IDA7XG4gICAgdGhpcy5jb25maWcgPSB0aGlzLnVzZXJDb25maWdTZXJ2aWNlLmdldENvbmZpZygpO1xuXG4gICAgaWYgKHRoaXMuY29uZmlnPy5zY3JvbGxDb250YWluZXIpIHtcbiAgICAgIC8vIFNldCB0byBudWxsIGlmIHNjcm9sbCBoYXMgdG8gYmUgZG9uZSBmcm9tIHJvb3RcbiAgICAgIHRoaXMuc2Nyb2xsQ29udGFpbmVyID0gdGhpcy5jb25maWc/LnNjcm9sbENvbnRhaW5lciA9PT0gJ3Jvb3QnID8gbnVsbCA6IHRoaXMuY29uZmlnPy5zY3JvbGxDb250YWluZXI7XG4gICAgfVxuICB9XG5cbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOnR5cGVkZWZcbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgLy8gY3JlYXRlIHRoZSBmaWx0ZXIgZm9ybVxuICAgIHRoaXMuY3JlYXRlRm9ybSgpO1xuICAgIHRoaXMuY3VycmVudFVzZXIgPSB0aGlzLmN1cnJlbnRVc2VyU2VydmljZS5nZXRVc2VyKCk7XG5cbiAgICB0aGlzLmZpbHRlckZvcm0udmFsdWVDaGFuZ2VzLnN1YnNjcmliZSh7XG4gICAgICBuZXh0OiAodmFsdWU6IGFueSkgPT4ge1xuICAgICAgICBjb25zdCBwYXJhbXM6IGFueSA9IHRoaXMucmVxdWVzdEhlbHBlclNlcnZpY2UuY29udmVydFRvRm9ybURhdGEodmFsdWUpO1xuICAgICAgICB0aGlzLnJlcXVlc3RIZWxwZXJTZXJ2aWNlLnVwZGF0ZVF1ZXJ5UGFyYW1zKHBhcmFtcyk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICAvLyB1cGRhdGUgZm9ybSB3aXRoIHF1ZXJ5IHBhcmFtc1xuICAgIHRoaXMucmVxdWVzdEhlbHBlclNlcnZpY2UudXBkYXRlRm9ybVdpdGhRdWVyeVBhcmFtcyh0aGlzLmZpbHRlckZvcm0sIHtcbiAgICAgIHJvbGVfaWRzOiB7IG11bHRpcGxlOiB0cnVlIH0sXG4gICAgICBzdGF0dXM6IHsgbXVsdGlwbGU6IHRydWUgfSxcbiAgICB9KTtcblxuICAgIC8vIGxpc3RlbiBmb3Igcm91dGUgY2hhbmdlXG4gICAgdGhpcy5hY3RpdmF0ZWRSb3V0ZS5xdWVyeVBhcmFtc1xuICAgICAgLnBpcGUoZGVib3VuY2VUaW1lKDgwMCksIGRpc3RpbmN0VW50aWxDaGFuZ2VkKCkpXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgICAgdGhpcy5yZWxvYWQoKTtcbiAgICAgIH0pO1xuICB9XG5cbiAgZ2V0VXNlclZpZXdSb3V0ZSh1c2VyOiBhbnkpIHtcbiAgICByZXR1cm4gdGhpcy5pc0FwcEFkbWluVXNlciA/IGAke3VzZXIuaWR9L2FwcC1hZG1pbi12aWV3YCA6IHVzZXIuaWQ7XG4gIH1cblxuICBwcml2YXRlIGNyZWF0ZUZvcm0oKTogdm9pZCB7XG4gICAgdGhpcy5maWx0ZXJGb3JtID0gdGhpcy5mYi5ncm91cCh7XG4gICAgICBzZWFyY2g6IFsnJ10sXG4gICAgICByb2xlX2lkczogWycnXSxcbiAgICAgIHN0YXR1czogWydlbmFibGVkJ10sXG4gICAgICBzb3J0X2J5OiBbJ2lkfEFTQyddLFxuICAgICAgcmVsYXRpb25zOiBbJ3JvbGVzLHR5cGUsdXNlckNsaWVudHMudHlwZSxjcmVhdG9yLHVzZXJDbGllbnQnXSxcbiAgICAgIGFwcGVuZHM6IFsnbGFzdF9sb2dpbiddLFxuICAgICAgY2xpZW50X2lkOiBbdGhpcy5jbGllbnRJZF1cbiAgICB9KTtcbiAgfVxuXG4gIGxvYWREYXRhKCk6IHZvaWQge1xuICAgIHRoaXMuaXNXb3JraW5nID0gdHJ1ZTtcbiAgICBsZXQgcGFyYW1zOiBhbnkgPSB0aGlzLnJlcXVlc3RIZWxwZXJTZXJ2aWNlLmNvbnZlcnRUb0Zvcm1EYXRhKHRoaXMuZmlsdGVyRm9ybS52YWx1ZSk7XG4gICAgY29uc3QgY2xpZW50SWQgPSB0aGlzLmNsaWVudElkID8/IHRoaXMuY3VycmVudFVzZXI/LmNsaWVudF9pZDtcbiAgICBwYXJhbXMgPSB7IC4uLnBhcmFtcywgbnVtX2l0ZW1zOiBgJHt0aGlzLnBhZ2VFdmVudC5wZXJQYWdlfXwke3RoaXMucGFnZUV2ZW50LnBhZ2V9YCwgdXNlcl90eXBlX2lkczogdGhpcy51c2VyVHlwZUlkcy50b1N0cmluZygpIH07XG5cbiAgICB0aGlzLmh0dHAuZ2V0KCdhcGkvdXNlcnMnLCB7IHBhcmFtcyB9KS5zdWJzY3JpYmUoe1xuICAgICAgbmV4dDogKHJlc3VsdDogYW55KSA9PiB7XG4gICAgICAgIHRoaXMuaXNXb3JraW5nID0gZmFsc2U7XG4gICAgICAgIHRoaXMubW9kZWxzID0gdGhpcy5tb2RlbHMuY29uY2F0KHJlc3VsdD8uZGF0YSk7XG4gICAgICAgIHRoaXMucGFnZUV2ZW50LnBhZ2UgPSByZXN1bHQuY3VycmVudF9wYWdlO1xuICAgICAgICB0aGlzLnBhZ2VFdmVudC5sYXN0UGFnZSA9IHJlc3VsdC5sYXN0X3BhZ2U7XG4gICAgICAgIHRoaXMubW9kZWxzLmZvckVhY2goKHVzZXJEYXRhOiBhbnkpID0+IHtcbiAgICAgICAgICBjb25zdCBjbGllbnQ6IGFueSA9ICh1c2VyRGF0YT8udXNlcl9jbGllbnRzIGFzIGFueVtdIHx8IFtdKVxuICAgICAgICAgICAgLmZpbmQoKHVzZXJDbGllbnQ6IGFueSkgPT4gdXNlckNsaWVudC5jbGllbnRfaWQgPT09IGNsaWVudElkICYmIHVzZXJDbGllbnQudXNlcl9pZCA9PT0gdXNlckRhdGEuaWQpO1xuICAgICAgICAgIGlmIChjbGllbnQpIHtcbiAgICAgICAgICAgIHVzZXJEYXRhLnVzZXJfdHlwZV9pZCA9IGNsaWVudC51c2VyX3R5cGVfaWQ7XG4gICAgICAgICAgICB1c2VyRGF0YS5jbGllbnRfaWQgPSBjbGllbnQuY2xpZW50X2lkO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9LFxuICAgICAgZXJyb3I6ICgpID0+IHRoaXMuaXNXb3JraW5nID0gZmFsc2VcbiAgICB9KTtcbiAgfVxuXG4gIGNyZWF0ZU9yRWRpdFVzZXIodXNlcj86IGFueSk6IHZvaWQge1xuICAgIHVzZXIgPSB1c2VyID8gdXNlciA6IHt9O1xuICAgIHVzZXIuY2xpZW50X2lkID0gdGhpcy5jbGllbnRJZCA/PyB0aGlzLmN1cnJlbnRVc2VyPy5jbGllbnRfaWQ7XG4gICAgY29uc3QgZGlhbG9nUmVmID0gdGhpcy5kaWFsb2cub3BlbihVc2VyRm9ybUNvbXBvbmVudCwge1xuICAgICAgd2lkdGg6ICc3MDBweCcsXG4gICAgICBkYXRhOiB1c2VyLFxuICAgICAgYXV0b0ZvY3VzOiBmYWxzZSxcbiAgICAgIHJlc3RvcmVGb2N1czogZmFsc2VcbiAgICB9KTtcblxuICAgIGRpYWxvZ1JlZi5hZnRlckNsb3NlZCgpLnN1YnNjcmliZShhc3luYyByZXN1bHQgPT4ge1xuICAgICAgaWYgKHJlc3VsdCkge1xuICAgICAgICB0aGlzLnJlbG9hZCgpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgZGVsZXRlVXNlcih1c2VyOiBhbnkpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5jdXJyZW50VXNlci5pZCAhPT0gdXNlcj8uaWQpIHtcbiAgICAgIGNvbnN0IGRpYWxvZ1JlZiA9IHRoaXMuZGlhbG9nLm9wZW4oQWN0aW9uUG9wdXBDb21wb25lbnQsIHtcbiAgICAgICAgd2lkdGg6ICc0MDBweCcsXG4gICAgICAgIGRhdGE6IHtcbiAgICAgICAgICB0aXRsZTogJ0RlbGV0aW5nIFVzZXInLFxuICAgICAgICAgIG1lc3NhZ2U6IGBBcmUgeW91IHN1cmUgdG8gcHJvY2VlZCBkZWxldGluZyB0aGUgdXNlciAke3VzZXIubmFtZX0/YFxuICAgICAgICB9IGFzIEFjdGlvblBvcHVwLFxuICAgICAgICBhdXRvRm9jdXM6IGZhbHNlXG4gICAgICB9KTtcblxuICAgICAgZGlhbG9nUmVmLmFmdGVyQ2xvc2VkKCkuc3Vic2NyaWJlKGFzeW5jIHJlc3VsdCA9PiB7XG4gICAgICAgIGlmIChyZXN1bHQpIHtcbiAgICAgICAgICAvLyBBY3Rpb24gY29uZmlybWVkXG4gICAgICAgICAgYXdhaXQgdGhpcy51c2VyU2VydmljZS5kZWxldGVVc2VyKFxuICAgICAgICAgICAgdXNlci5pZCxcbiAgICAgICAgICAgIHsgY2xpZW50X2lkOiB1c2VyLmNsaWVudF9pZCB9XG4gICAgICAgICAgKTtcbiAgICAgICAgICB0aGlzLnJlbG9hZCgpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICB0aGlzLmFsZXJ0U2VydmljZS5hZGRBbGVydCgnQ3VycmVudCB1c2VyIGNhbm5vdCBiZSBkZWxldGVkJywgJ3dhcm4nKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogSGFuZGxlIHRoZSBzb3J0IGNoYW5nZSBldmVudC5cbiAgICogQHBhcmFtIHNvcnQgU29ydFxuICAgKi9cbiAgb25Tb3J0Q2hhbmdlKHNvcnQ6IFNvcnQpOiB2b2lkIHtcbiAgICBjb25zdCBkaXJlY3Rpb246IHN0cmluZyA9IHNvcnQuZGlyZWN0aW9uID8gc29ydC5kaXJlY3Rpb24gOiAnYXNjJztcbiAgICBjb25zdCBjb2x1bW46IHN0cmluZyA9IHNvcnQuYWN0aXZlID8gc29ydC5hY3RpdmUgOiAnaWQnO1xuICAgIHRoaXMuZmlsdGVyRm9ybS5nZXQoJ3NvcnRfYnknKS5zZXRWYWx1ZShjb2x1bW4gKyAnfCcgKyBkaXJlY3Rpb24pO1xuICB9XG5cbiAgcmVsb2FkKCk6IHZvaWQge1xuICAgIHRoaXMubW9kZWxzID0gW107XG4gICAgdGhpcy5wYWdlRXZlbnQgPSB7IHBhZ2U6IDEsIHBlclBhZ2U6IDI1LCBsYXN0UGFnZTogMSB9O1xuICAgIHRoaXMubG9hZERhdGEoKTtcbiAgfVxuXG4gIG9uU2Nyb2xsKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnBhZ2VFdmVudC5sYXN0UGFnZSA+IHRoaXMucGFnZUV2ZW50LnBhZ2UpIHtcbiAgICAgIHRoaXMucGFnZUV2ZW50LnBhZ2UgKz0gMTtcbiAgICAgIHRoaXMubG9hZERhdGEoKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSB1c2VyIHR5cGUgZm9yIHRoZSBjdXJyZW50IGNsaWVudC5cbiAgICpcbiAgICogQHBhcmFtIHVzZXIgVXNlclxuICAgKi9cbiAgZ2V0VXNlclR5cGUodXNlcjogYW55KTogc3RyaW5nIHtcbiAgICBsZXQgdXNlckNsaWVudDogYW55O1xuICAgIGlmICh0aGlzLmN1cnJlbnRVc2VyU2VydmljZS5nZXRVc2VyKCk/LnVzZXJfdHlwZV9pZCA9PT0gVXNlclR5cGVFbnVtLkFETUlOICYmICEhdGhpcy5jbGllbnRJZCkge1xuICAgICAgdXNlckNsaWVudCA9ICh1c2VyPy51c2VyX2NsaWVudHMgYXMgW10pLmZpbmQoKGl0ZW06IGFueSkgPT4gaXRlbT8uY2xpZW50X2lkID09PSB0aGlzLmNsaWVudElkKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdXNlckNsaWVudCA9ICh1c2VyPy51c2VyX2NsaWVudHMgYXMgW10pLmZpbmQoKGl0ZW06IGFueSkgPT4gaXRlbT8uY2xpZW50X2lkID09PSB0aGlzLmN1cnJlbnRVc2VyPy5jbGllbnRfaWQpO1xuICAgIH1cbiAgICByZXR1cm4gdXNlckNsaWVudD8udHlwZT8udGl0bGUgfHwgJyc7XG4gIH1cblxuICByZXNldFBhc3N3b3JkKHVzZXI6IGFueSkge1xuICAgIHRoaXMuaXNXb3JraW5nID0gdHJ1ZTtcbiAgICB0aGlzLnVzZXJTZXJ2aWNlLnJlc2V0UGFzc3dvcmQodXNlcilcbiAgICAgIC5waXBlKGZpbmFsaXplKCgpID0+IHRoaXMuaXNXb3JraW5nID0gZmFsc2UpKVxuICAgICAgLnN1YnNjcmliZShfID0+IHRoaXMuYWxlcnRTZXJ2aWNlLmFkZEFsZXJ0KCdQYXNzd29yZCByZXNldCBlbWFpbCBzZW50JywgJ3N1Y2Nlc3MnKSk7XG4gIH1cbn1cbiIsIjxkaXYgW25nQ2xhc3NdPVwieydtLTQnOmNvbmZpZz8udXNlckNvbmZpZz8uc2hvd0RlZmF1bHRNYXJnaW59XCI+XG4gIDxtYXQtY2FyZCBjbGFzcz1cIm1iLTJcIj5cbiAgICA8bWF0LWNhcmQtY29udGVudCBjbGFzcz1cImQtZmxleCBqdXN0aWZ5LWNvbnRlbnQtYmV0d2VlbiBhbGlnbi1pdGVtcyBjZW50ZXIgZ2FwLTJcIj5cbiAgICAgIDxzZWN0aW9uIGNsYXNzPVwiZC1mbGV4IGp1c3RpZnktY29udGVudC1zdGFydCBhbGlnbi1pdGVtcy1jZW50ZXIgZ2FwLTJcIj5cbiAgICAgICAgPGgzIGNsYXNzPVwibWItMFwiPlxuICAgICAgICAgIHt7IHRpdGxlIH19XG4gICAgICAgIDwvaDM+XG4gICAgICAgIDxtYXQtaWNvbiBjbGFzcz1cImN1cnNvci1wb2ludGVyXCIgbWF0VG9vbHRpcD1cIk5ldyBVc2VyXCJcbiAgICAgICAgICAqbmdJZj1cImNvbmZpZz8udXNlckNvbmZpZz8uc2hvd0FkZFVzZXIgJiYgY3VycmVudFVzZXJTZXJ2aWNlPy5oYXNQZXJtaXNzaW9uKCd1c2VyX2NyZWF0ZScpXCJcbiAgICAgICAgICAoY2xpY2spPVwiY3JlYXRlT3JFZGl0VXNlcigpXCI+YWRkPC9tYXQtaWNvbj5cbiAgICAgICAgPGJ1dHRvbiBtYXQtcmFpc2VkLWJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgW3JvdXRlckxpbmtdPVwiWycuLi9pbXBvcnQnXVwiXG4gICAgICAgICAgKm5nSWY9XCJjb25maWc/LnVzZXJDb25maWc/LnNob3dJbXBvcnRCdXR0b24gJiYgY3VycmVudFVzZXJTZXJ2aWNlPy5oYXNQZXJtaXNzaW9uKCd1c2VyX2NyZWF0ZScpXCI+XG4gICAgICAgICAgSW1wb3J0IFVzZXJcbiAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDxidXR0b24gbWF0LXJhaXNlZC1idXR0b24gdHlwZT1cImJ1dHRvblwiIFtyb3V0ZXJMaW5rXT1cIlsnLi4vcm9sZXMnXVwiICpuZ0lmPVwiY29uZmlnPy51c2VyQ29uZmlnPy5zaG93Um9sZXNcIj5cbiAgICAgICAgICA8bWF0LWljb24+cGVvcGxlPC9tYXQtaWNvbj5cbiAgICAgICAgICBSb2xlc1xuICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgPGJ1dHRvbiBtYXQtcmFpc2VkLWJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgW3JvdXRlckxpbmtdPVwiWycuLi9yb2xlLXBlcm1pc3Npb25zJ11cIlxuICAgICAgICAgICpuZ0lmPVwiY29uZmlnPy51c2VyQ29uZmlnPy5zaG93UGVybWlzc2lvbnNcIj5cbiAgICAgICAgICA8bWF0LWljb24+bG9jazwvbWF0LWljb24+XG4gICAgICAgICAgUm9sZSBQZXJtaXNzaW9uc1xuICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgPGJ1dHRvbiBtYXQtcmFpc2VkLWJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgW3JvdXRlckxpbmtdPVwiWycuLi9jb25maWd1cmF0aW9ucyddXCJcbiAgICAgICAgICAqbmdJZj1cImNvbmZpZz8udXNlckNvbmZpZz8uc2hvd0NvbmZpZ3VyYXRpb25zICYmIGN1cnJlbnRVc2VyPy51c2VyX3R5cGVfaWQgPT09IDJcIj5cbiAgICAgICAgICA8bWF0LWljb24+XG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cIm1hdGVyaWFsLWljb25zLW91dGxpbmVkXCI+XG4gICAgICAgICAgICAgIHRvZ2dsZV9vblxuICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgIDwvbWF0LWljb24+XG4gICAgICAgICAgQ29uZmlndXJhdGlvbnNcbiAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDxidXR0b24gbWF0LXJhaXNlZC1idXR0b24gdHlwZT1cImJ1dHRvblwiIFtyb3V0ZXJMaW5rXT1cIlsnLi4vcmVzdHJpY3RvcnMnXVwiXG4gICAgICAgICAgKm5nSWY9XCJjb25maWc/LnVzZXJDb25maWc/LnNob3dSZXN0cmljdG9ycyAmJiBjdXJyZW50VXNlcj8udXNlcl90eXBlX2lkID09PSAyXCI+XG4gICAgICAgICAgPG1hdC1pY29uPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJtYXRlcmlhbC1pY29ucy1vdXRsaW5lZFwiPlxuICAgICAgICAgICAgICB2cG5fbG9ja1xuICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgIDwvbWF0LWljb24+XG4gICAgICAgICAgUmVzdHJpY3RvcnNcbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L3NlY3Rpb24+XG4gICAgICA8Zm9ybSBbZm9ybUdyb3VwXT1cImZpbHRlckZvcm1cIiBmeExheW91dCBmeExheW91dEFsaWduPVwiZW5kIHN0YXJ0XCIgZnhMYXlvdXRHYXA9XCIwLjNyZW1cIj5cbiAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCIgc3R5bGU9XCJtYXgtd2lkdGg6IDE1MHB4O1wiPlxuICAgICAgICAgIDxtYXQtbGFiZWw+U2VhcmNoPC9tYXQtbGFiZWw+XG4gICAgICAgICAgPGlucHV0IGF1dG9jb21wbGV0ZT1cIm9mZlwiIG1hdElucHV0IHR5cGU9XCJ0ZXh0XCIgbmFtZT1cInNlYXJjaFwiIHBsYWNlaG9sZGVyPVwiU2VhcmNoIGJ5IG5hbWUsIGVtYWlsXCJcbiAgICAgICAgICAgIGZvcm1Db250cm9sTmFtZT1cInNlYXJjaFwiPlxuICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgICAgICA8bWF0LWZvcm0tZmllbGQgYXBwZWFyYW5jZT1cIm91dGxpbmVcIiBzdHlsZT1cIm1heC13aWR0aDogMTUwcHg7XCI+XG4gICAgICAgICAgPG1hdC1sYWJlbD5Sb2xlPC9tYXQtbGFiZWw+XG4gICAgICAgICAgPGFwcC1zZWFyY2hhYmxlLXNlbGVjdG9yIGFwaVVybD1cImFwaS9yb2xlc1wiIFttdWx0aXBsZV09XCJ0cnVlXCIgZm9ybUNvbnRyb2xOYW1lPVwicm9sZV9pZHNcIlxuICAgICAgICAgICAgdGl0bGVGaWVsZD1cImxhYmVsXCI+PC9hcHAtc2VhcmNoYWJsZS1zZWxlY3Rvcj5cbiAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgICAgPG1hdC1idXR0b24tdG9nZ2xlLWdyb3VwIFtoaWRlU2luZ2xlU2VsZWN0aW9uSW5kaWNhdG9yXT1cInRydWVcIiBbaGlkZU11bHRpcGxlU2VsZWN0aW9uSW5kaWNhdG9yXT1cInRydWVcIlxuICAgICAgICAgIGZvcm1Db250cm9sTmFtZT1cInN0YXR1c1wiIG11bHRpcGxlPlxuICAgICAgICAgIDxtYXQtYnV0dG9uLXRvZ2dsZSB2YWx1ZT1cImVuYWJsZWRcIj5FbmFibGVkPC9tYXQtYnV0dG9uLXRvZ2dsZT5cbiAgICAgICAgICA8bWF0LWJ1dHRvbi10b2dnbGUgdmFsdWU9XCJkaXNhYmxlZFwiPkRpc2FibGVkPC9tYXQtYnV0dG9uLXRvZ2dsZT5cbiAgICAgICAgPC9tYXQtYnV0dG9uLXRvZ2dsZS1ncm91cD5cbiAgICAgIDwvZm9ybT5cbiAgICA8L21hdC1jYXJkLWNvbnRlbnQ+XG4gIDwvbWF0LWNhcmQ+XG4gIDxtYXQtY2FyZCBjbGFzcz1cIm10LTIgcC0wXCI+XG4gICAgPG1hdC1jYXJkLWNvbnRlbnQ+XG4gICAgICA8dGFibGUgbWF0LXRhYmxlIFtkYXRhU291cmNlXT1cIm1vZGVsc1wiIGNsYXNzPVwidy0xMDBcIiBhcmlhLWRlc2NyaWJlZGJ5PVwiVXNlcnNcIiBpbmZpbml0ZVNjcm9sbFxuICAgICAgICBbaW5maW5pdGVTY3JvbGxEaXN0YW5jZV09XCIyXCIgW2luZmluaXRlU2Nyb2xsVGhyb3R0bGVdPVwiNTBcIiBbaW5maW5pdGVTY3JvbGxDb250YWluZXJdPVwic2Nyb2xsQ29udGFpbmVyXCJcbiAgICAgICAgW2Zyb21Sb290XT1cInRydWVcIiAoc2Nyb2xsZWQpPVwib25TY3JvbGwoKVwiIG1hdFNvcnQgKG1hdFNvcnRDaGFuZ2UpPVwib25Tb3J0Q2hhbmdlKCRldmVudClcIj5cbiAgICAgICAgPCEtLSBJbmRleCBDb2x1bW4gLS0+XG4gICAgICAgIDxuZy1jb250YWluZXIgbWF0Q29sdW1uRGVmPVwiaW5kZXhcIj5cbiAgICAgICAgICA8dGggbWF0LWhlYWRlci1jZWxsICptYXRIZWFkZXJDZWxsRGVmPiAjIDwvdGg+XG4gICAgICAgICAgPHRkIG1hdC1jZWxsICptYXRDZWxsRGVmPVwibGV0IGVsZW1lbnQ7IGxldCBpID0gaW5kZXg7XCI+IHt7IGkgKyAxIH19IDwvdGQ+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICAgIDwhLS0gTmFtZSBDb2x1bW4gLS0+XG4gICAgICAgIDxuZy1jb250YWluZXIgbWF0Q29sdW1uRGVmPVwibmFtZVwiPlxuICAgICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgbWF0LXNvcnQtaGVhZGVyPVwibmFtZVwiICptYXRIZWFkZXJDZWxsRGVmPiBOYW1lIDwvdGg+XG4gICAgICAgICAgPHRkIG1hdC1jZWxsICptYXRDZWxsRGVmPVwibGV0IGVsZW1lbnRcIj5cbiAgICAgICAgICAgIDxhIFtyb3V0ZXJMaW5rXT1cIltlbGVtZW50Py5pZF1cIiBjbGFzcz1cInRleHQtZGVjb3JhdGlvbi1ub25lXCI+XG4gICAgICAgICAgICAgIHt7IGVsZW1lbnQubmFtZSB9fVxuICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgPHAgY2xhc3M9XCJtYi0wIHRleHQtc2Vjb25kYXJ5XCI+XG4gICAgICAgICAgICAgIDwhLS0gIWVsZW1lbnQ/LnVzZXJfY2xpZW50IGNvbmRpdGlvbiBhZGRlZCB0byBjaGVjayBpZiB1c2VyIGhhcyB1c2VyX2NsaWVudCByZWNvcmQgLS0+XG4gICAgICAgICAgICAgIHt7ICFlbGVtZW50Py51c2VyX2NsaWVudCA/ICcnIDogZWxlbWVudD8udXNlcl9jbGllbnQ/LmlzX2VuYWJsZWQgPyAnRW5hYmxlZCcgOiAnRGlzYWJsZWQnIH19XG4gICAgICAgICAgICA8L3A+XG4gICAgICAgICAgPC90ZD5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgICAgPCEtLSBFbWFpbCBDb2x1bW4gLS0+XG4gICAgICAgIDxuZy1jb250YWluZXIgbWF0Q29sdW1uRGVmPVwiZW1haWxcIj5cbiAgICAgICAgICA8dGggbWF0LWhlYWRlci1jZWxsIG1hdC1zb3J0LWhlYWRlcj1cImVtYWlsXCIgKm1hdEhlYWRlckNlbGxEZWY+IEVtYWlsIDwvdGg+XG4gICAgICAgICAgPHRkIG1hdC1jZWxsICptYXRDZWxsRGVmPVwibGV0IGVsZW1lbnRcIj4ge3tlbGVtZW50LmVtYWlsfX0gPC90ZD5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgICAgPCEtLSBUeXBlIENvbHVtbiAtLT5cbiAgICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJ0eXBlXCI+XG4gICAgICAgICAgPHRoIG1hdC1oZWFkZXItY2VsbCBtYXQtc29ydC1oZWFkZXI9XCJ1c2VyX3R5cGVfaWRcIiAqbWF0SGVhZGVyQ2VsbERlZj4gVXNlciBUeXBlIDwvdGg+XG4gICAgICAgICAgPHRkIG1hdC1jZWxsICptYXRDZWxsRGVmPVwibGV0IGVsZW1lbnRcIj4ge3sgZ2V0VXNlclR5cGUoZWxlbWVudCkgfX0gPC90ZD5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgICAgPCEtLSBSb2xlcyBDb2x1bW4gLS0+XG4gICAgICAgIDxuZy1jb250YWluZXIgbWF0Q29sdW1uRGVmPVwicm9sZXNcIj5cbiAgICAgICAgICA8dGggbWF0LWhlYWRlci1jZWxsICptYXRIZWFkZXJDZWxsRGVmPiBSb2xlIDwvdGg+XG4gICAgICAgICAgPHRkIG1hdC1jZWxsICptYXRDZWxsRGVmPVwibGV0IGVsZW1lbnRcIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJkLWZsZXgganVzdGlmeS1jb250ZW50LXN0YXJ0IGFsaWduLWl0ZW1zLWNlbnRlciBnYXAtMSBmbGV4LXdyYXAgdGV4dC1saWdodFwiPlxuICAgICAgICAgICAgICA8c3BhbiAqbmdGb3I9XCJsZXQgcm9sZSBvZiBlbGVtZW50Py5yb2xlc1wiIGNsYXNzPVwiYmFkZ2UgYmctc2Vjb25kYXJ5XCI+XG4gICAgICAgICAgICAgICAge3sgcm9sZT8ubGFiZWwgfX1cbiAgICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC90ZD5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgICAgPCEtLSBMYXN0IExvZ2luIENvbHVtbiAtLT5cbiAgICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJsYXN0X2xvZ2luXCI+XG4gICAgICAgICAgPHRoIG1hdC1oZWFkZXItY2VsbCAqbWF0SGVhZGVyQ2VsbERlZj4gTGFzdCBMb2dpbiA8L3RoPlxuICAgICAgICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCBlbGVtZW50XCI+e3sgZWxlbWVudD8ubGFzdF9sb2dpbiB8IGRhdGU6J21lZGl1bScgfX08L3RkPlxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgICA8IS0tIEFkZGVkIEJ5IENvbHVtbiAtLT5cbiAgICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJhZGRlZF9ieVwiPlxuICAgICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgKm1hdEhlYWRlckNlbGxEZWY+IEFkZGVkIEJ5IDwvdGg+XG4gICAgICAgICAgPHRkIG1hdC1jZWxsICptYXRDZWxsRGVmPVwibGV0IGVsZW1lbnRcIj5cbiAgICAgICAgICAgIDxwIGNsYXNzPVwibWItMFwiPnt7IGVsZW1lbnQ/LmNyZWF0b3I/Lm5hbWUgfX08L3A+XG4gICAgICAgICAgICA8cCBjbGFzcz1cInRleHQtc2Vjb25kYXJ5XCI+e3sgZWxlbWVudD8uY3JlYXRlZF9hdCB8IGRhdGUgfX08L3A+XG4gICAgICAgICAgPC90ZD5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgICAgPCEtLSBBY3Rpb25zIENvbHVtbiAtLT5cbiAgICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJhY3Rpb25zXCI+XG4gICAgICAgICAgPHRoIG1hdC1oZWFkZXItY2VsbCAqbWF0SGVhZGVyQ2VsbERlZj4gQWN0aW9uIDwvdGg+XG4gICAgICAgICAgPHRkIG1hdC1jZWxsICptYXRDZWxsRGVmPVwibGV0IGVsZW1lbnRcIj5cbiAgICAgICAgICAgIDxkaXYgZnhMYXlvdXQgZnhMYXlvdXRBbGlnbj1cInN0YXJ0IGNlbnRlclwiIGZ4TGF5b3V0R2FwPVwiNXB4XCI+XG4gICAgICAgICAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIG1hdC1pY29uLWJ1dHRvbiBbcm91dGVyTGlua109XCJbZ2V0VXNlclZpZXdSb3V0ZShlbGVtZW50KV1cIj5cbiAgICAgICAgICAgICAgICA8bWF0LWljb24+dmlzaWJpbGl0eTwvbWF0LWljb24+XG4gICAgICAgICAgICAgIDwvYnV0dG9uPlxuXG4gICAgICAgICAgICAgIDxidXR0b24gKm5nSWY9XCJjdXJyZW50VXNlclNlcnZpY2UuaGFzUGVybWlzc2lvbigndXNlcl91cGRhdGUnKVwiIHR5cGU9XCJidXR0b25cIiBtYXQtaWNvbi1idXR0b25cbiAgICAgICAgICAgICAgICAoY2xpY2spPVwiY3JlYXRlT3JFZGl0VXNlcihlbGVtZW50KVwiPlxuICAgICAgICAgICAgICAgIDxtYXQtaWNvbj5lZGl0PC9tYXQtaWNvbj5cbiAgICAgICAgICAgICAgPC9idXR0b24+XG5cbiAgICAgICAgICAgICAgPGJ1dHRvbiAqbmdJZj1cImN1cnJlbnRVc2VyU2VydmljZS5oYXNQZXJtaXNzaW9uKCd1c2VyX2RlbGV0ZScpXCIgdHlwZT1cImJ1dHRvblwiIG1hdC1pY29uLWJ1dHRvblxuICAgICAgICAgICAgICAgIChjbGljayk9XCJkZWxldGVVc2VyKGVsZW1lbnQpXCI+XG4gICAgICAgICAgICAgICAgPG1hdC1pY29uPmRlbGV0ZTwvbWF0LWljb24+XG4gICAgICAgICAgICAgIDwvYnV0dG9uPlxuXG4gICAgICAgICAgICAgIDxidXR0b24gKm5nSWY9XCJjdXJyZW50VXNlclNlcnZpY2UuaGFzUGVybWlzc2lvbigndGVjaGxpZnlfcmJhYy51c2VyLnJlc2V0X3Bhc3N3b3JkJylcIiB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgICBtYXQtaWNvbi1idXR0b24gKGNsaWNrKT1cInJlc2V0UGFzc3dvcmQoZWxlbWVudClcIiBtYXRUb29sdGlwPVwiUmVzZXQgVXNlciBQYXNzd29yZFwiPlxuICAgICAgICAgICAgICAgIDxtYXQtaWNvbj5yZWZyZXNoPC9tYXQtaWNvbj5cbiAgICAgICAgICAgICAgPC9idXR0b24+XG5cbiAgICAgICAgICAgICAgPGFwcC11c2VyLWVuYWJsZS1idXR0b24gW3VzZXJdPVwiZWxlbWVudFwiIChvblNhdmUpPVwicmVsb2FkKClcIj48L2FwcC11c2VyLWVuYWJsZS1idXR0b24+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L3RkPlxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgICA8dHIgbWF0LWhlYWRlci1yb3cgKm1hdEhlYWRlclJvd0RlZj1cImRpc3BsYXllZENvbHVtbnNcIj48L3RyPlxuICAgICAgICA8dHIgbWF0LXJvdyAqbWF0Um93RGVmPVwibGV0IHJvdzsgY29sdW1uczogZGlzcGxheWVkQ29sdW1ucztcIj48L3RyPlxuICAgICAgPC90YWJsZT5cbiAgICAgIDxtYXQtcHJvZ3Jlc3MtYmFyICpuZ0lmPVwiaXNXb3JraW5nXCIgbW9kZT1cImluZGV0ZXJtaW5hdGVcIj48L21hdC1wcm9ncmVzcy1iYXI+XG4gICAgPC9tYXQtY2FyZC1jb250ZW50PlxuICA8L21hdC1jYXJkPlxuPC9kaXY+Il19
168
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNlcnMtdmlldy1hbGwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LXRlY2hsaWZ5LWNvcmUvc3JjL2xpYi91c2VyL3VzZXJzLXZpZXctYWxsLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC10ZWNobGlmeS1jb3JlL3NyYy9saWIvdXNlci91c2Vycy12aWV3LWFsbC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFVLEtBQUssRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUt6RCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUcxRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDMUMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBRXJELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNoRCxPQUFPLEVBQUUsa0NBQWtDLEVBQUUsTUFBTSxlQUFlLENBQUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBUTVELElBQU0scUJBQXFCLEdBQTNCLE1BQU0scUJBQXNCLFNBQVEsa0NBQWtDO0lBeUIzRSxZQUNVLFlBQTBCLEVBQzNCLGtCQUFzQyxFQUN0QyxpQkFBb0MsRUFDbkMsTUFBaUIsRUFDTixPQUFvQixFQUMvQixFQUFzQjtRQUU5QixLQUFLLEVBQUUsQ0FBQztRQVBBLGlCQUFZLEdBQVosWUFBWSxDQUFjO1FBQzNCLHVCQUFrQixHQUFsQixrQkFBa0IsQ0FBb0I7UUFDdEMsc0JBQWlCLEdBQWpCLGlCQUFpQixDQUFtQjtRQUNuQyxXQUFNLEdBQU4sTUFBTSxDQUFXO1FBQ04sWUFBTyxHQUFQLE9BQU8sQ0FBYTtRQUMvQixPQUFFLEdBQUYsRUFBRSxDQUFvQjtRQTNCdkIsZ0JBQVcsR0FBYSxFQUFFLENBQUM7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QUFLLENBQUMsQ0FBQzthQUM1QyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsQ0FBQywyQkFBMkIsRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDO0lBQ3hGLENBQUM7K0dBeklVLHFCQUFxQjttR0FBckIscUJBQXFCLGlNQ3BCbEMsNHdQQTBKTTs7QUR0SU8scUJBQXFCO0lBTGpDLFlBQVksRUFBRTtHQUtGLHFCQUFxQixDQTBJakM7OzRGQTFJWSxxQkFBcUI7a0JBSmpDLFNBQVM7K0JBQ0Usb0JBQW9CO3FPQU1yQixRQUFRO3NCQUFoQixLQUFLO2dCQUNHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBS0csS0FBSztzQkFBYixLQUFLO2dCQWNHLGNBQWM7c0JBQXRCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIE9uSW5pdCwgSW5wdXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFVzZXIgfSBmcm9tICcuL3VzZXIubW9kZWwnO1xuaW1wb3J0IHsgQ3VycmVudFVzZXJTZXJ2aWNlIH0gZnJvbSAnLi9jdXJyZW50LXVzZXIuc2VydmljZSc7XG5pbXBvcnQgeyBNYXREaWFsb2cgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9kaWFsb2cnO1xuaW1wb3J0IHsgVXNlclNlcnZpY2UgfSBmcm9tICcuL3VzZXIuc2VydmljZSc7XG5pbXBvcnQgeyBVc2VyRm9ybUNvbXBvbmVudCB9IGZyb20gJy4vdXNlci1mb3JtLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBNdWx0aVVzZXJDb25maWcsIFVzZXJDb25maWdTZXJ2aWNlIH0gZnJvbSAnLi4vdXNlci1jb25maWcnO1xuaW1wb3J0IHsgVW50eXBlZEZvcm1CdWlsZGVyIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgZmluYWxpemUgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBVbnRpbERlc3Ryb3kgfSBmcm9tICdAbmduZWF0L3VudGlsLWRlc3Ryb3knO1xuaW1wb3J0IHsgQWxlcnRTZXJ2aWNlLCBIdHRwU2VydmljZSB9IGZyb20gJy4uL2NvcmUnO1xuaW1wb3J0IHsgVXNlclR5cGVFbnVtIH0gZnJvbSAnLi91c2VyLXR5cGUuZW51bSc7XG5pbXBvcnQgeyBUZWNobGlmeUxpc3RpbmdDb250cm9sbGVySW50ZXJmYWNlIH0gZnJvbSAnLi4vYmFzZS1tb2RlbCc7XG5pbXBvcnQgeyBBY3RpdmF0ZWRSb3V0ZSB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5cbkBVbnRpbERlc3Ryb3koKVxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYXBwLXVzZXJzLXZpZXctYWxsJyxcbiAgdGVtcGxhdGVVcmw6ICcuL3VzZXJzLXZpZXctYWxsLmh0bWwnXG59KVxuZXhwb3J0IGNsYXNzIFVzZXJzVmlld0FsbENvbXBvbmVudCBleHRlbmRzIFRlY2hsaWZ5TGlzdGluZ0NvbnRyb2xsZXJJbnRlcmZhY2UgaW1wbGVtZW50cyBPbkluaXQge1xuXG4gIC8vIEZvciBhZG1pbiBwYWdlIHdlIG5lZWQgdG8gcGFzcyB0aGUgY2xpZW50IElkXG4gIEBJbnB1dCgpIGNsaWVudElkOiBudW1iZXI7XG4gIEBJbnB1dCgpIHVzZXJUeXBlSWRzOiBudW1iZXJbXSA9IFtdO1xuXG4gIGN1cnJlbnRVc2VyOiBVc2VyO1xuICBjb25maWc6IE11bHRpVXNlckNvbmZpZztcbiAgdXNlcjogVXNlcjtcbiAgQElucHV0KCkgdGl0bGUgPSAnVXNlciBNYW5hZ2VtZW50JztcbiAgZGlzcGxheWVkQ29sdW1uczogc3RyaW5nW10gPSBbXG4gICAgJ2luZGV4JyxcbiAgICAnbmFtZScsXG4gICAgJ2VtYWlsJyxcbiAgICAndHlwZScsXG4gICAgJ3JvbGVzJyxcbiAgICAnbGFzdF9sb2dpbicsXG4gICAgJ2FkZGVkX2J5JyxcbiAgICAnYWN0aW9ucydcbiAgXTtcblxuICBzY3JvbGxDb250YWluZXIgPSAnLm1hdC1zaWRlbmF2LWNvbnRlbnQnO1xuICBtb2RlbHM6IGFueVtdID0gW107XG4gIEBJbnB1dCgpIGlzQXBwQWRtaW5Vc2VyOiBib29sZWFuID0gZmFsc2U7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBhbGVydFNlcnZpY2U6IEFsZXJ0U2VydmljZSxcbiAgICBwdWJsaWMgY3VycmVudFVzZXJTZXJ2aWNlOiBDdXJyZW50VXNlclNlcnZpY2UsXG4gICAgcHVibGljIHVzZXJDb25maWdTZXJ2aWNlOiBVc2VyQ29uZmlnU2VydmljZSxcbiAgICBwcml2YXRlIGRpYWxvZzogTWF0RGlhbG9nLFxuICAgIHByb3RlY3RlZCBvdmVycmlkZSBzZXJ2aWNlOiBVc2VyU2VydmljZSxcbiAgICBwcml2YXRlIGZiOiBVbnR5cGVkRm9ybUJ1aWxkZXIsXG4gICkge1xuICAgIHN1cGVyKCk7XG4gICAgdGhpcy5jb25maWcgPSB0aGlzLnVzZXJDb25maWdTZXJ2aWNlLmdldENvbmZpZygpO1xuXG4gICAgdGhpcy5maWx0ZXJGb3JtQ29uZmlndXJhdGlvbiA9IHtcbiAgICAgIHJvbGVfaWRzOiB7IG11bHRpcGxlOiB0cnVlIH0sXG4gICAgICBzdGF0dXM6IHsgbXVsdGlwbGU6IHRydWUgfSxcbiAgICAgIHVzZXJfdHlwZV9pZHM6IHsgbXVsdGlwbGU6IHRydWUgfVxuICAgIH07XG5cbiAgICB0aGlzLmZpbHRlckZvcm0gPSB0aGlzLmZiLmdyb3VwKHtcbiAgICAgIHNlYXJjaDogWycnXSxcbiAgICAgIHJvbGVfaWRzOiBbJyddLFxuICAgICAgc3RhdHVzOiBbJ2VuYWJsZWQnXSxcbiAgICAgIHNvcnRfYnk6IFsnaWR8QVNDJ10sXG4gICAgICByZWxhdGlvbnM6IFsncm9sZXMsdHlwZSx1c2VyQ2xpZW50cy50eXBlLGNyZWF0b3IsdXNlckNsaWVudCddLFxuICAgICAgYXBwZW5kczogWydsYXN0X2xvZ2luJ10sXG4gICAgICBjbGllbnRfaWQ6IFt0aGlzLmNsaWVudElkXSxcbiAgICAgIHVzZXJfdHlwZV9pZHM6IHRoaXMudXNlclR5cGVJZHMudG9TdHJpbmcoKVxuICAgIH0pO1xuXG4gICAgaWYgKHRoaXMuY29uZmlnPy5zY3JvbGxDb250YWluZXIpIHtcbiAgICAgIC8vIFNldCB0byBudWxsIGlmIHNjcm9sbCBoYXMgdG8gYmUgZG9uZSBmcm9tIHJvb3RcbiAgICAgIHRoaXMuc2Nyb2xsQ29udGFpbmVyID0gdGhpcy5jb25maWc/LnNjcm9sbENvbnRhaW5lciA9PT0gJ3Jvb3QnID8gbnVsbCA6IHRoaXMuY29uZmlnPy5zY3JvbGxDb250YWluZXI7XG4gICAgfVxuICB9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy5jdXJyZW50VXNlciA9IHRoaXMuY3VycmVudFVzZXJTZXJ2aWNlLmdldFVzZXIoKTtcblxuICAgIHRoaXMucGF0Y2hGaWx0ZXJzRnJvbVJvdXRlKCk7XG4gICAgdGhpcy5saXN0ZW5GaWx0ZXJDaGFuZ2VzKCk7XG4gICAgdGhpcy5sb2FkRGF0YSgpO1xuICB9XG5cbiAgZ2V0VXNlclZpZXdSb3V0ZSh1c2VyOiBhbnkpIHtcbiAgICByZXR1cm4gdGhpcy5pc0FwcEFkbWluVXNlciA/IGAke3VzZXIuaWR9L2FwcC1hZG1pbi12aWV3YCA6IHVzZXIuaWQ7XG4gIH1cblxuICBvdmVycmlkZSBsb2FkRGF0YSgpOiB2b2lkIHtcbiAgICB0aGlzLmlzV29ya2luZyA9IHRydWU7XG4gICAgY29uc3QgY2xpZW50SWQgPSB0aGlzLmNsaWVudElkID8/IHRoaXMuY3VycmVudFVzZXI/LmNsaWVudF9pZDtcbiAgICBjb25zdCBwYXJhbXMgPSB7XG4gICAgICAuLi50aGlzLmZpbHRlckZvcm0udmFsdWUsXG4gICAgICBzdGF0dXM6IHRoaXMuZmlsdGVyRm9ybS52YWx1ZS5zdGF0dXMgPyB0aGlzLmZpbHRlckZvcm0udmFsdWUuc3RhdHVzLnRvU3RyaW5nKCkgOiAnJyxcbiAgICAgIHBhZ2U6IHRoaXMucGFnZSxcbiAgICAgIHBlclBhZ2U6IHRoaXMucGVyUGFnZVxuICAgIH07XG5cbiAgICB0aGlzLnNlcnZpY2UuaW5kZXgocGFyYW1zKS5zdWJzY3JpYmUoe1xuICAgICAgbmV4dDogKHJlc3VsdDogYW55KSA9PiB7XG4gICAgICAgIHRoaXMuaXNXb3JraW5nID0gZmFsc2U7XG4gICAgICAgIHRoaXMubW9kZWxzID0gdGhpcy5tb2RlbHMuY29uY2F0KHJlc3VsdD8uZGF0YSk7XG4gICAgICAgIHRoaXMubGFzdFBhZ2UgPSByZXN1bHQ/Lmxhc3RfcGFnZTtcblxuICAgICAgICB0aGlzLm1vZGVscy5mb3JFYWNoKCh1c2VyRGF0YTogYW55KSA9PiB7XG4gICAgICAgICAgY29uc3QgY2xpZW50OiBhbnkgPSAodXNlckRhdGE/LnVzZXJfY2xpZW50cyBhcyBhbnlbXSB8fCBbXSlcbiAgICAgICAgICAgIC5maW5kKCh1c2VyQ2xpZW50OiBhbnkpID0+IHVzZXJDbGllbnQuY2xpZW50X2lkID09PSBjbGllbnRJZCAmJiB1c2VyQ2xpZW50LnVzZXJfaWQgPT09IHVzZXJEYXRhLmlkKTtcbiAgICAgICAgICBpZiAoY2xpZW50KSB7XG4gICAgICAgICAgICB1c2VyRGF0YS51c2VyX3R5cGVfaWQgPSBjbGllbnQudXNlcl90eXBlX2lkO1xuICAgICAgICAgICAgdXNlckRhdGEuY2xpZW50X2lkID0gY2xpZW50LmNsaWVudF9pZDtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSxcbiAgICAgIGVycm9yOiAoKSA9PiB0aGlzLmlzV29ya2luZyA9IGZhbHNlXG4gICAgfSlcbiAgfVxuXG4gIGNyZWF0ZU9yRWRpdFVzZXIodXNlcj86IGFueSk6IHZvaWQge1xuICAgIHVzZXIgPSB1c2VyID8gdXNlciA6IHt9O1xuICAgIHVzZXIuY2xpZW50X2lkID0gdGhpcy5jbGllbnRJZCA/PyB0aGlzLmN1cnJlbnRVc2VyPy5jbGllbnRfaWQ7XG4gICAgY29uc3QgZGlhbG9nUmVmID0gdGhpcy5kaWFsb2cub3BlbihVc2VyRm9ybUNvbXBvbmVudCwge1xuICAgICAgd2lkdGg6ICc3MDBweCcsXG4gICAgICBkYXRhOiB1c2VyLFxuICAgICAgYXV0b0ZvY3VzOiBmYWxzZSxcbiAgICAgIHJlc3RvcmVGb2N1czogZmFsc2VcbiAgICB9KTtcblxuICAgIGRpYWxvZ1JlZi5hZnRlckNsb3NlZCgpLnN1YnNjcmliZShhc3luYyByZXN1bHQgPT4ge1xuICAgICAgaWYgKHJlc3VsdCkge1xuICAgICAgICB0aGlzLnJlbG9hZCgpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgdXNlciB0eXBlIGZvciB0aGUgY3VycmVudCBjbGllbnQuXG4gICAqXG4gICAqIEBwYXJhbSB1c2VyIFVzZXJcbiAgICovXG4gIGdldFVzZXJUeXBlKHVzZXI6IGFueSk6IHN0cmluZyB7XG4gICAgbGV0IHVzZXJDbGllbnQ6IGFueTtcbiAgICBpZiAodGhpcy5jdXJyZW50VXNlclNlcnZpY2UuZ2V0VXNlcigpPy51c2VyX3R5cGVfaWQgPT09IFVzZXJUeXBlRW51bS5BRE1JTiAmJiAhIXRoaXMuY2xpZW50SWQpIHtcbiAgICAgIHVzZXJDbGllbnQgPSAodXNlcj8udXNlcl9jbGllbnRzIGFzIFtdKS5maW5kKChpdGVtOiBhbnkpID0+IGl0ZW0/LmNsaWVudF9pZCA9PT0gdGhpcy5jbGllbnRJZCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHVzZXJDbGllbnQgPSAodXNlcj8udXNlcl9jbGllbnRzIGFzIFtdKS5maW5kKChpdGVtOiBhbnkpID0+IGl0ZW0/LmNsaWVudF9pZCA9PT0gdGhpcy5jdXJyZW50VXNlcj8uY2xpZW50X2lkKTtcbiAgICB9XG4gICAgcmV0dXJuIHVzZXJDbGllbnQ/LnR5cGU/LnRpdGxlIHx8ICcnO1xuICB9XG5cbiAgcmVzZXRQYXNzd29yZCh1c2VyOiBhbnkpIHtcbiAgICB0aGlzLmlzV29ya2luZyA9IHRydWU7XG4gICAgdGhpcy5zZXJ2aWNlLnJlc2V0UGFzc3dvcmQodXNlcilcbiAgICAgIC5waXBlKGZpbmFsaXplKCgpID0+IHRoaXMuaXNXb3JraW5nID0gZmFsc2UpKVxuICAgICAgLnN1YnNjcmliZShfID0+IHRoaXMuYWxlcnRTZXJ2aWNlLmFkZEFsZXJ0KCdQYXNzd29yZCByZXNldCBlbWFpbCBzZW50JywgJ3N1Y2Nlc3MnKSk7XG4gIH1cbn1cbiIsIjxkaXYgW25nQ2xhc3NdPVwieydtLTQnOmNvbmZpZz8udXNlckNvbmZpZz8uc2hvd0RlZmF1bHRNYXJnaW59XCI+XG4gIDxtYXQtY2FyZCBjbGFzcz1cIm1iLTJcIj5cbiAgICA8bWF0LWNhcmQtY29udGVudCBjbGFzcz1cImQtZmxleCBqdXN0aWZ5LWNvbnRlbnQtYmV0d2VlbiBhbGlnbi1pdGVtcy1jZW50ZXIgZ2FwLTJcIj5cbiAgICAgIDxzZWN0aW9uIGNsYXNzPVwiZC1mbGV4IGp1c3RpZnktY29udGVudC1zdGFydCBhbGlnbi1pdGVtcy1jZW50ZXIgZ2FwLTJcIj5cbiAgICAgICAgPGg1IGNsYXNzPVwibWItMFwiPiB7eyB0aXRsZSB9fSA8L2g1PlxuICAgICAgICA8bWF0LWljb24gY2xhc3M9XCJjdXJzb3ItcG9pbnRlclwiIG1hdFRvb2x0aXA9XCJOZXcgVXNlclwiXG4gICAgICAgICAgKm5nSWY9XCJjb25maWc/LnVzZXJDb25maWc/LnNob3dBZGRVc2VyICYmIGN1cnJlbnRVc2VyU2VydmljZT8uaGFzUGVybWlzc2lvbigndXNlcl9jcmVhdGUnKVwiXG4gICAgICAgICAgKGNsaWNrKT1cImNyZWF0ZU9yRWRpdFVzZXIoKVwiPmFkZDwvbWF0LWljb24+XG4gICAgICAgIDxidXR0b24gbWF0LXJhaXNlZC1idXR0b24gdHlwZT1cImJ1dHRvblwiIFtyb3V0ZXJMaW5rXT1cIlsnLi4vaW1wb3J0J11cIlxuICAgICAgICAgICpuZ0lmPVwiY29uZmlnPy51c2VyQ29uZmlnPy5zaG93SW1wb3J0QnV0dG9uICYmIGN1cnJlbnRVc2VyU2VydmljZT8uaGFzUGVybWlzc2lvbigndXNlcl9jcmVhdGUnKVwiPlxuICAgICAgICAgIEltcG9ydCBVc2VyXG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgICA8YnV0dG9uIG1hdC1yYWlzZWQtYnV0dG9uIHR5cGU9XCJidXR0b25cIiBbcm91dGVyTGlua109XCJbJy4uL3JvbGVzJ11cIiAqbmdJZj1cImNvbmZpZz8udXNlckNvbmZpZz8uc2hvd1JvbGVzXCI+XG4gICAgICAgICAgPG1hdC1pY29uPnBlb3BsZTwvbWF0LWljb24+XG4gICAgICAgICAgUm9sZXNcbiAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDxidXR0b24gbWF0LXJhaXNlZC1idXR0b24gdHlwZT1cImJ1dHRvblwiIFtyb3V0ZXJMaW5rXT1cIlsnLi4vcm9sZS1wZXJtaXNzaW9ucyddXCJcbiAgICAgICAgICAqbmdJZj1cImNvbmZpZz8udXNlckNvbmZpZz8uc2hvd1Blcm1pc3Npb25zXCI+XG4gICAgICAgICAgPG1hdC1pY29uPmxvY2s8L21hdC1pY29uPlxuICAgICAgICAgIFJvbGUgUGVybWlzc2lvbnNcbiAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDxidXR0b24gbWF0LXJhaXNlZC1idXR0b24gdHlwZT1cImJ1dHRvblwiIFtyb3V0ZXJMaW5rXT1cIlsnLi4vY29uZmlndXJhdGlvbnMnXVwiXG4gICAgICAgICAgKm5nSWY9XCJjb25maWc/LnVzZXJDb25maWc/LnNob3dDb25maWd1cmF0aW9ucyAmJiBjdXJyZW50VXNlcj8udXNlcl90eXBlX2lkID09PSAyXCI+XG4gICAgICAgICAgPG1hdC1pY29uPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJtYXRlcmlhbC1pY29ucy1vdXRsaW5lZFwiPlxuICAgICAgICAgICAgICB0b2dnbGVfb25cbiAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICA8L21hdC1pY29uPlxuICAgICAgICAgIENvbmZpZ3VyYXRpb25zXG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgICA8YnV0dG9uIG1hdC1yYWlzZWQtYnV0dG9uIHR5cGU9XCJidXR0b25cIiBbcm91dGVyTGlua109XCJbJy4uL3Jlc3RyaWN0b3JzJ11cIlxuICAgICAgICAgICpuZ0lmPVwiY29uZmlnPy51c2VyQ29uZmlnPy5zaG93UmVzdHJpY3RvcnMgJiYgY3VycmVudFVzZXI/LnVzZXJfdHlwZV9pZCA9PT0gMlwiPlxuICAgICAgICAgIDxtYXQtaWNvbj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibWF0ZXJpYWwtaWNvbnMtb3V0bGluZWRcIj5cbiAgICAgICAgICAgICAgdnBuX2xvY2tcbiAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICA8L21hdC1pY29uPlxuICAgICAgICAgIFJlc3RyaWN0b3JzXG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgPC9zZWN0aW9uPlxuICAgICAgPGZvcm0gW2Zvcm1Hcm91cF09XCJmaWx0ZXJGb3JtXCIgY2xhc3M9XCJkLWZsZXggZmxleC1yb3cganVzdGlmeS1jb250ZW50LWNlbnRlciBhbGlnbi1pdGVtcy1jZW50ZXIgZ2FwLTJcIj5cbiAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCIgY2xhc3M9J2ZsLW1kJz5cbiAgICAgICAgICA8bWF0LWxhYmVsPlNlYXJjaDwvbWF0LWxhYmVsPlxuICAgICAgICAgIDxpbnB1dCBhdXRvY29tcGxldGU9XCJvZmZcIiBtYXRJbnB1dCB0eXBlPVwidGV4dFwiIG5hbWU9XCJzZWFyY2hcIiBwbGFjZWhvbGRlcj1cIlNlYXJjaCBieSBuYW1lLCBlbWFpbFwiXG4gICAgICAgICAgICBmb3JtQ29udHJvbE5hbWU9XCJzZWFyY2hcIj5cbiAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCIgY2xhc3M9J2ZsLXNtJz5cbiAgICAgICAgICA8bWF0LWxhYmVsPlJvbGU8L21hdC1sYWJlbD5cbiAgICAgICAgICA8YXBwLXNlYXJjaGFibGUtc2VsZWN0b3IgYXBpVXJsPVwiYXBpL3JvbGVzXCIgW211bHRpcGxlXT1cInRydWVcIiBmb3JtQ29udHJvbE5hbWU9XCJyb2xlX2lkc1wiXG4gICAgICAgICAgICB0aXRsZUZpZWxkPVwibGFiZWxcIj48L2FwcC1zZWFyY2hhYmxlLXNlbGVjdG9yPlxuICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgICAgICA8bWF0LWJ1dHRvbi10b2dnbGUtZ3JvdXAgY2xhc3M9J21iLTMnIFtoaWRlU2luZ2xlU2VsZWN0aW9uSW5kaWNhdG9yXT1cInRydWVcIiBbaGlkZU11bHRpcGxlU2VsZWN0aW9uSW5kaWNhdG9yXT1cInRydWVcIlxuICAgICAgICAgIGZvcm1Db250cm9sTmFtZT1cInN0YXR1c1wiIG11bHRpcGxlPlxuICAgICAgICAgIDxtYXQtYnV0dG9uLXRvZ2dsZSB2YWx1ZT1cImVuYWJsZWRcIj5FbmFibGVkPC9tYXQtYnV0dG9uLXRvZ2dsZT5cbiAgICAgICAgICA8bWF0LWJ1dHRvbi10b2dnbGUgdmFsdWU9XCJkaXNhYmxlZFwiPkRpc2FibGVkPC9tYXQtYnV0dG9uLXRvZ2dsZT5cbiAgICAgICAgPC9tYXQtYnV0dG9uLXRvZ2dsZS1ncm91cD5cbiAgICAgIDwvZm9ybT5cbiAgICA8L21hdC1jYXJkLWNvbnRlbnQ+XG4gIDwvbWF0LWNhcmQ+XG4gIDxtYXQtY2FyZCBjbGFzcz1cIm10LTIgcC0wXCI+XG4gICAgPG1hdC1jYXJkLWNvbnRlbnQ+XG4gICAgICA8dGFibGUgbWF0LXRhYmxlIFtkYXRhU291cmNlXT1cIm1vZGVsc1wiIGNsYXNzPVwidy0xMDBcIiBhcmlhLWRlc2NyaWJlZGJ5PVwiVXNlcnNcIiBpbmZpbml0ZVNjcm9sbFxuICAgICAgICBbaW5maW5pdGVTY3JvbGxEaXN0YW5jZV09XCIyXCIgW2luZmluaXRlU2Nyb2xsVGhyb3R0bGVdPVwiNTBcIiBbaW5maW5pdGVTY3JvbGxDb250YWluZXJdPVwic2Nyb2xsQ29udGFpbmVyXCJcbiAgICAgICAgW2Zyb21Sb290XT1cInRydWVcIiAoc2Nyb2xsZWQpPVwib25TY3JvbGwoKVwiIG1hdFNvcnQgKG1hdFNvcnRDaGFuZ2UpPVwic29ydENvbHVtbigkZXZlbnQpXCI+XG4gICAgICAgIDwhLS0gSW5kZXggQ29sdW1uIC0tPlxuICAgICAgICA8bmctY29udGFpbmVyIG1hdENvbHVtbkRlZj1cImluZGV4XCI+XG4gICAgICAgICAgPHRoIG1hdC1oZWFkZXItY2VsbCAqbWF0SGVhZGVyQ2VsbERlZj4gIyA8L3RoPlxuICAgICAgICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCBlbGVtZW50OyBsZXQgaSA9IGluZGV4O1wiPiB7eyBpICsgMSB9fSA8L3RkPlxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgICA8IS0tIE5hbWUgQ29sdW1uIC0tPlxuICAgICAgICA8bmctY29udGFpbmVyIG1hdENvbHVtbkRlZj1cIm5hbWVcIj5cbiAgICAgICAgICA8dGggbWF0LWhlYWRlci1jZWxsIG1hdC1zb3J0LWhlYWRlcj1cIm5hbWVcIiAqbWF0SGVhZGVyQ2VsbERlZj4gTmFtZSA8L3RoPlxuICAgICAgICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCBlbGVtZW50XCI+XG4gICAgICAgICAgICA8YSBbcm91dGVyTGlua109XCJbZWxlbWVudD8uaWRdXCIgY2xhc3M9XCJ0ZXh0LWRlY29yYXRpb24tbm9uZVwiPlxuICAgICAgICAgICAgICB7eyBlbGVtZW50Lm5hbWUgfX1cbiAgICAgICAgICAgIDwvYT5cbiAgICAgICAgICAgIDxwIGNsYXNzPVwibWItMCB0ZXh0LXNlY29uZGFyeVwiPlxuICAgICAgICAgICAgICA8IS0tICFlbGVtZW50Py51c2VyX2NsaWVudCBjb25kaXRpb24gYWRkZWQgdG8gY2hlY2sgaWYgdXNlciBoYXMgdXNlcl9jbGllbnQgcmVjb3JkIC0tPlxuICAgICAgICAgICAgICB7eyAhZWxlbWVudD8udXNlcl9jbGllbnQgPyAnJyA6IGVsZW1lbnQ/LnVzZXJfY2xpZW50Py5pc19lbmFibGVkID8gJ0VuYWJsZWQnIDogJ0Rpc2FibGVkJyB9fVxuICAgICAgICAgICAgPC9wPlxuICAgICAgICAgIDwvdGQ+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICAgIDwhLS0gRW1haWwgQ29sdW1uIC0tPlxuICAgICAgICA8bmctY29udGFpbmVyIG1hdENvbHVtbkRlZj1cImVtYWlsXCI+XG4gICAgICAgICAgPHRoIG1hdC1oZWFkZXItY2VsbCBtYXQtc29ydC1oZWFkZXI9XCJlbWFpbFwiICptYXRIZWFkZXJDZWxsRGVmPiBFbWFpbCA8L3RoPlxuICAgICAgICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCBlbGVtZW50XCI+IHt7ZWxlbWVudC5lbWFpbH19IDwvdGQ+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICAgIDwhLS0gVHlwZSBDb2x1bW4gLS0+XG4gICAgICAgIDxuZy1jb250YWluZXIgbWF0Q29sdW1uRGVmPVwidHlwZVwiPlxuICAgICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgbWF0LXNvcnQtaGVhZGVyPVwidXNlcl90eXBlX2lkXCIgKm1hdEhlYWRlckNlbGxEZWY+IFVzZXIgVHlwZSA8L3RoPlxuICAgICAgICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCBlbGVtZW50XCI+IHt7IGdldFVzZXJUeXBlKGVsZW1lbnQpIH19IDwvdGQ+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICAgIDwhLS0gUm9sZXMgQ29sdW1uIC0tPlxuICAgICAgICA8bmctY29udGFpbmVyIG1hdENvbHVtbkRlZj1cInJvbGVzXCI+XG4gICAgICAgICAgPHRoIG1hdC1oZWFkZXItY2VsbCAqbWF0SGVhZGVyQ2VsbERlZj4gUm9sZSA8L3RoPlxuICAgICAgICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCBlbGVtZW50XCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZC1mbGV4IGp1c3RpZnktY29udGVudC1zdGFydCBhbGlnbi1pdGVtcy1jZW50ZXIgZ2FwLTEgZmxleC13cmFwIHRleHQtbGlnaHRcIj5cbiAgICAgICAgICAgICAgPHNwYW4gKm5nRm9yPVwibGV0IHJvbGUgb2YgZWxlbWVudD8ucm9sZXNcIiBjbGFzcz1cImJhZGdlIGJnLXNlY29uZGFyeVwiPlxuICAgICAgICAgICAgICAgIHt7IHJvbGU/LmxhYmVsIH19XG4gICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDwvdGQ+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICAgIDwhLS0gTGFzdCBMb2dpbiBDb2x1bW4gLS0+XG4gICAgICAgIDxuZy1jb250YWluZXIgbWF0Q29sdW1uRGVmPVwibGFzdF9sb2dpblwiPlxuICAgICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgKm1hdEhlYWRlckNlbGxEZWY+IExhc3QgTG9naW4gPC90aD5cbiAgICAgICAgICA8dGQgbWF0LWNlbGwgKm1hdENlbGxEZWY9XCJsZXQgZWxlbWVudFwiPnt7IGVsZW1lbnQ/Lmxhc3RfbG9naW4gfCBkYXRlOidtZWRpdW0nIH19PC90ZD5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgICAgPCEtLSBBZGRlZCBCeSBDb2x1bW4gLS0+XG4gICAgICAgIDxuZy1jb250YWluZXIgbWF0Q29sdW1uRGVmPVwiYWRkZWRfYnlcIj5cbiAgICAgICAgICA8dGggbWF0LWhlYWRlci1jZWxsICptYXRIZWFkZXJDZWxsRGVmPiBBZGRlZCBCeSA8L3RoPlxuICAgICAgICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCBlbGVtZW50XCI+XG4gICAgICAgICAgICA8cCBjbGFzcz1cIm1iLTBcIj57eyBlbGVtZW50Py5jcmVhdG9yPy5uYW1lIH19PC9wPlxuICAgICAgICAgICAgPHAgY2xhc3M9XCJ0ZXh0LXNlY29uZGFyeVwiPnt7IGVsZW1lbnQ/LmNyZWF0ZWRfYXQgfCBkYXRlIH19PC9wPlxuICAgICAgICAgIDwvdGQ+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICAgIDwhLS0gQWN0aW9ucyBDb2x1bW4gLS0+XG4gICAgICAgIDxuZy1jb250YWluZXIgbWF0Q29sdW1uRGVmPVwiYWN0aW9uc1wiPlxuICAgICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgKm1hdEhlYWRlckNlbGxEZWY+IEFjdGlvbiA8L3RoPlxuICAgICAgICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCBlbGVtZW50XCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZC1mbGV4IGZsZXgtcm93IGp1c3RpZnktY29udGVudC1zdGFydCBhbGlnbi1pdGVtcy1jZW50ZXIgZ2FwLTIgdGV4dC1zZWNvbmRhcnlcIj5cbiAgICAgICAgICAgICAgPGFwcC10ZWNobGlmeS1pY29uIHJvbGU9J2J1dHRvbicgbmFtZT1cInZpZXdcIiBjbGFzcz1cImNsaWNrYWJsZVwiIFtyb3V0ZXJMaW5rXT1cIltnZXRVc2VyVmlld1JvdXRlKGVsZW1lbnQpXVwiXG4gICAgICAgICAgICAgICAgbWF0VG9vbHRpcD1cIlZpZXdcIj48L2FwcC10ZWNobGlmeS1pY29uPlxuXG4gICAgICAgICAgICAgIDxhcHAtdGVjaGxpZnktaWNvbiByb2xlPSdidXR0b24nICpuZ0lmPVwiY3VycmVudFVzZXJTZXJ2aWNlLmhhc1Blcm1pc3Npb24oJ3VzZXJfdXBkYXRlJylcIiBuYW1lPVwiZWRpdFwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJjbGlja2FibGVcIiAoY2xpY2spPVwiY3JlYXRlT3JFZGl0VXNlcihlbGVtZW50KVwiIG1hdFRvb2x0aXA9XCJFZGl0XCI+PC9hcHAtdGVjaGxpZnktaWNvbj5cblxuICAgICAgICAgICAgICA8YXBwLXRlY2hsaWZ5LWRlbGV0ZS1idXR0b25cbiAgICAgICAgICAgICAgICAqbmdJZj1cImN1cnJlbnRVc2VyU2VydmljZS5oYXNQZXJtaXNzaW9uKCd1c2VyX2RlbGV0ZScpICYmIGVsZW1lbnQ/LmlkICE9PSBjdXJyZW50VXNlcj8uaWRcIlxuICAgICAgICAgICAgICAgIFttb2RlbF09XCJlbGVtZW50XCIgW3NlcnZpY2VdPVwic2VydmljZVwiIFtkYXRhXT1cInt0aXRsZTogZWxlbWVudD8ubmFtZSwgdHlwZTogJ3VzZXInfVwiXG4gICAgICAgICAgICAgICAgKGRlbGV0ZWQpPVwicmVsb2FkKClcIj48L2FwcC10ZWNobGlmeS1kZWxldGUtYnV0dG9uPlxuXG4gICAgICAgICAgICAgIDxhcHAtdGVjaGxpZnktaWNvbiByb2xlPSdidXR0b24nXG4gICAgICAgICAgICAgICAgKm5nSWY9XCJjdXJyZW50VXNlclNlcnZpY2UuaGFzUGVybWlzc2lvbigndGVjaGxpZnlfcmJhYy51c2VyLnJlc2V0X3Bhc3N3b3JkJylcIiBuYW1lPVwicmVzZXRcIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwiY2xpY2thYmxlXCIgKGNsaWNrKT1cInJlc2V0UGFzc3dvcmQoZWxlbWVudClcIiBtYXRUb29sdGlwPVwiUmVzZXQgVXNlciBQYXNzd29yZFwiPjwvYXBwLXRlY2hsaWZ5LWljb24+XG5cbiAgICAgICAgICAgICAgPGFwcC11c2VyLWVuYWJsZS1idXR0b24gW3VzZXJdPVwiZWxlbWVudFwiIChvblNhdmUpPVwicmVsb2FkKClcIj48L2FwcC11c2VyLWVuYWJsZS1idXR0b24+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L3RkPlxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgICA8dHIgbWF0LWhlYWRlci1yb3cgKm1hdEhlYWRlclJvd0RlZj1cImRpc3BsYXllZENvbHVtbnNcIj48L3RyPlxuICAgICAgICA8dHIgbWF0LXJvdyAqbWF0Um93RGVmPVwibGV0IHJvdzsgY29sdW1uczogZGlzcGxheWVkQ29sdW1ucztcIj48L3RyPlxuICAgICAgPC90YWJsZT5cbiAgICAgIDxtYXQtcHJvZ3Jlc3MtYmFyICpuZ0lmPVwiaXNXb3JraW5nXCIgbW9kZT1cImluZGV0ZXJtaW5hdGVcIj48L21hdC1wcm9ncmVzcy1iYXI+XG4gICAgPC9tYXQtY2FyZC1jb250ZW50PlxuICA8L21hdC1jYXJkPlxuPC9kaXY+Il19