@sumaris-net/ngx-components 2.8.0-rc1 → 2.8.0-rc3
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.
- package/doc/changelog.md +1 -0
- package/esm2022/public_api.mjs +3 -1
- package/esm2022/src/app/admin/users/users.mjs +5 -3
- package/esm2022/src/app/core/account/token.table.mjs +7 -5
- package/esm2022/src/app/core/core.testing.module.mjs +2 -2
- package/esm2022/src/app/core/form/properties/properties.table.mjs +1 -1
- package/esm2022/src/app/core/services/model/settings.model.mjs +2 -1
- package/esm2022/src/app/core/table/table.class.mjs +9 -5
- package/esm2022/src/app/core/table/table.module.mjs +16 -3
- package/esm2022/src/app/core/table/table.pipes.mjs +74 -0
- package/esm2022/src/app/core/table/testing/table.testing.mjs +40 -20
- package/esm2022/src/app/core/table/testing/table2.testing.mjs +40 -14
- package/esm2022/src/app/shared/form/field.component.mjs +1 -1
- package/esm2022/src/app/shared/material/boolean/material.boolean.mjs +8 -6
- package/esm2022/src/app/shared/material/boolean/testing/boolean.test.page.mjs +1 -1
- package/esm2022/src/app/shared/material/testing/common.test.mjs +1 -1
- package/esm2022/src/app/shared/pipes/form.pipes.mjs +10 -10
- package/esm2022/src/app/shared/pipes/pipes.module.mjs +28 -3
- package/esm2022/src/app/shared/pipes/selection.pipes.mjs +176 -0
- package/fesm2022/sumaris-net.ngx-components.mjs +386 -59
- package/fesm2022/sumaris-net.ngx-components.mjs.map +1 -1
- package/package.json +1 -1
- package/public_api.d.ts +2 -0
- package/src/app/core/services/model/settings.model.d.ts +1 -0
- package/src/app/core/table/table.module.d.ts +4 -3
- package/src/app/core/table/table.pipes.d.ts +28 -0
- package/src/app/core/table/testing/table.testing.d.ts +9 -8
- package/src/app/core/table/testing/table2.testing.d.ts +10 -5
- package/src/app/shared/material/boolean/material.boolean.d.ts +2 -2
- package/src/app/shared/pipes/form.pipes.d.ts +1 -1
- package/src/app/shared/pipes/pipes.module.d.ts +5 -4
- package/src/app/shared/pipes/selection.pipes.d.ts +62 -0
- package/src/assets/manifest.json +1 -1
- package/src/theme/_ngx-components.scss +4 -0
- package/src/theme/_ngx-components.table.scss +4 -14
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ChangeDetectionStrategy, Component, forwardRef, Input, ViewChild, } from '@angular/core';
|
|
2
2
|
import { AppTable } from '../table.class';
|
|
3
|
-
import { Referential,
|
|
3
|
+
import { Referential, StatusList } from '../../services/model/referential.model';
|
|
4
4
|
import { IonInfiniteScroll } from '@ionic/angular';
|
|
5
5
|
import { EntitiesTableDataSource } from '../entities-table-datasource.class';
|
|
6
6
|
import { InMemoryEntitiesService } from '../../../shared/services/memory-entity-service.class';
|
|
@@ -12,7 +12,7 @@ import { debounceTime, filter, tap } from 'rxjs/operators';
|
|
|
12
12
|
import { MatExpansionPanel } from '@angular/material/expansion';
|
|
13
13
|
import { StatusIds } from '../../services/model/model.enum';
|
|
14
14
|
import { timer } from 'rxjs';
|
|
15
|
-
import {
|
|
15
|
+
import { RESERVED_END_COLUMNS, RESERVED_START_COLUMNS } from '../table.model';
|
|
16
16
|
import { TableValidatorService } from './table-validator.service';
|
|
17
17
|
import * as i0 from "@angular/core";
|
|
18
18
|
import * as i1 from "../../services/validator/base.validator.class";
|
|
@@ -50,7 +50,9 @@ import * as i32 from "../../../shared/pipes/latlong-format.pipe";
|
|
|
50
50
|
import * as i33 from "../../../shared/pipes/number-format.pipe";
|
|
51
51
|
import * as i34 from "../../../shared/pipes/arrays.pipe";
|
|
52
52
|
import * as i35 from "../../../shared/pipes/form.pipes";
|
|
53
|
-
import * as i36 from "
|
|
53
|
+
import * as i36 from "../../../shared/pipes/selection.pipes";
|
|
54
|
+
import * as i37 from "../table.pipes";
|
|
55
|
+
import * as i38 from "../../services/pipes/referential-to-string.pipe";
|
|
54
56
|
export class TableTestPage extends AppTable {
|
|
55
57
|
validatorService;
|
|
56
58
|
formBuilder;
|
|
@@ -65,10 +67,10 @@ export class TableTestPage extends AppTable {
|
|
|
65
67
|
rowHeight = 48;
|
|
66
68
|
permanentSelectionAllowed = true;
|
|
67
69
|
statusList = StatusList;
|
|
68
|
-
|
|
69
|
-
columnDefinitions = {};
|
|
70
|
+
filterPanelFloating = true;
|
|
70
71
|
enableInfiniteScroll;
|
|
71
|
-
|
|
72
|
+
sticky = true;
|
|
73
|
+
stickyEnd = true;
|
|
72
74
|
get hasMoreData() {
|
|
73
75
|
return this.data.length < 100;
|
|
74
76
|
}
|
|
@@ -161,10 +163,10 @@ export class TableTestPage extends AppTable {
|
|
|
161
163
|
}));
|
|
162
164
|
this.markAsReady();
|
|
163
165
|
}
|
|
164
|
-
ngAfterViewInit() {
|
|
166
|
+
async ngAfterViewInit() {
|
|
165
167
|
super.ngAfterViewInit();
|
|
166
168
|
// Restore filter from settings
|
|
167
|
-
this.restoreFilter();
|
|
169
|
+
await this.restoreFilter();
|
|
168
170
|
// Load data
|
|
169
171
|
this.load();
|
|
170
172
|
}
|
|
@@ -172,16 +174,16 @@ export class TableTestPage extends AppTable {
|
|
|
172
174
|
console.debug('[test-table] Destroying table...');
|
|
173
175
|
super.ngOnDestroy();
|
|
174
176
|
this.stopTimer();
|
|
175
|
-
//this.dataService.stop();
|
|
176
177
|
}
|
|
177
|
-
restoreFilter() {
|
|
178
|
+
async restoreFilter() {
|
|
179
|
+
await this.settings.ready();
|
|
178
180
|
const json = this.settings.getPageSettings(this.settingsId, 'filter');
|
|
179
181
|
console.debug('[table-test] Restoring filter from settings...', json);
|
|
180
182
|
if (json) {
|
|
181
183
|
const filter = ReferentialFilter.fromObject(json);
|
|
182
184
|
this.filterForm.patchValue(json, { emitEvent: false });
|
|
183
185
|
this.filterCriteriaCount = filter.countNotEmptyCriteria();
|
|
184
|
-
this.setFilter(filter, { emitEvent:
|
|
186
|
+
this.setFilter(filter, { emitEvent: true });
|
|
185
187
|
this.markForCheck();
|
|
186
188
|
}
|
|
187
189
|
}
|
|
@@ -191,7 +193,7 @@ export class TableTestPage extends AppTable {
|
|
|
191
193
|
else
|
|
192
194
|
this.startTimer();
|
|
193
195
|
}
|
|
194
|
-
load() {
|
|
196
|
+
async load() {
|
|
195
197
|
console.debug('[test-table] Updating data...');
|
|
196
198
|
this.markAsLoading();
|
|
197
199
|
if (isNil(this.data)) {
|
|
@@ -224,10 +226,24 @@ export class TableTestPage extends AppTable {
|
|
|
224
226
|
formControl.setValue(null);
|
|
225
227
|
return false;
|
|
226
228
|
}
|
|
229
|
+
toggleFilterPanelFloating() {
|
|
230
|
+
this.filterPanelFloating = !this.filterPanelFloating;
|
|
231
|
+
this.markForCheck();
|
|
232
|
+
}
|
|
227
233
|
applyFilterAndClosePanel(event) {
|
|
228
|
-
|
|
234
|
+
const filter = this.filterForm.value;
|
|
235
|
+
this.setFilter(filter, { emitEvent: false });
|
|
229
236
|
this.onRefresh.emit(event);
|
|
230
|
-
this.filterExpansionPanel.
|
|
237
|
+
if (this.filterExpansionPanel && this.filterPanelFloating)
|
|
238
|
+
this.filterExpansionPanel.close();
|
|
239
|
+
}
|
|
240
|
+
closeFilterPanel() {
|
|
241
|
+
if (this.filterExpansionPanel)
|
|
242
|
+
this.filterExpansionPanel.close();
|
|
243
|
+
if (!this.filterPanelFloating) {
|
|
244
|
+
this.filterPanelFloating = true;
|
|
245
|
+
this.markForCheck();
|
|
246
|
+
}
|
|
231
247
|
}
|
|
232
248
|
resetFilter(_) {
|
|
233
249
|
this.filterForm.reset({}, { emitEvent: true });
|
|
@@ -276,7 +292,7 @@ export class TableTestPage extends AppTable {
|
|
|
276
292
|
this.cd.markForCheck();
|
|
277
293
|
}
|
|
278
294
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: TableTestPage, deps: [{ token: i0.Injector }, { token: i1.AppValidatorService }, { token: i2.UntypedFormBuilder }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
279
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
295
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.2.4", type: TableTestPage, selector: "app-table-testing", inputs: { filterPanelFloating: "filterPanelFloating", enableInfiniteScroll: "enableInfiniteScroll", sticky: "sticky", stickyEnd: "stickyEnd" }, providers: [
|
|
280
296
|
{
|
|
281
297
|
provide: AppValidatorService,
|
|
282
298
|
useClass: TableValidatorService,
|
|
@@ -285,7 +301,7 @@ export class TableTestPage extends AppTable {
|
|
|
285
301
|
provide: AppTable,
|
|
286
302
|
useExisting: forwardRef(() => TableTestPage),
|
|
287
303
|
},
|
|
288
|
-
], viewQueries: [{ propertyName: "filterExpansionPanel", first: true, predicate: MatExpansionPanel, descendants: true, static: true }, { propertyName: "infiniteScroll", first: true, predicate: IonInfiniteScroll, descendants: true }], usesInheritance: true, ngImport: i0, template: "<app-toolbar\n color=\"primary\"\n [canGoBack]=\"true\"\n [hasValidate]=\"(loadingSubject | async) !== true && (dirtySubject | async) === true\"\n (onValidate)=\"save()\"\n [backHref]=\"'/testing'\"\n>\n <ion-title>Table (click to edit)</ion-title>\n <ion-buttons slot=\"end\">\n <ng-container *ngIf=\"!selection.hasValue(); else hasSelection\">\n <input matInput type=\"number\" step=\"1\" style=\"color: black; width: 50px\" [(ngModel)]=\"rowHeight\" />\n\n <!-- Add -->\n <button mat-icon-button *ngIf=\"canEdit && !mobile\" [title]=\"'COMMON.BTN_ADD' | translate\" (click)=\"addRow()\">\n <mat-icon>add</mat-icon>\n </button>\n\n <!-- reset filter -->\n <button mat-icon-button (click)=\"resetFilter()\" *ngIf=\"filterCriteriaCount\">\n <mat-icon color=\"accent\">filter_list_alt</mat-icon>\n <mat-icon class=\"icon-secondary\" style=\"left: 16px; top: 5px; font-weight: bold\">close</mat-icon>\n </button>\n\n <!-- show filter -->\n <button mat-icon-button (click)=\"filterExpansionPanel.toggle()\">\n <mat-icon\n *ngIf=\"filterCriteriaCount; else emptyFilter\"\n [matBadge]=\"filterCriteriaCount\"\n matBadgeColor=\"accent\"\n matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n aria-hidden=\"false\"\n >\n filter_list_alt\n </mat-icon>\n <ng-template #emptyFilter>\n <mat-icon>filter_list_alt</mat-icon>\n </ng-template>\n </button>\n\n <!-- save -->\n <button mat-icon-button *ngIf=\"mobile\" [disabled]=\"(dirtySubject | async) !== true\" (click)=\"save()\">\n <mat-icon>save</mat-icon>\n </button>\n\n <!-- start/stop timer to auto-load data -->\n <ion-button *ngIf=\"!timer\" (click)=\"startTimer()\">Start reload</ion-button>\n <ion-button *ngIf=\"timer\" (click)=\"stopTimer()\" color=\"accent\">Stop reload</ion-button>\n </ng-container>\n\n <!-- if row selection -->\n <ng-template #hasSelection>\n <!-- delete -->\n <button\n mat-icon-button\n *ngIf=\"canEdit\"\n [title]=\"'COMMON.BTN_DELETE' | translate\"\n (click)=\"deleteSelection($event)\"\n >\n <mat-icon>delete</mat-icon>\n </button>\n\n <!-- duplicate -->\n <button\n mat-icon-button\n *ngIf=\"canEdit && selection.selected | isArrayLength: { equals: 1 }\"\n [title]=\"'COMMON.BTN_DUPLICATE' | translate\"\n (click)=\"duplicateRow($event, selection.selected[0])\"\n >\n <mat-icon>file_copy</mat-icon>\n </button>\n </ng-template>\n </ion-buttons>\n</app-toolbar>\n<ion-content class=\"ion-no-padding\">\n <ion-refresher slot=\"fixed\" *ngIf=\"mobile\" (ionRefresh)=\"doRefresh($event)\">\n <ion-refresher-content></ion-refresher-content>\n </ion-refresher>\n\n <!-- error -->\n <ion-item *ngIf=\"mobile && error\" lines=\"none\" @slideUpDownAnimation>\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"error | translate\"></ion-label>\n </ion-item>\n\n <!-- search -->\n <mat-expansion-panel #filterExpansionPanel class=\"filter-panel filter-panel-floating\">\n <form class=\"form-container ion-padding-top\" [formGroup]=\"filterForm\" (ngSubmit)=\"applyFilterAndClosePanel($event)\">\n <ion-grid>\n <ion-row>\n <ion-col>\n <!-- search text -->\n <mat-form-field>\n <mat-label>{{ 'TABLE.TESTING.SEARCH_TEXT' | translate }}</mat-label>\n <ion-icon matPrefix name=\"search\"></ion-icon>\n <input matInput formControlName=\"searchText\" autocomplete=\"off\" />\n <button\n mat-icon-button\n matSuffix\n tabindex=\"-1\"\n type=\"button\"\n (click)=\"clearControlValue($event, filterForm.controls.searchText)\"\n [hidden]=\"filterForm.controls.searchText.disabled || !filterForm.controls.searchText.value\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </mat-form-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </form>\n\n <mat-action-row>\n <!-- Counter -->\n <ion-label\n [hidden]=\"(loadingSubject | async) || filterForm.dirty\"\n [color]=\"empty && 'danger'\"\n class=\"ion-padding\"\n >\n {{\n (totalRowCount ? 'COMMON.RESULT_COUNT' : 'COMMON.NO_RESULT')\n | translate\n : {\n count: (totalRowCount | numberFormat)\n }\n }}\n </ion-label>\n\n <div class=\"toolbar-spacer\"></div>\n\n <!-- Close panel -->\n <ion-button\n mat-button\n fill=\"clear\"\n color=\"dark\"\n (click)=\"filterExpansionPanel.close()\"\n [disabled]=\"loadingSubject | async\"\n >\n <ion-text translate>COMMON.BTN_CLOSE</ion-text>\n </ion-button>\n\n <!-- Search button -->\n <ion-button\n mat-button\n [color]=\"filterForm.dirty ? 'tertiary' : 'dark'\"\n [fill]=\"filterForm.dirty ? 'solid' : 'clear'\"\n (click)=\"applyFilterAndClosePanel($event)\"\n >\n <ion-text translate>COMMON.BTN_APPLY</ion-text>\n </ion-button>\n </mat-action-row>\n </mat-expansion-panel>\n\n <!-- table -->\n <div [class.table-container]=\"!enableInfiniteScroll\">\n <table\n #table\n mat-table\n matSort\n matSortDisableClear\n [dataSource]=\"dataSource\"\n [matSortActive]=\"defaultSortBy\"\n [matSortDirection]=\"defaultSortDirection\"\n [trackBy]=\"trackByFn\"\n [style.--mat-row-height]=\"rowHeight + 'px'\"\n >\n >\n\n <!-- group header cells -->\n\n <ng-container matColumnDef=\"top-start\" [sticky]=\"useSticky\">\n <th mat-header-cell *matHeaderCellDef [class.cdk-visually-hidden]=\"!canEdit\" [attr.colspan]=\"2\">\n <!-- start spacer -->\n </th>\n </ng-container>\n\n <ng-container matColumnDef=\"group-1\">\n <th mat-header-cell *matHeaderCellDef [attr.colspan]=\"3\">\n <ion-label translate>{{ i18nColumnPrefix + 'GROUP_1' }}</ion-label>\n </th>\n </ng-container>\n\n <ng-container matColumnDef=\"group-2\">\n <th mat-header-cell *matHeaderCellDef [attr.colspan]=\"3\">\n <ion-label translate>{{ i18nColumnPrefix + 'GROUP_2' }}</ion-label>\n </th>\n </ng-container>\n\n <ng-container matColumnDef=\"top-end\">\n <th mat-header-cell *matHeaderCellDef [attr.colspan]=\"2\">\n <!-- end spacer -->\n </th>\n </ng-container>\n\n <ng-container matColumnDef=\"select\" [sticky]=\"useSticky\" [class.mat-column-sticky]=\"useSticky\">\n <th mat-header-cell *matHeaderCellDef [class.cdk-visually-hidden]=\"!canEdit\">\n <mat-checkbox\n (change)=\"$event ? masterToggle() : null\"\n [checked]=\"selection.hasValue() && isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n ></mat-checkbox>\n </th>\n <td mat-cell *matCellDef=\"let row\" [class.cdk-visually-hidden]=\"!canEdit\">\n <mat-checkbox (click)=\"toggleSelectRow($event, row)\" [checked]=\"selection.isSelected(row)\"></mat-checkbox>\n </td>\n </ng-container>\n\n <!-- Id column -->\n <ng-container matColumnDef=\"id\" [sticky]=\"useSticky\" [class.mat-column-sticky]=\"useSticky\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label>#</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\">{{ row.currentData?.id }}</td>\n </ng-container>\n\n <!-- Label column -->\n <ng-container matColumnDef=\"label\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>TABLE.TESTING.LABEL</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"focusColumn = 'label'\">\n <mat-form-field *ngIf=\"row.editing; else readonlyCell\" [hideRequiredMarker]=\"false\">\n <input\n matInput\n autocomplete=\"off\"\n [formControl]=\"row.validator.controls['label']\"\n [placeholder]=\"'TABLE.TESTING.LABEL' | translate\"\n [appAutofocus]=\"row.editing && focusColumn === 'label'\"\n [readonly]=\"!row.editing\"\n />\n <mat-error *ngIf=\"row.validator.controls['label'].hasError('required')\" translate>\n ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n <ng-template #readonlyCell>\n <ion-label appAutoTitle>\n {{ row.validator | formGetValue: 'label' }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Name column -->\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>TABLE.TESTING.NAME</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"focusColumn = 'name'\">\n <mat-form-field *ngIf=\"row.editing; else readonlyCell\">\n <input\n matInput\n [formControl]=\"row.validator?.controls.name\"\n [placeholder]=\"'TABLE.TESTING.NAME' | translate\"\n [appAutofocus]=\"row.editing && focusColumn === 'name'\"\n />\n <mat-error *ngIf=\"row.validator?.controls.name.hasError('required')\" translate>\n ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n <ng-template #readonlyCell>\n <ion-label appAutoTitle>\n {{ row.validator | formGetValue: 'name' }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Level column -->\n <ng-container matColumnDef=\"levelId\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>TABLE.TESTING.LEVEL_ID</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"focusColumn = 'levelId'\">\n <mat-autocomplete-field\n *ngIf=\"row.editing; else readonlyCell\"\n [formControl]=\"row.validator.controls.levelId\"\n [placeholder]=\"'TABLE.TESTING.LEVEL_ID' | translate\"\n floatLabel=\"never\"\n [config]=\"autocompleteFields.level\"\n [readonly]=\"!row.editing\"\n [autofocus]=\"focusColumn === 'levelId'\"\n [required]=\"true\"\n ></mat-autocomplete-field>\n <ng-template #readonlyCell>\n <ion-label appAutoTitle>\n {{ row.validator | formGetValue: 'levelId' | referentialToString: autocompleteFields.level.attributes }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Status column -->\n <ng-container matColumnDef=\"statusId\">\n <th mat-header-cell *matHeaderCellDef>\n <span translate>USER.STATUS</span>\n </th>\n <td mat-cell *matCellDef=\"let row\"\n [class.mat-form-field-disabled]=\"!row.editing\"\n (click)=\"focusColumn = 'statusId'\">\n <mat-form-field>\n <mat-select\n [formControl]=\"row.validator.controls['statusId']\"\n [placeholder]=\"i18nColumnPrefix + 'STATUS_ID' | translate\"\n >\n <mat-option *ngFor=\"let item of statusList\" [value]=\"item.id\">\n <mat-icon><ion-icon [name]=\"item.icon\"></ion-icon></mat-icon>\n <mat-label>{{ item.label | translate }}</mat-label>\n </mat-option>\n </mat-select>\n <mat-error *ngIf=\"row.validator.controls['statusId'].hasError('required')\" translate>\n ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n </td>\n </ng-container>\n\n <!-- Enum column -->\n <!-- NOTE : Never used in table -->\n <!-- <ng-container matColumnDef=\"values\">-->\n <!-- <th mat-header-cell *matHeaderCellDef>-->\n <!-- <span translate>Enums</span>-->\n <!-- </th>-->\n <!-- <td mat-cell *matCellDef=\"let row\" [class.mat-form-field-disabled]=\"!row.editing\">-->\n <!-- <app-form-field-->\n <!-- [formControl]=\"row.validator|formGetControl:'properties.values'\"-->\n <!-- [definition]=\"columnDefinitions['values']\"-->\n <!-- ></app-form-field>-->\n <!-- </td>-->\n <!-- </ng-container>-->\n\n <!-- boolean (as checkbox) -->\n <ng-container matColumnDef=\"boolean\">\n <th mat-header-cell *matHeaderCellDef cdkDrag [resizable]=\"true\">\n <!-- if sortable, wrap the header with a mat-sort-header -->\n <span mat-sort-header>\n <ion-label>Boolean</ion-label>\n </span>\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-boolean-field\n *ngIf=\"!readOnly && row.editing; else readOnlyTemplate\"\n floatLabel=\"never\"\n [style]=\"'checkbox'\"\n placeholder=\"Oui/Non\"\n [formControl]=\"row.validator | formGetControl: 'properties.boolean'\"\n [compact]=\"true\"\n ></mat-boolean-field>\n <ng-template #readOnlyTemplate>\n <ion-label appAutoTitle>\n {{ (row.validator | formGetValue: 'properties.boolean') ? '✔' : '✘' }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- date -->\n <ng-container matColumnDef=\"date\">\n <th mat-header-cell *matHeaderCellDef cdkDrag [resizable]=\"true\" class=\"mat-cell-date-time\">\n <!-- if sortable, wrap the header with a mat-sort-header -->\n <span mat-sort-header>\n <ion-label>Date</ion-label>\n </span>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-cell-date-time\" (click)=\"focusColumn='date'\">\n <mat-date-time-field\n *ngIf=\"!readOnly && row.editing && row.validator | formGetControl: 'properties.date'; let dateControl; else readOnlyTemplate\"\n floatLabel=\"never\"\n [formControl]=\"dateControl\"\n [autofocus]=\"focusColumn === 'date'\"\n [compact]=\"true\"\n ></mat-date-time-field>\n <ng-template #readOnlyTemplate>\n <ion-label appAutoTitle>\n {{ (row.validator | formGetValue: 'properties.date') | dateFormat: { time: true } }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- latitude -->\n <ng-container matColumnDef=\"latitude\">\n <th mat-header-cell *matHeaderCellDef cdkDrag [resizable]=\"true\">\n <!-- if sortable, wrap the header with a mat-sort-header -->\n <span mat-sort-header>\n <ion-label>Latitude</ion-label>\n </span>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"focusColumn='latitude'\">\n <mat-latlong-field\n *ngIf=\"!readOnly && row.editing && row.validator | formGetControl: 'properties.latitude'; let latitudeControl; else readOnlyTemplate\"\n floatLabel=\"never\"\n [formControl]=\"latitudeControl\"\n [latLongPattern]=\"'DDMM'\"\n [autofocus]=\"focusColumn === 'latitude'\"\n ></mat-latlong-field>\n <ng-template #readOnlyTemplate>\n <ion-label appAutoTitle>\n {{ (row.validator | formGetValue: 'properties.latitude') | latitudeFormat }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Creation date column -->\n <ng-container matColumnDef=\"updateDate\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>TABLE.TESTING.UPDATE_DATE</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-form-field-disabled\">\n <ion-text color=\"medium\" *ngIf=\"row.id !== -1\">\n <small>\n {{ row.validator | formGetValue: 'creationDate' | dateFormat: { time: true } }}\n </small>\n </ion-text>\n </td>\n </ng-container>\n\n <!-- Comment column -->\n <ng-container matColumnDef=\"comments\">\n <th mat-header-cell *matHeaderCellDef>\n <ion-label translate>TABLE.TESTING.COMMENTS</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-form-field *ngIf=\"row.editing; else iconComment\">\n <!--<textarea matInput [formControl]=\"row.validator?.controls.comments\"\n [placeholder]=\"'TABLE.TESTING.COMMENTS'|translate\"\n [readonly]=\"!row.editing\"></textarea>-->\n\n <input\n type=\"text\"\n matInput\n [formControl]=\"row.validator?.controls.comments\"\n [placeholder]=\"'TABLE.TESTING.COMMENTS' | translate\"\n [readonly]=\"!row.editing\"\n />\n </mat-form-field>\n\n <ng-template #iconComment>\n <ion-icon\n [color]=\"row.validator?.controls.comments.value ? 'tertiary' : 'medium'\"\n name=\"chatbox\"\n slot=\"icon-only\"\n ></ion-icon>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Actions buttons column -->\n <app-actions-column\n [stickyEnd]=\"true\"\n [canCancel]=\"false\"\n [style]=\"'table'\"\n (optionsClick)=\"openSelectColumnsModal($event)\"\n (cancelOrDeleteClick)=\"cancelOrDelete($event.event, $event.row)\"\n (confirmAndAddClick)=\"confirmAndAdd($event.event, $event.row)\"\n (backward)=\"confirmAndBackward($event.event, $event.row)\"\n (forward)=\"confirmAndForward($event.event, $event.row)\"\n [cellTemplate]=\"cellInjection\"\n >\n <!-- cell injection-->\n <ng-template #cellInjection let-row>\n <span *ngIf=\"row.editing && !row.validator.dirty\">-</span>\n </ng-template>\n </app-actions-column>\n\n <tr mat-header-row *matHeaderRowDef=\"groupColumns\" class=\"mat-toolbar\"></tr>\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns; sticky: true\"></tr>\n <tr\n mat-row\n *matRowDef=\"let row; columns: displayedColumns\"\n [class.mat-mdc-row-selected]=\"row.editing\"\n [class.mat-mdc-row-error]=\"row.validator?.invalid\"\n [class.mat-mdc-row-disabled]=\"!row.editing\"\n [class.mat-mdc-row-dirty]=\"row.validator?.dirty\"\n (click)=\"clickRow($event, row)\"\n (keydown.escape)=\"escapeEditingRow($event)\"\n [cdkTrapFocus]=\"row.validator?.invalid\"\n ></tr>\n </table>\n\n <ng-container *ngIf=\"loadingSubject | async; else noResult\">\n <ion-item>\n <ion-skeleton-text animated></ion-skeleton-text>\n </ion-item>\n </ng-container>\n\n <ng-template #noResult>\n <ion-item *ngIf=\"totalRowCount === 0\">\n <ion-text color=\"danger\" class=\"text-italic\" translate>COMMON.NO_RESULT</ion-text>\n </ion-item>\n </ng-template>\n\n <ion-infinite-scroll\n *ngIf=\"enableInfiniteScroll\"\n [threshold]=\"mobile ? '10%' : '2%'\"\n position=\"bottom\"\n (ionInfinite)=\"fetchMore($event)\"\n >\n <ion-infinite-scroll-content\n loadingSpinner=\"circles\"\n [loadingText]=\"'COMMON.LOADING_DOTS' | translate\"\n ></ion-infinite-scroll-content>\n </ion-infinite-scroll>\n </div>\n</ion-content>\n\n<ion-footer>\n <!-- Paginator -->\n <mat-paginator\n *ngIf=\"!enableInfiniteScroll\"\n [length]=\"totalRowCount\"\n [pageSize]=\"defaultPageSize\"\n [pageSizeOptions]=\"defaultPageSizeOptions\"\n showFirstLastButtons\n ></mat-paginator>\n\n <app-form-buttons-bar\n *ngIf=\"canEdit && !mobile\"\n (onCancel)=\"load()\"\n (onSave)=\"save()\"\n [disabled]=\"(loadingSubject | async) || !dirty\"\n >\n <!-- error -->\n <ion-item *ngIf=\"error$ | async\" lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" [innerHTML]=\"error | translate\"></ion-label>\n </ion-item>\n </app-form-buttons-bar>\n</ion-footer>\n\n<ion-fab slot=\"fixed\" vertical=\"bottom\" horizontal=\"end\" *ngIf=\"canEdit && mobile\">\n <ion-fab-button color=\"tertiary\" (click)=\"addRow($event)\">\n <ion-icon name=\"add\"></ion-icon>\n </ion-fab-button>\n</ion-fab>\n", styles: [".table-container .mat-mdc-table{--mat-column-actions-min-width: 62px;--mat-column-actions-max-width: 62px}.table-container .mat-mdc-table .mat-row-selected{padding:3px}.table-container .mat-mdc-table .mat-column-select{min-width:30px}.table-container .mat-mdc-table .mat-column-id{min-width:30px;max-width:30px}.table-container .mat-mdc-table .mat-column-label,.table-container .mat-mdc-table .mat-column-name,.table-container .mat-mdc-table .mat-column-levelId,.table-container .mat-mdc-table .mat-column-statusId{min-width:150px}.table-container .mat-mdc-table .mat-column-comments{min-width:100px;max-width:100px}.table-container .mat-mdc-table .mat-column-updateDate{min-width:110px;max-width:110px}\n"], dependencies: [{ kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i4.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i4.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i4.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i4.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i4.IonFab, selector: "ion-fab", inputs: ["activated", "edge", "horizontal", "vertical"] }, { kind: "component", type: i4.IonFabButton, selector: "ion-fab-button", inputs: ["activated", "closeIcon", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "show", "size", "target", "translucent", "type"] }, { kind: "component", type: i4.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i4.IonGrid, selector: "ion-grid", inputs: ["fixed"] }, { kind: "component", type: i4.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i4.IonInfiniteScroll, selector: "ion-infinite-scroll", inputs: ["disabled", "position", "threshold"] }, { kind: "component", type: i4.IonInfiniteScrollContent, selector: "ion-infinite-scroll-content", inputs: ["loadingSpinner", "loadingText"] }, { kind: "component", type: i4.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i4.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i4.IonRefresher, selector: "ion-refresher", inputs: ["closeDuration", "disabled", "mode", "pullFactor", "pullMax", "pullMin", "snapbackDuration"] }, { kind: "component", type: i4.IonRefresherContent, selector: "ion-refresher-content", inputs: ["pullingIcon", "pullingText", "refreshingSpinner", "refreshingText"] }, { kind: "component", type: i4.IonRow, selector: "ion-row" }, { kind: "component", type: i4.IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: i4.IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: i4.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "directive", type: i5.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.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: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i6.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "component", type: i7.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i7.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i7.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i7.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i7.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i7.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i7.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i7.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i7.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i7.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i8.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i8.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "component", type: i9.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { 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: "directive", type: i10.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i10.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "directive", type: i10.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: i11.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: "component", type: i12.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "component", type: i13.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "directive", type: i13.MatExpansionPanelActionRow, selector: "mat-action-row" }, { kind: "component", type: i14.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i15.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i16.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i17.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i18.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "directive", type: i19.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "component", type: i20.MatAutocompleteField, selector: "mat-autocomplete-field", inputs: ["equals", "logPrefix", "formControl", "formControlName", "floatLabel", "appearance", "subscriptSizing", "placeholder", "suggestFn", "required", "mobile", "clearable", "debounceTime", "displayWith", "displayAttributes", "displayColumnSizes", "displayColumnNames", "highlightAccent", "showAllOnFocus", "showPanelOnFocus", "autofocus", "config", "i18nPrefix", "noResultMessage", "class", "panelWidth", "matAutocompletePosition", "multiple", "fetchMoreThreshold", "suggestLengthThreshold", "showLoadingSpinner", "debug", "showSearchBar", "stickySearchBar", "applyImplicitValue", "dropButtonTitle", "clearButtonTitle", "filter", "readonly", "tabindex", "items"], outputs: ["click", "blur", "focus", "dropButtonClick", "keydown.escape", "keyup.enter"] }, { kind: "component", type: i21.MatLatLongField, selector: "mat-latlong-field", inputs: ["formControl", "formControlName", "type", "latLongPattern", "required", "floatLabel", "placeholder", "tabindex", "defaultSign", "maxDecimals", "placeholderChar", "autofocus", "appearance", "readonly", "subscriptSizing"], outputs: ["onBlur", "onFocus"] }, { kind: "component", type: i22.MatDateTime, selector: "mat-date-time-field", inputs: ["placeholder", "floatLabel", "mobile", "compact", "autofocus", "startDate", "clearable", "datePickerFilter", "appearance", "subscriptSizing", "formControl", "formControlName", "required", "readonly", "tabindex"] }, { kind: "component", type: i23.MatBooleanField, selector: "mat-boolean-field", inputs: ["disabled", "formControl", "formControlName", "placeholder", "floatLabel", "appearance", "subscriptSizing", "readonly", "required", "compact", "style", "buttonsColCount", "class", "yesLabel", "noLabel", "showButtonIcons", "yesIcon", "noIcon", "tabindex", "value"], outputs: ["keyup.enter", "onBlur"] }, { kind: "directive", type: i24.AutofocusDirective, selector: "[autofocus], input[appAutofocus]", inputs: ["appAutofocus", "autofocusDelay"] }, { kind: "directive", type: i25.AutoTitleDirective, selector: "[appAutoTitle]" }, { kind: "component", type: i26.ToolbarComponent, selector: "app-toolbar", inputs: ["progressBarMode", "title", "color", "class", "backHref", "defaultBackHref", "hasValidate", "hasClose", "hasSearch", "canGoBack", "canShowMenu"], outputs: ["onValidate", "onClose", "onValidateAndClose", "onBackClick", "onSearch"] }, { kind: "component", type: i27.FormButtonsBarComponent, selector: "app-form-buttons-bar", inputs: ["disabled", "disabledCancel", "classList", "saveButtonColor", "backText", "cancelText", "nextText", "showBack", "showCancel", "showNext", "showSave", "showSaveAndClose", "showSaveAndNext"], outputs: ["onCancel", "onSave", "onNext", "onBack", "onSaveAndClose", "onSaveAndNext"] }, { kind: "component", type: i28.ActionsColumnComponent, selector: "app-actions-column", inputs: ["matColumnDef", "style", "stickyEnd", "canCancel", "canConfirm", "canDelete", "canBackward", "canForward", "canConfirmAndAdd", "dirtyIcon", "optionsTitle", "class", "cellTemplate"], outputs: ["optionsClick", "cancelOrDeleteClick", "confirmEditCreateClick", "confirmAndAddClick", "backward", "forward"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i29.ResizableComponent, selector: "th[resizable]", inputs: ["resizable"], outputs: ["sizeChanged"] }, { kind: "directive", type: i30.ResizableDirective, selector: "[resizable]", outputs: ["resizable", "fit"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }, { kind: "pipe", type: i31.DateFormatPipe, name: "dateFormat" }, { kind: "pipe", type: i32.LatitudeFormatPipe, name: "latitudeFormat" }, { kind: "pipe", type: i33.NumberFormatPipe, name: "numberFormat" }, { kind: "pipe", type: i34.ArrayLengthPipe, name: "isArrayLength" }, { kind: "pipe", type: i35.FormGetControlPipe, name: "formGetControl" }, { kind: "pipe", type: i35.FormGetValuePipe, name: "formGetValue" }, { kind: "pipe", type: i36.ReferentialToStringPipe, name: "referentialToString" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
304
|
+
], viewQueries: [{ propertyName: "filterExpansionPanel", first: true, predicate: MatExpansionPanel, descendants: true, static: true }, { propertyName: "infiniteScroll", first: true, predicate: IonInfiniteScroll, descendants: true }], usesInheritance: true, ngImport: i0, template: "<app-toolbar\n color=\"primary\"\n [canGoBack]=\"true\"\n [hasValidate]=\"(loadingSubject | async) !== true && (dirtySubject | async) === true\"\n (onValidate)=\"save()\"\n [backHref]=\"'/testing'\"\n>\n <ion-title>Table (click to edit)</ion-title>\n <ion-buttons slot=\"end\">\n @if (selection | isEmptySelection) {\n <input matInput type=\"number\" step=\"1\" style=\"color: black; width: 50px\" [(ngModel)]=\"rowHeight\" />\n\n <!-- Add -->\n <button mat-icon-button *ngIf=\"canEdit && !mobile\" [title]=\"'COMMON.BTN_ADD' | translate\" (click)=\"addRow()\">\n <mat-icon>add</mat-icon>\n </button>\n\n <!-- reset filter -->\n <button mat-icon-button (click)=\"resetFilter()\" *ngIf=\"filterCriteriaCount\">\n <mat-icon color=\"accent\">filter_list_alt</mat-icon>\n <mat-icon class=\"icon-secondary\" style=\"left: 16px; top: 5px; font-weight: bold\">close</mat-icon>\n </button>\n\n <!-- show filter -->\n <button mat-icon-button (click)=\"filterExpansionPanel.toggle()\">\n <mat-icon\n *ngIf=\"filterCriteriaCount; else emptyFilter\"\n [matBadge]=\"filterCriteriaCount\"\n matBadgeColor=\"accent\"\n matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n aria-hidden=\"false\"\n >\n filter_list_alt\n </mat-icon>\n <ng-template #emptyFilter>\n <mat-icon>filter_list_alt</mat-icon>\n </ng-template>\n </button>\n\n <!-- save -->\n <button mat-icon-button *ngIf=\"mobile\" [disabled]=\"(dirtySubject | async) !== true\" (click)=\"save()\">\n <mat-icon>save</mat-icon>\n </button>\n\n <!-- start/stop timer to auto-load data -->\n <ion-button *ngIf=\"!timer\" (click)=\"startTimer()\">Start reload</ion-button>\n <ion-button *ngIf=\"timer\" (click)=\"stopTimer()\" color=\"accent\">Stop reload</ion-button>\n } @else {\n <!-- if row selection -->\n <!-- delete -->\n <button\n mat-icon-button\n *ngIf=\"canEdit\"\n [title]=\"'COMMON.BTN_DELETE' | translate\"\n (click)=\"deleteSelection($event)\"\n >\n <mat-icon>delete</mat-icon>\n </button>\n\n <!-- duplicate -->\n <button\n mat-icon-button\n *ngIf=\"canEdit && selection.selected | isArrayLength: { equals: 1 }\"\n [title]=\"'COMMON.BTN_DUPLICATE' | translate\"\n (click)=\"duplicateRow($event, selection.selected[0])\"\n >\n <mat-icon>file_copy</mat-icon>\n </button>\n }\n </ion-buttons>\n</app-toolbar>\n<ion-content class=\"ion-no-padding\">\n <ion-refresher slot=\"fixed\" *ngIf=\"mobile\" (ionRefresh)=\"doRefresh($event)\">\n <ion-refresher-content></ion-refresher-content>\n </ion-refresher>\n\n <!-- error -->\n <ion-item *ngIf=\"mobile && error\" lines=\"none\" @slideUpDownAnimation>\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"error | translate\"></ion-label>\n </ion-item>\n\n <!-- search -->\n <mat-expansion-panel\n #filterExpansionPanel\n class=\"filter-panel\"\n [class.filter-panel-floating]=\"filterPanelFloating\"\n [class.filter-panel-pinned]=\"!filterPanelFloating\"\n >\n <form class=\"form-container ion-padding-top\" [formGroup]=\"filterForm\" (ngSubmit)=\"applyFilterAndClosePanel($event)\">\n <ion-grid>\n <ion-row>\n <ion-col>\n <!-- search text -->\n <mat-form-field>\n <mat-label>{{ 'TABLE.TESTING.SEARCH_TEXT' | translate }}</mat-label>\n <ion-icon matPrefix name=\"search\"></ion-icon>\n <input matInput formControlName=\"searchText\" autocomplete=\"off\" />\n <button\n mat-icon-button\n matSuffix\n tabindex=\"-1\"\n type=\"button\"\n (click)=\"clearControlValue($event, filterForm.controls.searchText)\"\n [hidden]=\"filterForm.controls.searchText.disabled || !filterForm.controls.searchText.value\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </mat-form-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </form>\n\n <mat-action-row>\n <!-- Counter -->\n <ion-label\n [hidden]=\"(loadingSubject | async) || filterForm.dirty\"\n [color]=\"empty && 'danger'\"\n class=\"ion-padding\"\n >\n {{\n (totalRowCount ? 'COMMON.RESULT_COUNT' : 'COMMON.NO_RESULT')\n | translate\n : {\n count: (totalRowCount | numberFormat)\n }\n }}\n </ion-label>\n\n <div class=\"toolbar-spacer\"></div>\n\n <button\n mat-icon-button\n color=\"accent\"\n *ngIf=\"filterPanelFloating\"\n (click)=\"toggleFilterPanelFloating()\"\n class=\"hidden-xs hidden-sm hidden-md\"\n [title]=\"(filterPanelFloating ? 'COMMON.BTN_EXPAND' : 'COMMON.BTN_HIDE') | translate\"\n >\n <mat-icon>\n <span style=\"transform: rotate(90deg)\">{{ filterPanelFloating ? '»' : '«' }}</span>\n </mat-icon>\n </button>\n\n <!-- Close panel -->\n <ion-button mat-button fill=\"clear\" color=\"dark\" (click)=\"closeFilterPanel()\" [disabled]=\"loadingSubject | async\">\n <ion-text translate>COMMON.BTN_CLOSE</ion-text>\n </ion-button>\n\n <!-- Search button -->\n <ion-button\n mat-button\n [color]=\"filterForm.dirty ? 'tertiary' : 'dark'\"\n [fill]=\"filterForm.dirty ? 'solid' : 'clear'\"\n (click)=\"applyFilterAndClosePanel($event)\"\n >\n <ion-text translate>COMMON.BTN_APPLY</ion-text>\n </ion-button>\n </mat-action-row>\n </mat-expansion-panel>\n\n <!-- table -->\n <div [class.table-container]=\"!enableInfiniteScroll\">\n <table\n #table\n mat-table\n matSort\n matSortDisableClear\n [dataSource]=\"dataSource\"\n [matSortActive]=\"defaultSortBy\"\n [matSortDirection]=\"defaultSortDirection\"\n [trackBy]=\"trackByFn\"\n [style.--mat-row-height]=\"rowHeight + 'px'\"\n >\n <!-- group header cells -->\n <ng-container matColumnDef=\"top-start\" [sticky]=\"sticky\">\n <th mat-header-cell *matHeaderCellDef [class.cdk-visually-hidden]=\"!canEdit\" [attr.colspan]=\"2\">\n <!-- start spacer -->\n </th>\n </ng-container>\n\n <ng-container matColumnDef=\"group-1\">\n <th mat-header-cell *matHeaderCellDef [attr.colspan]=\"3\">\n <ion-label translate>{{ i18nColumnPrefix + 'GROUP_1' }}</ion-label>\n </th>\n </ng-container>\n\n <ng-container matColumnDef=\"group-2\">\n <th mat-header-cell *matHeaderCellDef [attr.colspan]=\"displayedColumns.length - 6\">\n <ion-label translate>{{ i18nColumnPrefix + 'GROUP_2' }}</ion-label>\n </th>\n </ng-container>\n\n <ng-container matColumnDef=\"top-end\" [stickyEnd]=\"stickyEnd\">\n <th mat-header-cell *matHeaderCellDef>\n <!-- end spacer -->\n <ion-label></ion-label>\n </th>\n </ng-container>\n\n <ng-container matColumnDef=\"select\" [sticky]=\"sticky\" [class.mat-column-sticky]=\"sticky\">\n <th mat-header-cell *matHeaderCellDef [class.cdk-visually-hidden]=\"!canEdit\">\n @if (selection | isMultipleSelection) {\n <mat-checkbox\n [checked]=\"this | isAllSelected\"\n [indeterminate]=\"this | isNotAllSelected\"\n (change)=\"$event ? masterToggle() : null\"\n ></mat-checkbox>\n }\n </th>\n <td mat-cell *matCellDef=\"let row\" [class.cdk-visually-hidden]=\"!canEdit\">\n <mat-checkbox [checked]=\"selection | isSelected: row\" (click)=\"toggleSelectRow($event, row)\"></mat-checkbox>\n </td>\n </ng-container>\n\n <!-- Id column -->\n <ng-container matColumnDef=\"id\" [sticky]=\"sticky\" [class.mat-column-sticky]=\"sticky\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label>#</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\">{{ row.currentData?.id }}</td>\n </ng-container>\n\n <!-- Label column -->\n <ng-container matColumnDef=\"label\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>TABLE.TESTING.LABEL</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"focusColumn = 'label'\">\n <mat-form-field *ngIf=\"row.editing; else readonlyCell\" [hideRequiredMarker]=\"false\">\n <input\n matInput\n autocomplete=\"off\"\n [formControl]=\"row.validator.controls['label']\"\n [placeholder]=\"'TABLE.TESTING.LABEL' | translate\"\n [appAutofocus]=\"row.editing && focusColumn === 'label'\"\n [readonly]=\"!row.editing\"\n />\n <mat-error *ngIf=\"row.validator.controls['label'].hasError('required')\" translate>\n ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n <ng-template #readonlyCell>\n <ion-label appAutoTitle>\n {{ row.validator | formGetValue: 'label' }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Name column -->\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>TABLE.TESTING.NAME</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"focusColumn = 'name'\">\n <mat-form-field *ngIf=\"row.editing; else readonlyCell\">\n <input\n matInput\n [formControl]=\"row.validator?.controls.name\"\n [placeholder]=\"'TABLE.TESTING.NAME' | translate\"\n [appAutofocus]=\"row.editing && focusColumn === 'name'\"\n />\n <mat-error *ngIf=\"row.validator?.controls.name.hasError('required')\" translate>\n ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n <ng-template #readonlyCell>\n <ion-label appAutoTitle>\n {{ row.validator | formGetValue: 'name' }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Level column -->\n <ng-container matColumnDef=\"levelId\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>TABLE.TESTING.LEVEL_ID</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"focusColumn = 'levelId'\">\n <mat-autocomplete-field\n *ngIf=\"row.editing; else readonlyCell\"\n [formControl]=\"row.validator.controls.levelId\"\n [placeholder]=\"'TABLE.TESTING.LEVEL_ID' | translate\"\n floatLabel=\"never\"\n [config]=\"autocompleteFields.level\"\n [readonly]=\"!row.editing\"\n [autofocus]=\"focusColumn === 'levelId'\"\n [required]=\"true\"\n ></mat-autocomplete-field>\n <ng-template #readonlyCell>\n <ion-label appAutoTitle>\n {{ row.validator | formGetValue: 'levelId' | referentialToString: autocompleteFields.level.attributes }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Status column -->\n <ng-container matColumnDef=\"statusId\">\n <th mat-header-cell *matHeaderCellDef>\n <span translate>USER.STATUS</span>\n </th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n [class.mat-form-field-disabled]=\"!row.editing\"\n (click)=\"focusColumn = 'statusId'\"\n >\n <mat-form-field>\n <mat-select\n [formControl]=\"row.validator.controls['statusId']\"\n [placeholder]=\"i18nColumnPrefix + 'STATUS_ID' | translate\"\n >\n <mat-option *ngFor=\"let item of statusList\" [value]=\"item.id\">\n <mat-icon><ion-icon [name]=\"item.icon\"></ion-icon></mat-icon>\n <mat-label>{{ item.label | translate }}</mat-label>\n </mat-option>\n </mat-select>\n <mat-error *ngIf=\"row.validator.controls['statusId'].hasError('required')\" translate>\n ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n </td>\n </ng-container>\n\n <!-- Enum column -->\n <!-- NOTE : Never used in table -->\n <!-- <ng-container matColumnDef=\"values\">-->\n <!-- <th mat-header-cell *matHeaderCellDef>-->\n <!-- <span translate>Enums</span>-->\n <!-- </th>-->\n <!-- <td mat-cell *matCellDef=\"let row\" [class.mat-form-field-disabled]=\"!row.editing\">-->\n <!-- <app-form-field-->\n <!-- [formControl]=\"row.validator|formGetControl:'properties.values'\"-->\n <!-- [definition]=\"columnDefinitions['values']\"-->\n <!-- ></app-form-field>-->\n <!-- </td>-->\n <!-- </ng-container>-->\n\n <!-- boolean (as checkbox) -->\n <ng-container matColumnDef=\"boolean\">\n <th mat-header-cell *matHeaderCellDef cdkDrag [resizable]=\"true\">\n <!-- if sortable, wrap the header with a mat-sort-header -->\n <span mat-sort-header>\n <ion-label>Boolean</ion-label>\n </span>\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-boolean-field\n *ngIf=\"!readOnly && row.editing; else readOnlyTemplate\"\n floatLabel=\"never\"\n [style]=\"'checkbox'\"\n placeholder=\"Oui/Non\"\n [formControl]=\"row.validator | formGetControl: 'properties.boolean'\"\n [compact]=\"true\"\n ></mat-boolean-field>\n <ng-template #readOnlyTemplate>\n <ion-label appAutoTitle>\n {{ (row.validator | formGetValue: 'properties.boolean') ? '✔' : '✘' }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- date -->\n <ng-container matColumnDef=\"date\">\n <th mat-header-cell *matHeaderCellDef cdkDrag [resizable]=\"true\" class=\"mat-cell-date-time\">\n <!-- if sortable, wrap the header with a mat-sort-header -->\n <span mat-sort-header>\n <ion-label>Date</ion-label>\n </span>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-cell-date-time\" (click)=\"focusColumn = 'date'\">\n <mat-date-time-field\n *ngIf=\"\n !readOnly && row.editing && row.validator | formGetControl: 'properties.date';\n let dateControl;\n else: readOnlyTemplate\n \"\n floatLabel=\"never\"\n [formControl]=\"dateControl\"\n [autofocus]=\"focusColumn === 'date'\"\n [compact]=\"true\"\n ></mat-date-time-field>\n <ng-template #readOnlyTemplate>\n <ion-label appAutoTitle>\n {{ row.validator | formGetValue: 'properties.date' | dateFormat: { time: true } }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- latitude -->\n <ng-container matColumnDef=\"latitude\">\n <th mat-header-cell *matHeaderCellDef cdkDrag [resizable]=\"true\">\n <!-- if sortable, wrap the header with a mat-sort-header -->\n <span mat-sort-header>\n <ion-label>Latitude</ion-label>\n </span>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"focusColumn = 'latitude'\">\n <mat-latlong-field\n *ngIf=\"\n !readOnly && row.editing && row.validator | formGetControl: 'properties.latitude';\n let latitudeControl;\n else: readOnlyTemplate\n \"\n floatLabel=\"never\"\n [formControl]=\"latitudeControl\"\n [latLongPattern]=\"'DDMM'\"\n [autofocus]=\"focusColumn === 'latitude'\"\n ></mat-latlong-field>\n <ng-template #readOnlyTemplate>\n <ion-label appAutoTitle>\n {{ row.validator | formGetValue: 'properties.latitude' | latitudeFormat }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Creation date column -->\n <ng-container matColumnDef=\"updateDate\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>TABLE.TESTING.UPDATE_DATE</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-form-field-disabled\">\n <ion-text color=\"medium\" *ngIf=\"row.id !== -1\">\n <small>\n {{ row.validator | formGetValue: 'creationDate' | dateFormat: { time: true } }}\n </small>\n </ion-text>\n </td>\n </ng-container>\n\n <!-- Comment column -->\n <ng-container matColumnDef=\"comments\">\n <th mat-header-cell *matHeaderCellDef>\n <ion-label translate>TABLE.TESTING.COMMENTS</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-form-field *ngIf=\"row.editing; else iconComment\">\n <!--<textarea matInput [formControl]=\"row.validator?.controls.comments\"\n [placeholder]=\"'TABLE.TESTING.COMMENTS'|translate\"\n [readonly]=\"!row.editing\"></textarea>-->\n\n <input\n type=\"text\"\n matInput\n [formControl]=\"row.validator?.controls.comments\"\n [placeholder]=\"'TABLE.TESTING.COMMENTS' | translate\"\n [readonly]=\"!row.editing\"\n />\n </mat-form-field>\n\n <ng-template #iconComment>\n <ion-icon\n [color]=\"row.validator?.controls.comments.value ? 'tertiary' : 'medium'\"\n name=\"chatbox\"\n slot=\"icon-only\"\n ></ion-icon>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Actions buttons column -->\n <app-actions-column\n [stickyEnd]=\"stickyEnd\"\n [canCancel]=\"false\"\n [style]=\"'table'\"\n (optionsClick)=\"openSelectColumnsModal($event)\"\n (cancelOrDeleteClick)=\"cancelOrDelete($event.event, $event.row)\"\n (confirmAndAddClick)=\"confirmAndAdd($event.event, $event.row)\"\n (backward)=\"confirmAndBackward($event.event, $event.row)\"\n (forward)=\"confirmAndForward($event.event, $event.row)\"\n [cellTemplate]=\"cellInjection\"\n >\n <!-- cell injection-->\n <ng-template #cellInjection let-row>\n <span *ngIf=\"row.editing && !row.validator.dirty\">-</span>\n </ng-template>\n </app-actions-column>\n\n <tr mat-header-row *matHeaderRowDef=\"groupColumns\"></tr>\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns; sticky: true\"></tr>\n <tr\n mat-row\n *matRowDef=\"let row; columns: displayedColumns\"\n [class.mat-mdc-row-selected]=\"row.editing\"\n [class.mat-mdc-row-error]=\"row.invalid\"\n [class.mat-mdc-row-disabled]=\"!row.editing\"\n [class.mat-mdc-row-dirty]=\"row.dirty\"\n (click)=\"clickRow($event, row)\"\n (keydown.escape)=\"escapeEditingRow($event)\"\n [cdkTrapFocus]=\"row.invalid\"\n ></tr>\n </table>\n\n <ng-container *ngIf=\"loadingSubject | async; else noResult\">\n <ion-item>\n <ion-skeleton-text animated></ion-skeleton-text>\n </ion-item>\n </ng-container>\n\n <ng-template #noResult>\n <ion-item *ngIf=\"totalRowCount === 0\">\n <ion-text color=\"danger\" class=\"text-italic\" translate>COMMON.NO_RESULT</ion-text>\n </ion-item>\n </ng-template>\n\n <ion-infinite-scroll\n *ngIf=\"enableInfiniteScroll\"\n [threshold]=\"mobile ? '10%' : '2%'\"\n position=\"bottom\"\n (ionInfinite)=\"fetchMore($event)\"\n >\n <ion-infinite-scroll-content\n loadingSpinner=\"circles\"\n [loadingText]=\"'COMMON.LOADING_DOTS' | translate\"\n ></ion-infinite-scroll-content>\n </ion-infinite-scroll>\n </div>\n</ion-content>\n\n<ion-footer>\n <!-- Paginator -->\n <mat-paginator\n *ngIf=\"!enableInfiniteScroll\"\n [length]=\"totalRowCount\"\n [pageSize]=\"defaultPageSize\"\n [pageSizeOptions]=\"defaultPageSizeOptions\"\n showFirstLastButtons\n ></mat-paginator>\n\n <app-form-buttons-bar\n *ngIf=\"canEdit && !mobile\"\n (onCancel)=\"load()\"\n (onSave)=\"save()\"\n [disabled]=\"(loadingSubject | async) || !dirty\"\n >\n <!-- error -->\n <ion-item *ngIf=\"error$ | async\" lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" [innerHTML]=\"error | translate\"></ion-label>\n </ion-item>\n </app-form-buttons-bar>\n</ion-footer>\n\n<ion-fab slot=\"fixed\" vertical=\"bottom\" horizontal=\"end\" *ngIf=\"canEdit && mobile\">\n <ion-fab-button color=\"tertiary\" (click)=\"addRow($event)\">\n <ion-icon name=\"add\"></ion-icon>\n </ion-fab-button>\n</ion-fab>\n", styles: [".table-container .mat-mdc-table{--mat-column-actions-min-width: 62px;--mat-column-actions-max-width: 62px}.table-container .mat-mdc-table .mat-row-selected{padding:3px}.table-container .mat-mdc-table .mat-column-select{min-width:30px}.table-container .mat-mdc-table .mat-column-id{min-width:30px;max-width:30px}.table-container .mat-mdc-table .mat-column-label,.table-container .mat-mdc-table .mat-column-name,.table-container .mat-mdc-table .mat-column-levelId,.table-container .mat-mdc-table .mat-column-statusId{min-width:150px}.table-container .mat-mdc-table .mat-column-comments{min-width:100px;max-width:100px}.table-container .mat-mdc-table .mat-column-updateDate{min-width:110px;max-width:110px}\n"], dependencies: [{ kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i4.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i4.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i4.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i4.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i4.IonFab, selector: "ion-fab", inputs: ["activated", "edge", "horizontal", "vertical"] }, { kind: "component", type: i4.IonFabButton, selector: "ion-fab-button", inputs: ["activated", "closeIcon", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "show", "size", "target", "translucent", "type"] }, { kind: "component", type: i4.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i4.IonGrid, selector: "ion-grid", inputs: ["fixed"] }, { kind: "component", type: i4.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i4.IonInfiniteScroll, selector: "ion-infinite-scroll", inputs: ["disabled", "position", "threshold"] }, { kind: "component", type: i4.IonInfiniteScrollContent, selector: "ion-infinite-scroll-content", inputs: ["loadingSpinner", "loadingText"] }, { kind: "component", type: i4.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i4.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i4.IonRefresher, selector: "ion-refresher", inputs: ["closeDuration", "disabled", "mode", "pullFactor", "pullMax", "pullMin", "snapbackDuration"] }, { kind: "component", type: i4.IonRefresherContent, selector: "ion-refresher-content", inputs: ["pullingIcon", "pullingText", "refreshingSpinner", "refreshingText"] }, { kind: "component", type: i4.IonRow, selector: "ion-row" }, { kind: "component", type: i4.IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: i4.IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: i4.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "directive", type: i5.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.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: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i6.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "component", type: i7.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i7.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i7.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i7.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i7.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i7.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i7.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i7.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i7.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i7.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i8.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i8.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "component", type: i9.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { 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: "directive", type: i10.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i10.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "directive", type: i10.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: i11.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: "component", type: i12.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "component", type: i13.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "directive", type: i13.MatExpansionPanelActionRow, selector: "mat-action-row" }, { kind: "component", type: i14.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i15.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i16.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i17.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i18.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "directive", type: i19.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "component", type: i20.MatAutocompleteField, selector: "mat-autocomplete-field", inputs: ["equals", "logPrefix", "formControl", "formControlName", "floatLabel", "appearance", "subscriptSizing", "placeholder", "suggestFn", "required", "mobile", "clearable", "debounceTime", "displayWith", "displayAttributes", "displayColumnSizes", "displayColumnNames", "highlightAccent", "showAllOnFocus", "showPanelOnFocus", "autofocus", "config", "i18nPrefix", "noResultMessage", "class", "panelWidth", "matAutocompletePosition", "multiple", "fetchMoreThreshold", "suggestLengthThreshold", "showLoadingSpinner", "debug", "showSearchBar", "stickySearchBar", "applyImplicitValue", "dropButtonTitle", "clearButtonTitle", "filter", "readonly", "tabindex", "items"], outputs: ["click", "blur", "focus", "dropButtonClick", "keydown.escape", "keyup.enter"] }, { kind: "component", type: i21.MatLatLongField, selector: "mat-latlong-field", inputs: ["formControl", "formControlName", "type", "latLongPattern", "required", "floatLabel", "placeholder", "tabindex", "defaultSign", "maxDecimals", "placeholderChar", "autofocus", "appearance", "readonly", "subscriptSizing"], outputs: ["onBlur", "onFocus"] }, { kind: "component", type: i22.MatDateTime, selector: "mat-date-time-field", inputs: ["placeholder", "floatLabel", "mobile", "compact", "autofocus", "startDate", "clearable", "datePickerFilter", "appearance", "subscriptSizing", "formControl", "formControlName", "required", "readonly", "tabindex"] }, { kind: "component", type: i23.MatBooleanField, selector: "mat-boolean-field", inputs: ["disabled", "formControl", "formControlName", "placeholder", "floatLabel", "appearance", "subscriptSizing", "readonly", "required", "compact", "style", "buttonsColCount", "class", "yesLabel", "noLabel", "showButtonIcons", "yesIcon", "noIcon", "showRadio", "tabindex", "value"], outputs: ["keyup.enter", "onBlur"] }, { kind: "directive", type: i24.AutofocusDirective, selector: "[autofocus], input[appAutofocus]", inputs: ["appAutofocus", "autofocusDelay"] }, { kind: "directive", type: i25.AutoTitleDirective, selector: "[appAutoTitle]" }, { kind: "component", type: i26.ToolbarComponent, selector: "app-toolbar", inputs: ["progressBarMode", "title", "color", "class", "backHref", "defaultBackHref", "hasValidate", "hasClose", "hasSearch", "canGoBack", "canShowMenu"], outputs: ["onValidate", "onClose", "onValidateAndClose", "onBackClick", "onSearch"] }, { kind: "component", type: i27.FormButtonsBarComponent, selector: "app-form-buttons-bar", inputs: ["disabled", "disabledCancel", "classList", "saveButtonColor", "backText", "cancelText", "nextText", "showBack", "showCancel", "showNext", "showSave", "showSaveAndClose", "showSaveAndNext"], outputs: ["onCancel", "onSave", "onNext", "onBack", "onSaveAndClose", "onSaveAndNext"] }, { kind: "component", type: i28.ActionsColumnComponent, selector: "app-actions-column", inputs: ["matColumnDef", "style", "stickyEnd", "canCancel", "canConfirm", "canDelete", "canBackward", "canForward", "canConfirmAndAdd", "dirtyIcon", "optionsTitle", "class", "cellTemplate"], outputs: ["optionsClick", "cancelOrDeleteClick", "confirmEditCreateClick", "confirmAndAddClick", "backward", "forward"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i29.ResizableComponent, selector: "th[resizable]", inputs: ["resizable"], outputs: ["sizeChanged"] }, { kind: "directive", type: i30.ResizableDirective, selector: "[resizable]", outputs: ["resizable", "fit"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }, { kind: "pipe", type: i31.DateFormatPipe, name: "dateFormat" }, { kind: "pipe", type: i32.LatitudeFormatPipe, name: "latitudeFormat" }, { kind: "pipe", type: i33.NumberFormatPipe, name: "numberFormat" }, { kind: "pipe", type: i34.ArrayLengthPipe, name: "isArrayLength" }, { kind: "pipe", type: i35.FormGetControlPipe, name: "formGetControl" }, { kind: "pipe", type: i35.FormGetValuePipe, name: "formGetValue" }, { kind: "pipe", type: i36.IsSelectedPipe, name: "isSelected" }, { kind: "pipe", type: i36.IsEmptySelectionPipe, name: "isEmptySelection" }, { kind: "pipe", type: i36.IsMultipleSelectionPipe, name: "isMultipleSelection" }, { kind: "pipe", type: i37.IsAllSelectedPipe, name: "isAllSelected" }, { kind: "pipe", type: i37.IsNotAllSelectedPipe, name: "isNotAllSelected" }, { kind: "pipe", type: i38.ReferentialToStringPipe, name: "referentialToString" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
289
305
|
}
|
|
290
306
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: TableTestPage, decorators: [{
|
|
291
307
|
type: Component,
|
|
@@ -298,10 +314,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImpor
|
|
|
298
314
|
provide: AppTable,
|
|
299
315
|
useExisting: forwardRef(() => TableTestPage),
|
|
300
316
|
},
|
|
301
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<app-toolbar\n color=\"primary\"\n [canGoBack]=\"true\"\n [hasValidate]=\"(loadingSubject | async) !== true && (dirtySubject | async) === true\"\n (onValidate)=\"save()\"\n [backHref]=\"'/testing'\"\n>\n <ion-title>Table (click to edit)</ion-title>\n <ion-buttons slot=\"end\">\n <ng-container *ngIf=\"!selection.hasValue(); else hasSelection\">\n <input matInput type=\"number\" step=\"1\" style=\"color: black; width: 50px\" [(ngModel)]=\"rowHeight\" />\n\n <!-- Add -->\n <button mat-icon-button *ngIf=\"canEdit && !mobile\" [title]=\"'COMMON.BTN_ADD' | translate\" (click)=\"addRow()\">\n <mat-icon>add</mat-icon>\n </button>\n\n <!-- reset filter -->\n <button mat-icon-button (click)=\"resetFilter()\" *ngIf=\"filterCriteriaCount\">\n <mat-icon color=\"accent\">filter_list_alt</mat-icon>\n <mat-icon class=\"icon-secondary\" style=\"left: 16px; top: 5px; font-weight: bold\">close</mat-icon>\n </button>\n\n <!-- show filter -->\n <button mat-icon-button (click)=\"filterExpansionPanel.toggle()\">\n <mat-icon\n *ngIf=\"filterCriteriaCount; else emptyFilter\"\n [matBadge]=\"filterCriteriaCount\"\n matBadgeColor=\"accent\"\n matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n aria-hidden=\"false\"\n >\n filter_list_alt\n </mat-icon>\n <ng-template #emptyFilter>\n <mat-icon>filter_list_alt</mat-icon>\n </ng-template>\n </button>\n\n <!-- save -->\n <button mat-icon-button *ngIf=\"mobile\" [disabled]=\"(dirtySubject | async) !== true\" (click)=\"save()\">\n <mat-icon>save</mat-icon>\n </button>\n\n <!-- start/stop timer to auto-load data -->\n <ion-button *ngIf=\"!timer\" (click)=\"startTimer()\">Start reload</ion-button>\n <ion-button *ngIf=\"timer\" (click)=\"stopTimer()\" color=\"accent\">Stop reload</ion-button>\n </ng-container>\n\n <!-- if row selection -->\n <ng-template #hasSelection>\n <!-- delete -->\n <button\n mat-icon-button\n *ngIf=\"canEdit\"\n [title]=\"'COMMON.BTN_DELETE' | translate\"\n (click)=\"deleteSelection($event)\"\n >\n <mat-icon>delete</mat-icon>\n </button>\n\n <!-- duplicate -->\n <button\n mat-icon-button\n *ngIf=\"canEdit && selection.selected | isArrayLength: { equals: 1 }\"\n [title]=\"'COMMON.BTN_DUPLICATE' | translate\"\n (click)=\"duplicateRow($event, selection.selected[0])\"\n >\n <mat-icon>file_copy</mat-icon>\n </button>\n </ng-template>\n </ion-buttons>\n</app-toolbar>\n<ion-content class=\"ion-no-padding\">\n <ion-refresher slot=\"fixed\" *ngIf=\"mobile\" (ionRefresh)=\"doRefresh($event)\">\n <ion-refresher-content></ion-refresher-content>\n </ion-refresher>\n\n <!-- error -->\n <ion-item *ngIf=\"mobile && error\" lines=\"none\" @slideUpDownAnimation>\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"error | translate\"></ion-label>\n </ion-item>\n\n <!-- search -->\n <mat-expansion-panel #filterExpansionPanel class=\"filter-panel filter-panel-floating\">\n <form class=\"form-container ion-padding-top\" [formGroup]=\"filterForm\" (ngSubmit)=\"applyFilterAndClosePanel($event)\">\n <ion-grid>\n <ion-row>\n <ion-col>\n <!-- search text -->\n <mat-form-field>\n <mat-label>{{ 'TABLE.TESTING.SEARCH_TEXT' | translate }}</mat-label>\n <ion-icon matPrefix name=\"search\"></ion-icon>\n <input matInput formControlName=\"searchText\" autocomplete=\"off\" />\n <button\n mat-icon-button\n matSuffix\n tabindex=\"-1\"\n type=\"button\"\n (click)=\"clearControlValue($event, filterForm.controls.searchText)\"\n [hidden]=\"filterForm.controls.searchText.disabled || !filterForm.controls.searchText.value\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </mat-form-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </form>\n\n <mat-action-row>\n <!-- Counter -->\n <ion-label\n [hidden]=\"(loadingSubject | async) || filterForm.dirty\"\n [color]=\"empty && 'danger'\"\n class=\"ion-padding\"\n >\n {{\n (totalRowCount ? 'COMMON.RESULT_COUNT' : 'COMMON.NO_RESULT')\n | translate\n : {\n count: (totalRowCount | numberFormat)\n }\n }}\n </ion-label>\n\n <div class=\"toolbar-spacer\"></div>\n\n <!-- Close panel -->\n <ion-button\n mat-button\n fill=\"clear\"\n color=\"dark\"\n (click)=\"filterExpansionPanel.close()\"\n [disabled]=\"loadingSubject | async\"\n >\n <ion-text translate>COMMON.BTN_CLOSE</ion-text>\n </ion-button>\n\n <!-- Search button -->\n <ion-button\n mat-button\n [color]=\"filterForm.dirty ? 'tertiary' : 'dark'\"\n [fill]=\"filterForm.dirty ? 'solid' : 'clear'\"\n (click)=\"applyFilterAndClosePanel($event)\"\n >\n <ion-text translate>COMMON.BTN_APPLY</ion-text>\n </ion-button>\n </mat-action-row>\n </mat-expansion-panel>\n\n <!-- table -->\n <div [class.table-container]=\"!enableInfiniteScroll\">\n <table\n #table\n mat-table\n matSort\n matSortDisableClear\n [dataSource]=\"dataSource\"\n [matSortActive]=\"defaultSortBy\"\n [matSortDirection]=\"defaultSortDirection\"\n [trackBy]=\"trackByFn\"\n [style.--mat-row-height]=\"rowHeight + 'px'\"\n >\n >\n\n <!-- group header cells -->\n\n <ng-container matColumnDef=\"top-start\" [sticky]=\"useSticky\">\n <th mat-header-cell *matHeaderCellDef [class.cdk-visually-hidden]=\"!canEdit\" [attr.colspan]=\"2\">\n <!-- start spacer -->\n </th>\n </ng-container>\n\n <ng-container matColumnDef=\"group-1\">\n <th mat-header-cell *matHeaderCellDef [attr.colspan]=\"3\">\n <ion-label translate>{{ i18nColumnPrefix + 'GROUP_1' }}</ion-label>\n </th>\n </ng-container>\n\n <ng-container matColumnDef=\"group-2\">\n <th mat-header-cell *matHeaderCellDef [attr.colspan]=\"3\">\n <ion-label translate>{{ i18nColumnPrefix + 'GROUP_2' }}</ion-label>\n </th>\n </ng-container>\n\n <ng-container matColumnDef=\"top-end\">\n <th mat-header-cell *matHeaderCellDef [attr.colspan]=\"2\">\n <!-- end spacer -->\n </th>\n </ng-container>\n\n <ng-container matColumnDef=\"select\" [sticky]=\"useSticky\" [class.mat-column-sticky]=\"useSticky\">\n <th mat-header-cell *matHeaderCellDef [class.cdk-visually-hidden]=\"!canEdit\">\n <mat-checkbox\n (change)=\"$event ? masterToggle() : null\"\n [checked]=\"selection.hasValue() && isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n ></mat-checkbox>\n </th>\n <td mat-cell *matCellDef=\"let row\" [class.cdk-visually-hidden]=\"!canEdit\">\n <mat-checkbox (click)=\"toggleSelectRow($event, row)\" [checked]=\"selection.isSelected(row)\"></mat-checkbox>\n </td>\n </ng-container>\n\n <!-- Id column -->\n <ng-container matColumnDef=\"id\" [sticky]=\"useSticky\" [class.mat-column-sticky]=\"useSticky\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label>#</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\">{{ row.currentData?.id }}</td>\n </ng-container>\n\n <!-- Label column -->\n <ng-container matColumnDef=\"label\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>TABLE.TESTING.LABEL</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"focusColumn = 'label'\">\n <mat-form-field *ngIf=\"row.editing; else readonlyCell\" [hideRequiredMarker]=\"false\">\n <input\n matInput\n autocomplete=\"off\"\n [formControl]=\"row.validator.controls['label']\"\n [placeholder]=\"'TABLE.TESTING.LABEL' | translate\"\n [appAutofocus]=\"row.editing && focusColumn === 'label'\"\n [readonly]=\"!row.editing\"\n />\n <mat-error *ngIf=\"row.validator.controls['label'].hasError('required')\" translate>\n ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n <ng-template #readonlyCell>\n <ion-label appAutoTitle>\n {{ row.validator | formGetValue: 'label' }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Name column -->\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>TABLE.TESTING.NAME</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"focusColumn = 'name'\">\n <mat-form-field *ngIf=\"row.editing; else readonlyCell\">\n <input\n matInput\n [formControl]=\"row.validator?.controls.name\"\n [placeholder]=\"'TABLE.TESTING.NAME' | translate\"\n [appAutofocus]=\"row.editing && focusColumn === 'name'\"\n />\n <mat-error *ngIf=\"row.validator?.controls.name.hasError('required')\" translate>\n ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n <ng-template #readonlyCell>\n <ion-label appAutoTitle>\n {{ row.validator | formGetValue: 'name' }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Level column -->\n <ng-container matColumnDef=\"levelId\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>TABLE.TESTING.LEVEL_ID</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"focusColumn = 'levelId'\">\n <mat-autocomplete-field\n *ngIf=\"row.editing; else readonlyCell\"\n [formControl]=\"row.validator.controls.levelId\"\n [placeholder]=\"'TABLE.TESTING.LEVEL_ID' | translate\"\n floatLabel=\"never\"\n [config]=\"autocompleteFields.level\"\n [readonly]=\"!row.editing\"\n [autofocus]=\"focusColumn === 'levelId'\"\n [required]=\"true\"\n ></mat-autocomplete-field>\n <ng-template #readonlyCell>\n <ion-label appAutoTitle>\n {{ row.validator | formGetValue: 'levelId' | referentialToString: autocompleteFields.level.attributes }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Status column -->\n <ng-container matColumnDef=\"statusId\">\n <th mat-header-cell *matHeaderCellDef>\n <span translate>USER.STATUS</span>\n </th>\n <td mat-cell *matCellDef=\"let row\"\n [class.mat-form-field-disabled]=\"!row.editing\"\n (click)=\"focusColumn = 'statusId'\">\n <mat-form-field>\n <mat-select\n [formControl]=\"row.validator.controls['statusId']\"\n [placeholder]=\"i18nColumnPrefix + 'STATUS_ID' | translate\"\n >\n <mat-option *ngFor=\"let item of statusList\" [value]=\"item.id\">\n <mat-icon><ion-icon [name]=\"item.icon\"></ion-icon></mat-icon>\n <mat-label>{{ item.label | translate }}</mat-label>\n </mat-option>\n </mat-select>\n <mat-error *ngIf=\"row.validator.controls['statusId'].hasError('required')\" translate>\n ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n </td>\n </ng-container>\n\n <!-- Enum column -->\n <!-- NOTE : Never used in table -->\n <!-- <ng-container matColumnDef=\"values\">-->\n <!-- <th mat-header-cell *matHeaderCellDef>-->\n <!-- <span translate>Enums</span>-->\n <!-- </th>-->\n <!-- <td mat-cell *matCellDef=\"let row\" [class.mat-form-field-disabled]=\"!row.editing\">-->\n <!-- <app-form-field-->\n <!-- [formControl]=\"row.validator|formGetControl:'properties.values'\"-->\n <!-- [definition]=\"columnDefinitions['values']\"-->\n <!-- ></app-form-field>-->\n <!-- </td>-->\n <!-- </ng-container>-->\n\n <!-- boolean (as checkbox) -->\n <ng-container matColumnDef=\"boolean\">\n <th mat-header-cell *matHeaderCellDef cdkDrag [resizable]=\"true\">\n <!-- if sortable, wrap the header with a mat-sort-header -->\n <span mat-sort-header>\n <ion-label>Boolean</ion-label>\n </span>\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-boolean-field\n *ngIf=\"!readOnly && row.editing; else readOnlyTemplate\"\n floatLabel=\"never\"\n [style]=\"'checkbox'\"\n placeholder=\"Oui/Non\"\n [formControl]=\"row.validator | formGetControl: 'properties.boolean'\"\n [compact]=\"true\"\n ></mat-boolean-field>\n <ng-template #readOnlyTemplate>\n <ion-label appAutoTitle>\n {{ (row.validator | formGetValue: 'properties.boolean') ? '✔' : '✘' }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- date -->\n <ng-container matColumnDef=\"date\">\n <th mat-header-cell *matHeaderCellDef cdkDrag [resizable]=\"true\" class=\"mat-cell-date-time\">\n <!-- if sortable, wrap the header with a mat-sort-header -->\n <span mat-sort-header>\n <ion-label>Date</ion-label>\n </span>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-cell-date-time\" (click)=\"focusColumn='date'\">\n <mat-date-time-field\n *ngIf=\"!readOnly && row.editing && row.validator | formGetControl: 'properties.date'; let dateControl; else readOnlyTemplate\"\n floatLabel=\"never\"\n [formControl]=\"dateControl\"\n [autofocus]=\"focusColumn === 'date'\"\n [compact]=\"true\"\n ></mat-date-time-field>\n <ng-template #readOnlyTemplate>\n <ion-label appAutoTitle>\n {{ (row.validator | formGetValue: 'properties.date') | dateFormat: { time: true } }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- latitude -->\n <ng-container matColumnDef=\"latitude\">\n <th mat-header-cell *matHeaderCellDef cdkDrag [resizable]=\"true\">\n <!-- if sortable, wrap the header with a mat-sort-header -->\n <span mat-sort-header>\n <ion-label>Latitude</ion-label>\n </span>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"focusColumn='latitude'\">\n <mat-latlong-field\n *ngIf=\"!readOnly && row.editing && row.validator | formGetControl: 'properties.latitude'; let latitudeControl; else readOnlyTemplate\"\n floatLabel=\"never\"\n [formControl]=\"latitudeControl\"\n [latLongPattern]=\"'DDMM'\"\n [autofocus]=\"focusColumn === 'latitude'\"\n ></mat-latlong-field>\n <ng-template #readOnlyTemplate>\n <ion-label appAutoTitle>\n {{ (row.validator | formGetValue: 'properties.latitude') | latitudeFormat }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Creation date column -->\n <ng-container matColumnDef=\"updateDate\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>TABLE.TESTING.UPDATE_DATE</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-form-field-disabled\">\n <ion-text color=\"medium\" *ngIf=\"row.id !== -1\">\n <small>\n {{ row.validator | formGetValue: 'creationDate' | dateFormat: { time: true } }}\n </small>\n </ion-text>\n </td>\n </ng-container>\n\n <!-- Comment column -->\n <ng-container matColumnDef=\"comments\">\n <th mat-header-cell *matHeaderCellDef>\n <ion-label translate>TABLE.TESTING.COMMENTS</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-form-field *ngIf=\"row.editing; else iconComment\">\n <!--<textarea matInput [formControl]=\"row.validator?.controls.comments\"\n [placeholder]=\"'TABLE.TESTING.COMMENTS'|translate\"\n [readonly]=\"!row.editing\"></textarea>-->\n\n <input\n type=\"text\"\n matInput\n [formControl]=\"row.validator?.controls.comments\"\n [placeholder]=\"'TABLE.TESTING.COMMENTS' | translate\"\n [readonly]=\"!row.editing\"\n />\n </mat-form-field>\n\n <ng-template #iconComment>\n <ion-icon\n [color]=\"row.validator?.controls.comments.value ? 'tertiary' : 'medium'\"\n name=\"chatbox\"\n slot=\"icon-only\"\n ></ion-icon>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Actions buttons column -->\n <app-actions-column\n [stickyEnd]=\"true\"\n [canCancel]=\"false\"\n [style]=\"'table'\"\n (optionsClick)=\"openSelectColumnsModal($event)\"\n (cancelOrDeleteClick)=\"cancelOrDelete($event.event, $event.row)\"\n (confirmAndAddClick)=\"confirmAndAdd($event.event, $event.row)\"\n (backward)=\"confirmAndBackward($event.event, $event.row)\"\n (forward)=\"confirmAndForward($event.event, $event.row)\"\n [cellTemplate]=\"cellInjection\"\n >\n <!-- cell injection-->\n <ng-template #cellInjection let-row>\n <span *ngIf=\"row.editing && !row.validator.dirty\">-</span>\n </ng-template>\n </app-actions-column>\n\n <tr mat-header-row *matHeaderRowDef=\"groupColumns\" class=\"mat-toolbar\"></tr>\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns; sticky: true\"></tr>\n <tr\n mat-row\n *matRowDef=\"let row; columns: displayedColumns\"\n [class.mat-mdc-row-selected]=\"row.editing\"\n [class.mat-mdc-row-error]=\"row.validator?.invalid\"\n [class.mat-mdc-row-disabled]=\"!row.editing\"\n [class.mat-mdc-row-dirty]=\"row.validator?.dirty\"\n (click)=\"clickRow($event, row)\"\n (keydown.escape)=\"escapeEditingRow($event)\"\n [cdkTrapFocus]=\"row.validator?.invalid\"\n ></tr>\n </table>\n\n <ng-container *ngIf=\"loadingSubject | async; else noResult\">\n <ion-item>\n <ion-skeleton-text animated></ion-skeleton-text>\n </ion-item>\n </ng-container>\n\n <ng-template #noResult>\n <ion-item *ngIf=\"totalRowCount === 0\">\n <ion-text color=\"danger\" class=\"text-italic\" translate>COMMON.NO_RESULT</ion-text>\n </ion-item>\n </ng-template>\n\n <ion-infinite-scroll\n *ngIf=\"enableInfiniteScroll\"\n [threshold]=\"mobile ? '10%' : '2%'\"\n position=\"bottom\"\n (ionInfinite)=\"fetchMore($event)\"\n >\n <ion-infinite-scroll-content\n loadingSpinner=\"circles\"\n [loadingText]=\"'COMMON.LOADING_DOTS' | translate\"\n ></ion-infinite-scroll-content>\n </ion-infinite-scroll>\n </div>\n</ion-content>\n\n<ion-footer>\n <!-- Paginator -->\n <mat-paginator\n *ngIf=\"!enableInfiniteScroll\"\n [length]=\"totalRowCount\"\n [pageSize]=\"defaultPageSize\"\n [pageSizeOptions]=\"defaultPageSizeOptions\"\n showFirstLastButtons\n ></mat-paginator>\n\n <app-form-buttons-bar\n *ngIf=\"canEdit && !mobile\"\n (onCancel)=\"load()\"\n (onSave)=\"save()\"\n [disabled]=\"(loadingSubject | async) || !dirty\"\n >\n <!-- error -->\n <ion-item *ngIf=\"error$ | async\" lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" [innerHTML]=\"error | translate\"></ion-label>\n </ion-item>\n </app-form-buttons-bar>\n</ion-footer>\n\n<ion-fab slot=\"fixed\" vertical=\"bottom\" horizontal=\"end\" *ngIf=\"canEdit && mobile\">\n <ion-fab-button color=\"tertiary\" (click)=\"addRow($event)\">\n <ion-icon name=\"add\"></ion-icon>\n </ion-fab-button>\n</ion-fab>\n", styles: [".table-container .mat-mdc-table{--mat-column-actions-min-width: 62px;--mat-column-actions-max-width: 62px}.table-container .mat-mdc-table .mat-row-selected{padding:3px}.table-container .mat-mdc-table .mat-column-select{min-width:30px}.table-container .mat-mdc-table .mat-column-id{min-width:30px;max-width:30px}.table-container .mat-mdc-table .mat-column-label,.table-container .mat-mdc-table .mat-column-name,.table-container .mat-mdc-table .mat-column-levelId,.table-container .mat-mdc-table .mat-column-statusId{min-width:150px}.table-container .mat-mdc-table .mat-column-comments{min-width:100px;max-width:100px}.table-container .mat-mdc-table .mat-column-updateDate{min-width:110px;max-width:110px}\n"] }]
|
|
302
|
-
}], ctorParameters: () => [{ type: i0.Injector }, { type: i1.AppValidatorService }, { type: i2.UntypedFormBuilder }, { type: i0.ChangeDetectorRef }], propDecorators: {
|
|
317
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<app-toolbar\n color=\"primary\"\n [canGoBack]=\"true\"\n [hasValidate]=\"(loadingSubject | async) !== true && (dirtySubject | async) === true\"\n (onValidate)=\"save()\"\n [backHref]=\"'/testing'\"\n>\n <ion-title>Table (click to edit)</ion-title>\n <ion-buttons slot=\"end\">\n @if (selection | isEmptySelection) {\n <input matInput type=\"number\" step=\"1\" style=\"color: black; width: 50px\" [(ngModel)]=\"rowHeight\" />\n\n <!-- Add -->\n <button mat-icon-button *ngIf=\"canEdit && !mobile\" [title]=\"'COMMON.BTN_ADD' | translate\" (click)=\"addRow()\">\n <mat-icon>add</mat-icon>\n </button>\n\n <!-- reset filter -->\n <button mat-icon-button (click)=\"resetFilter()\" *ngIf=\"filterCriteriaCount\">\n <mat-icon color=\"accent\">filter_list_alt</mat-icon>\n <mat-icon class=\"icon-secondary\" style=\"left: 16px; top: 5px; font-weight: bold\">close</mat-icon>\n </button>\n\n <!-- show filter -->\n <button mat-icon-button (click)=\"filterExpansionPanel.toggle()\">\n <mat-icon\n *ngIf=\"filterCriteriaCount; else emptyFilter\"\n [matBadge]=\"filterCriteriaCount\"\n matBadgeColor=\"accent\"\n matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n aria-hidden=\"false\"\n >\n filter_list_alt\n </mat-icon>\n <ng-template #emptyFilter>\n <mat-icon>filter_list_alt</mat-icon>\n </ng-template>\n </button>\n\n <!-- save -->\n <button mat-icon-button *ngIf=\"mobile\" [disabled]=\"(dirtySubject | async) !== true\" (click)=\"save()\">\n <mat-icon>save</mat-icon>\n </button>\n\n <!-- start/stop timer to auto-load data -->\n <ion-button *ngIf=\"!timer\" (click)=\"startTimer()\">Start reload</ion-button>\n <ion-button *ngIf=\"timer\" (click)=\"stopTimer()\" color=\"accent\">Stop reload</ion-button>\n } @else {\n <!-- if row selection -->\n <!-- delete -->\n <button\n mat-icon-button\n *ngIf=\"canEdit\"\n [title]=\"'COMMON.BTN_DELETE' | translate\"\n (click)=\"deleteSelection($event)\"\n >\n <mat-icon>delete</mat-icon>\n </button>\n\n <!-- duplicate -->\n <button\n mat-icon-button\n *ngIf=\"canEdit && selection.selected | isArrayLength: { equals: 1 }\"\n [title]=\"'COMMON.BTN_DUPLICATE' | translate\"\n (click)=\"duplicateRow($event, selection.selected[0])\"\n >\n <mat-icon>file_copy</mat-icon>\n </button>\n }\n </ion-buttons>\n</app-toolbar>\n<ion-content class=\"ion-no-padding\">\n <ion-refresher slot=\"fixed\" *ngIf=\"mobile\" (ionRefresh)=\"doRefresh($event)\">\n <ion-refresher-content></ion-refresher-content>\n </ion-refresher>\n\n <!-- error -->\n <ion-item *ngIf=\"mobile && error\" lines=\"none\" @slideUpDownAnimation>\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"error | translate\"></ion-label>\n </ion-item>\n\n <!-- search -->\n <mat-expansion-panel\n #filterExpansionPanel\n class=\"filter-panel\"\n [class.filter-panel-floating]=\"filterPanelFloating\"\n [class.filter-panel-pinned]=\"!filterPanelFloating\"\n >\n <form class=\"form-container ion-padding-top\" [formGroup]=\"filterForm\" (ngSubmit)=\"applyFilterAndClosePanel($event)\">\n <ion-grid>\n <ion-row>\n <ion-col>\n <!-- search text -->\n <mat-form-field>\n <mat-label>{{ 'TABLE.TESTING.SEARCH_TEXT' | translate }}</mat-label>\n <ion-icon matPrefix name=\"search\"></ion-icon>\n <input matInput formControlName=\"searchText\" autocomplete=\"off\" />\n <button\n mat-icon-button\n matSuffix\n tabindex=\"-1\"\n type=\"button\"\n (click)=\"clearControlValue($event, filterForm.controls.searchText)\"\n [hidden]=\"filterForm.controls.searchText.disabled || !filterForm.controls.searchText.value\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </mat-form-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </form>\n\n <mat-action-row>\n <!-- Counter -->\n <ion-label\n [hidden]=\"(loadingSubject | async) || filterForm.dirty\"\n [color]=\"empty && 'danger'\"\n class=\"ion-padding\"\n >\n {{\n (totalRowCount ? 'COMMON.RESULT_COUNT' : 'COMMON.NO_RESULT')\n | translate\n : {\n count: (totalRowCount | numberFormat)\n }\n }}\n </ion-label>\n\n <div class=\"toolbar-spacer\"></div>\n\n <button\n mat-icon-button\n color=\"accent\"\n *ngIf=\"filterPanelFloating\"\n (click)=\"toggleFilterPanelFloating()\"\n class=\"hidden-xs hidden-sm hidden-md\"\n [title]=\"(filterPanelFloating ? 'COMMON.BTN_EXPAND' : 'COMMON.BTN_HIDE') | translate\"\n >\n <mat-icon>\n <span style=\"transform: rotate(90deg)\">{{ filterPanelFloating ? '»' : '«' }}</span>\n </mat-icon>\n </button>\n\n <!-- Close panel -->\n <ion-button mat-button fill=\"clear\" color=\"dark\" (click)=\"closeFilterPanel()\" [disabled]=\"loadingSubject | async\">\n <ion-text translate>COMMON.BTN_CLOSE</ion-text>\n </ion-button>\n\n <!-- Search button -->\n <ion-button\n mat-button\n [color]=\"filterForm.dirty ? 'tertiary' : 'dark'\"\n [fill]=\"filterForm.dirty ? 'solid' : 'clear'\"\n (click)=\"applyFilterAndClosePanel($event)\"\n >\n <ion-text translate>COMMON.BTN_APPLY</ion-text>\n </ion-button>\n </mat-action-row>\n </mat-expansion-panel>\n\n <!-- table -->\n <div [class.table-container]=\"!enableInfiniteScroll\">\n <table\n #table\n mat-table\n matSort\n matSortDisableClear\n [dataSource]=\"dataSource\"\n [matSortActive]=\"defaultSortBy\"\n [matSortDirection]=\"defaultSortDirection\"\n [trackBy]=\"trackByFn\"\n [style.--mat-row-height]=\"rowHeight + 'px'\"\n >\n <!-- group header cells -->\n <ng-container matColumnDef=\"top-start\" [sticky]=\"sticky\">\n <th mat-header-cell *matHeaderCellDef [class.cdk-visually-hidden]=\"!canEdit\" [attr.colspan]=\"2\">\n <!-- start spacer -->\n </th>\n </ng-container>\n\n <ng-container matColumnDef=\"group-1\">\n <th mat-header-cell *matHeaderCellDef [attr.colspan]=\"3\">\n <ion-label translate>{{ i18nColumnPrefix + 'GROUP_1' }}</ion-label>\n </th>\n </ng-container>\n\n <ng-container matColumnDef=\"group-2\">\n <th mat-header-cell *matHeaderCellDef [attr.colspan]=\"displayedColumns.length - 6\">\n <ion-label translate>{{ i18nColumnPrefix + 'GROUP_2' }}</ion-label>\n </th>\n </ng-container>\n\n <ng-container matColumnDef=\"top-end\" [stickyEnd]=\"stickyEnd\">\n <th mat-header-cell *matHeaderCellDef>\n <!-- end spacer -->\n <ion-label></ion-label>\n </th>\n </ng-container>\n\n <ng-container matColumnDef=\"select\" [sticky]=\"sticky\" [class.mat-column-sticky]=\"sticky\">\n <th mat-header-cell *matHeaderCellDef [class.cdk-visually-hidden]=\"!canEdit\">\n @if (selection | isMultipleSelection) {\n <mat-checkbox\n [checked]=\"this | isAllSelected\"\n [indeterminate]=\"this | isNotAllSelected\"\n (change)=\"$event ? masterToggle() : null\"\n ></mat-checkbox>\n }\n </th>\n <td mat-cell *matCellDef=\"let row\" [class.cdk-visually-hidden]=\"!canEdit\">\n <mat-checkbox [checked]=\"selection | isSelected: row\" (click)=\"toggleSelectRow($event, row)\"></mat-checkbox>\n </td>\n </ng-container>\n\n <!-- Id column -->\n <ng-container matColumnDef=\"id\" [sticky]=\"sticky\" [class.mat-column-sticky]=\"sticky\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label>#</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\">{{ row.currentData?.id }}</td>\n </ng-container>\n\n <!-- Label column -->\n <ng-container matColumnDef=\"label\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>TABLE.TESTING.LABEL</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"focusColumn = 'label'\">\n <mat-form-field *ngIf=\"row.editing; else readonlyCell\" [hideRequiredMarker]=\"false\">\n <input\n matInput\n autocomplete=\"off\"\n [formControl]=\"row.validator.controls['label']\"\n [placeholder]=\"'TABLE.TESTING.LABEL' | translate\"\n [appAutofocus]=\"row.editing && focusColumn === 'label'\"\n [readonly]=\"!row.editing\"\n />\n <mat-error *ngIf=\"row.validator.controls['label'].hasError('required')\" translate>\n ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n <ng-template #readonlyCell>\n <ion-label appAutoTitle>\n {{ row.validator | formGetValue: 'label' }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Name column -->\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>TABLE.TESTING.NAME</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"focusColumn = 'name'\">\n <mat-form-field *ngIf=\"row.editing; else readonlyCell\">\n <input\n matInput\n [formControl]=\"row.validator?.controls.name\"\n [placeholder]=\"'TABLE.TESTING.NAME' | translate\"\n [appAutofocus]=\"row.editing && focusColumn === 'name'\"\n />\n <mat-error *ngIf=\"row.validator?.controls.name.hasError('required')\" translate>\n ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n <ng-template #readonlyCell>\n <ion-label appAutoTitle>\n {{ row.validator | formGetValue: 'name' }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Level column -->\n <ng-container matColumnDef=\"levelId\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>TABLE.TESTING.LEVEL_ID</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"focusColumn = 'levelId'\">\n <mat-autocomplete-field\n *ngIf=\"row.editing; else readonlyCell\"\n [formControl]=\"row.validator.controls.levelId\"\n [placeholder]=\"'TABLE.TESTING.LEVEL_ID' | translate\"\n floatLabel=\"never\"\n [config]=\"autocompleteFields.level\"\n [readonly]=\"!row.editing\"\n [autofocus]=\"focusColumn === 'levelId'\"\n [required]=\"true\"\n ></mat-autocomplete-field>\n <ng-template #readonlyCell>\n <ion-label appAutoTitle>\n {{ row.validator | formGetValue: 'levelId' | referentialToString: autocompleteFields.level.attributes }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Status column -->\n <ng-container matColumnDef=\"statusId\">\n <th mat-header-cell *matHeaderCellDef>\n <span translate>USER.STATUS</span>\n </th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n [class.mat-form-field-disabled]=\"!row.editing\"\n (click)=\"focusColumn = 'statusId'\"\n >\n <mat-form-field>\n <mat-select\n [formControl]=\"row.validator.controls['statusId']\"\n [placeholder]=\"i18nColumnPrefix + 'STATUS_ID' | translate\"\n >\n <mat-option *ngFor=\"let item of statusList\" [value]=\"item.id\">\n <mat-icon><ion-icon [name]=\"item.icon\"></ion-icon></mat-icon>\n <mat-label>{{ item.label | translate }}</mat-label>\n </mat-option>\n </mat-select>\n <mat-error *ngIf=\"row.validator.controls['statusId'].hasError('required')\" translate>\n ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n </td>\n </ng-container>\n\n <!-- Enum column -->\n <!-- NOTE : Never used in table -->\n <!-- <ng-container matColumnDef=\"values\">-->\n <!-- <th mat-header-cell *matHeaderCellDef>-->\n <!-- <span translate>Enums</span>-->\n <!-- </th>-->\n <!-- <td mat-cell *matCellDef=\"let row\" [class.mat-form-field-disabled]=\"!row.editing\">-->\n <!-- <app-form-field-->\n <!-- [formControl]=\"row.validator|formGetControl:'properties.values'\"-->\n <!-- [definition]=\"columnDefinitions['values']\"-->\n <!-- ></app-form-field>-->\n <!-- </td>-->\n <!-- </ng-container>-->\n\n <!-- boolean (as checkbox) -->\n <ng-container matColumnDef=\"boolean\">\n <th mat-header-cell *matHeaderCellDef cdkDrag [resizable]=\"true\">\n <!-- if sortable, wrap the header with a mat-sort-header -->\n <span mat-sort-header>\n <ion-label>Boolean</ion-label>\n </span>\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-boolean-field\n *ngIf=\"!readOnly && row.editing; else readOnlyTemplate\"\n floatLabel=\"never\"\n [style]=\"'checkbox'\"\n placeholder=\"Oui/Non\"\n [formControl]=\"row.validator | formGetControl: 'properties.boolean'\"\n [compact]=\"true\"\n ></mat-boolean-field>\n <ng-template #readOnlyTemplate>\n <ion-label appAutoTitle>\n {{ (row.validator | formGetValue: 'properties.boolean') ? '✔' : '✘' }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- date -->\n <ng-container matColumnDef=\"date\">\n <th mat-header-cell *matHeaderCellDef cdkDrag [resizable]=\"true\" class=\"mat-cell-date-time\">\n <!-- if sortable, wrap the header with a mat-sort-header -->\n <span mat-sort-header>\n <ion-label>Date</ion-label>\n </span>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-cell-date-time\" (click)=\"focusColumn = 'date'\">\n <mat-date-time-field\n *ngIf=\"\n !readOnly && row.editing && row.validator | formGetControl: 'properties.date';\n let dateControl;\n else: readOnlyTemplate\n \"\n floatLabel=\"never\"\n [formControl]=\"dateControl\"\n [autofocus]=\"focusColumn === 'date'\"\n [compact]=\"true\"\n ></mat-date-time-field>\n <ng-template #readOnlyTemplate>\n <ion-label appAutoTitle>\n {{ row.validator | formGetValue: 'properties.date' | dateFormat: { time: true } }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- latitude -->\n <ng-container matColumnDef=\"latitude\">\n <th mat-header-cell *matHeaderCellDef cdkDrag [resizable]=\"true\">\n <!-- if sortable, wrap the header with a mat-sort-header -->\n <span mat-sort-header>\n <ion-label>Latitude</ion-label>\n </span>\n </th>\n <td mat-cell *matCellDef=\"let row\" (click)=\"focusColumn = 'latitude'\">\n <mat-latlong-field\n *ngIf=\"\n !readOnly && row.editing && row.validator | formGetControl: 'properties.latitude';\n let latitudeControl;\n else: readOnlyTemplate\n \"\n floatLabel=\"never\"\n [formControl]=\"latitudeControl\"\n [latLongPattern]=\"'DDMM'\"\n [autofocus]=\"focusColumn === 'latitude'\"\n ></mat-latlong-field>\n <ng-template #readOnlyTemplate>\n <ion-label appAutoTitle>\n {{ row.validator | formGetValue: 'properties.latitude' | latitudeFormat }}\n </ion-label>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Creation date column -->\n <ng-container matColumnDef=\"updateDate\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n <ion-label translate>TABLE.TESTING.UPDATE_DATE</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\" class=\"mat-form-field-disabled\">\n <ion-text color=\"medium\" *ngIf=\"row.id !== -1\">\n <small>\n {{ row.validator | formGetValue: 'creationDate' | dateFormat: { time: true } }}\n </small>\n </ion-text>\n </td>\n </ng-container>\n\n <!-- Comment column -->\n <ng-container matColumnDef=\"comments\">\n <th mat-header-cell *matHeaderCellDef>\n <ion-label translate>TABLE.TESTING.COMMENTS</ion-label>\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-form-field *ngIf=\"row.editing; else iconComment\">\n <!--<textarea matInput [formControl]=\"row.validator?.controls.comments\"\n [placeholder]=\"'TABLE.TESTING.COMMENTS'|translate\"\n [readonly]=\"!row.editing\"></textarea>-->\n\n <input\n type=\"text\"\n matInput\n [formControl]=\"row.validator?.controls.comments\"\n [placeholder]=\"'TABLE.TESTING.COMMENTS' | translate\"\n [readonly]=\"!row.editing\"\n />\n </mat-form-field>\n\n <ng-template #iconComment>\n <ion-icon\n [color]=\"row.validator?.controls.comments.value ? 'tertiary' : 'medium'\"\n name=\"chatbox\"\n slot=\"icon-only\"\n ></ion-icon>\n </ng-template>\n </td>\n </ng-container>\n\n <!-- Actions buttons column -->\n <app-actions-column\n [stickyEnd]=\"stickyEnd\"\n [canCancel]=\"false\"\n [style]=\"'table'\"\n (optionsClick)=\"openSelectColumnsModal($event)\"\n (cancelOrDeleteClick)=\"cancelOrDelete($event.event, $event.row)\"\n (confirmAndAddClick)=\"confirmAndAdd($event.event, $event.row)\"\n (backward)=\"confirmAndBackward($event.event, $event.row)\"\n (forward)=\"confirmAndForward($event.event, $event.row)\"\n [cellTemplate]=\"cellInjection\"\n >\n <!-- cell injection-->\n <ng-template #cellInjection let-row>\n <span *ngIf=\"row.editing && !row.validator.dirty\">-</span>\n </ng-template>\n </app-actions-column>\n\n <tr mat-header-row *matHeaderRowDef=\"groupColumns\"></tr>\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns; sticky: true\"></tr>\n <tr\n mat-row\n *matRowDef=\"let row; columns: displayedColumns\"\n [class.mat-mdc-row-selected]=\"row.editing\"\n [class.mat-mdc-row-error]=\"row.invalid\"\n [class.mat-mdc-row-disabled]=\"!row.editing\"\n [class.mat-mdc-row-dirty]=\"row.dirty\"\n (click)=\"clickRow($event, row)\"\n (keydown.escape)=\"escapeEditingRow($event)\"\n [cdkTrapFocus]=\"row.invalid\"\n ></tr>\n </table>\n\n <ng-container *ngIf=\"loadingSubject | async; else noResult\">\n <ion-item>\n <ion-skeleton-text animated></ion-skeleton-text>\n </ion-item>\n </ng-container>\n\n <ng-template #noResult>\n <ion-item *ngIf=\"totalRowCount === 0\">\n <ion-text color=\"danger\" class=\"text-italic\" translate>COMMON.NO_RESULT</ion-text>\n </ion-item>\n </ng-template>\n\n <ion-infinite-scroll\n *ngIf=\"enableInfiniteScroll\"\n [threshold]=\"mobile ? '10%' : '2%'\"\n position=\"bottom\"\n (ionInfinite)=\"fetchMore($event)\"\n >\n <ion-infinite-scroll-content\n loadingSpinner=\"circles\"\n [loadingText]=\"'COMMON.LOADING_DOTS' | translate\"\n ></ion-infinite-scroll-content>\n </ion-infinite-scroll>\n </div>\n</ion-content>\n\n<ion-footer>\n <!-- Paginator -->\n <mat-paginator\n *ngIf=\"!enableInfiniteScroll\"\n [length]=\"totalRowCount\"\n [pageSize]=\"defaultPageSize\"\n [pageSizeOptions]=\"defaultPageSizeOptions\"\n showFirstLastButtons\n ></mat-paginator>\n\n <app-form-buttons-bar\n *ngIf=\"canEdit && !mobile\"\n (onCancel)=\"load()\"\n (onSave)=\"save()\"\n [disabled]=\"(loadingSubject | async) || !dirty\"\n >\n <!-- error -->\n <ion-item *ngIf=\"error$ | async\" lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" [innerHTML]=\"error | translate\"></ion-label>\n </ion-item>\n </app-form-buttons-bar>\n</ion-footer>\n\n<ion-fab slot=\"fixed\" vertical=\"bottom\" horizontal=\"end\" *ngIf=\"canEdit && mobile\">\n <ion-fab-button color=\"tertiary\" (click)=\"addRow($event)\">\n <ion-icon name=\"add\"></ion-icon>\n </ion-fab-button>\n</ion-fab>\n", styles: [".table-container .mat-mdc-table{--mat-column-actions-min-width: 62px;--mat-column-actions-max-width: 62px}.table-container .mat-mdc-table .mat-row-selected{padding:3px}.table-container .mat-mdc-table .mat-column-select{min-width:30px}.table-container .mat-mdc-table .mat-column-id{min-width:30px;max-width:30px}.table-container .mat-mdc-table .mat-column-label,.table-container .mat-mdc-table .mat-column-name,.table-container .mat-mdc-table .mat-column-levelId,.table-container .mat-mdc-table .mat-column-statusId{min-width:150px}.table-container .mat-mdc-table .mat-column-comments{min-width:100px;max-width:100px}.table-container .mat-mdc-table .mat-column-updateDate{min-width:110px;max-width:110px}\n"] }]
|
|
318
|
+
}], ctorParameters: () => [{ type: i0.Injector }, { type: i1.AppValidatorService }, { type: i2.UntypedFormBuilder }, { type: i0.ChangeDetectorRef }], propDecorators: { filterPanelFloating: [{
|
|
319
|
+
type: Input
|
|
320
|
+
}], enableInfiniteScroll: [{
|
|
321
|
+
type: Input
|
|
322
|
+
}], sticky: [{
|
|
303
323
|
type: Input
|
|
304
|
-
}],
|
|
324
|
+
}], stickyEnd: [{
|
|
305
325
|
type: Input
|
|
306
326
|
}], filterExpansionPanel: [{
|
|
307
327
|
type: ViewChild,
|
|
@@ -310,4 +330,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImpor
|
|
|
310
330
|
type: ViewChild,
|
|
311
331
|
args: [IonInfiniteScroll]
|
|
312
332
|
}] } });
|
|
313
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFibGUudGVzdGluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcHAvY29yZS90YWJsZS90ZXN0aW5nL3RhYmxlLnRlc3RpbmcudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBwL2NvcmUvdGFibGUvdGVzdGluZy90YWJsZS50ZXN0aW5nLmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUVMLHVCQUF1QixFQUV2QixTQUFTLEVBQ1QsVUFBVSxFQUVWLEtBQUssRUFHTCxTQUFTLEdBQ1YsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzFDLE9BQU8sRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxNQUFNLHdDQUF3QyxDQUFDO0FBQzdGLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ25ELE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQzdFLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLHNEQUFzRCxDQUFDO0FBQy9GLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLCtDQUErQyxDQUFDO0FBRXBGLE9BQU8sRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDNUQsT0FBTyxFQUFFLFNBQVMsRUFBRSxtQkFBbUIsRUFBRSxlQUFlLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUN4RixPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpREFBaUQsQ0FBQztBQUNwRixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUMzRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0saUNB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QUFFLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDekIsQ0FBQzt1R0ExUlUsYUFBYTsyRkFBYixhQUFhLDhIQVpiO1lBQ1Q7Z0JBQ0UsT0FBTyxFQUFFLG1CQUFtQjtnQkFDNUIsUUFBUSxFQUFFLHFCQUFxQjthQUNoQztZQUNEO2dCQUNFLE9BQU8sRUFBRSxRQUFRO2dCQUNqQixXQUFXLEVBQUUsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLGFBQWEsQ0FBQzthQUM3QztTQUNGLGdGQTBCVSxpQkFBaUIsK0ZBQ2pCLGlCQUFpQix1RUN0RTlCLG9scEJBdWhCQTs7MkZEemVhLGFBQWE7a0JBaEJ6QixTQUFTOytCQUNFLG1CQUFtQixhQUdsQjt3QkFDVDs0QkFDRSxPQUFPLEVBQUUsbUJBQW1COzRCQUM1QixRQUFRLEVBQUUscUJBQXFCO3lCQUNoQzt3QkFDRDs0QkFDRSxPQUFPLEVBQUUsUUFBUTs0QkFDakIsV0FBVyxFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsY0FBYyxDQUFDO3lCQUM3QztxQkFDRixtQkFDZ0IsdUJBQXVCLENBQUMsTUFBTTtnTEFrQnRDLG9CQUFvQjtzQkFBNUIsS0FBSztnQkFDRyxTQUFTO3NCQUFqQixLQUFLO2dCQU0wQyxvQkFBb0I7c0JBQW5FLFNBQVM7dUJBQUMsaUJBQWlCLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFO2dCQUNoQixjQUFjO3NCQUEzQyxTQUFTO3VCQUFDLGlCQUFpQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEFmdGVyVmlld0luaXQsXG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgQ29tcG9uZW50LFxuICBmb3J3YXJkUmVmLFxuICBJbmplY3RvcixcbiAgSW5wdXQsXG4gIE9uRGVzdHJveSxcbiAgT25Jbml0LFxuICBWaWV3Q2hpbGQsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQXBwVGFibGUgfSBmcm9tICcuLi90YWJsZS5jbGFzcyc7XG5pbXBvcnQgeyBSZWZlcmVudGlhbCwgU3RhdHVzQnlJZCwgU3RhdHVzTGlzdCB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL21vZGVsL3JlZmVyZW50aWFsLm1vZGVsJztcbmltcG9ydCB7IElvbkluZmluaXRlU2Nyb2xsIH0gZnJvbSAnQGlvbmljL2FuZ3VsYXInO1xuaW1wb3J0IHsgRW50aXRpZXNUYWJsZURhdGFTb3VyY2UgfSBmcm9tICcuLi9lbnRpdGllcy10YWJsZS1kYXRhc291cmNlLmNsYXNzJztcbmltcG9ydCB7IEluTWVtb3J5RW50aXRpZXNTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vLi4vc2hhcmVkL3NlcnZpY2VzL21lbW9yeS1lbnRpdHktc2VydmljZS5jbGFzcyc7XG5pbXBvcnQgeyBBcHBWYWxpZGF0b3JTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vc2VydmljZXMvdmFsaWRhdG9yL2Jhc2UudmFsaWRhdG9yLmNsYXNzJztcbmltcG9ydCB7IEFic3RyYWN0Q29udHJvbCwgVW50eXBlZEZvcm1CdWlsZGVyLCBVbnR5cGVkRm9ybUdyb3VwIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgaXNOaWwsIGlzTm90TmlsIH0gZnJvbSAnLi4vLi4vLi4vc2hhcmVkL2Z1bmN0aW9ucyc7XG5pbXBvcnQgeyBEYXRlVXRpbHMsIGZyb21Vbml4TXNUaW1lc3RhbXAsIHRvRGF0ZUlTT1N0cmluZyB9IGZyb20gJy4uLy4uLy4uL3NoYXJlZC9kYXRlcyc7XG5pbXBvcnQgeyBSZWZlcmVudGlhbEZpbHRlciB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL3Rlc3RpbmcvcmVmZXJlbnRpYWwtZmlsdGVyLm1vZGVsJztcbmltcG9ydCB7IGRlYm91bmNlVGltZSwgZmlsdGVyLCB0YXAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBNYXRFeHBhbnNpb25QYW5lbCB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2V4cGFuc2lvbic7XG5pbXBvcnQgeyBTdGF0dXNJZHMgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9tb2RlbC9tb2RlbC5lbnVtJztcbmltcG9ydCB7IFN1YnNjcmlwdGlvbiwgdGltZXIgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IERFRkFVTFRfUEFHRV9TSVpFLCBSRVNFUlZFRF9FTkRfQ09MVU1OUywgUkVTRVJWRURfU1RBUlRfQ09MVU1OUyB9IGZyb20gJy4uL3RhYmxlLm1vZGVsJztcbmltcG9ydCB7IEZvcm1GaWVsZERlZmluaXRpb25NYXAgfSBmcm9tICcuLi8uLi8uLi9zaGFyZWQvZm9ybS9maWVsZC5tb2RlbCc7XG5pbXBvcnQgeyBUYWJsZVZhbGlkYXRvclNlcnZpY2UgfSBmcm9tICcuL3RhYmxlLXZhbGlkYXRvci5zZXJ2aWNlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYXBwLXRhYmxlLXRlc3RpbmcnLFxuICBzdHlsZVVybHM6IFsndGFibGUudGVzdGluZy5zY3NzJ10sXG4gIHRlbXBsYXRlVXJsOiAndGFibGUudGVzdGluZy5odG1sJyxcbiAgcHJvdmlkZXJzOiBbXG4gICAge1xuICAgICAgcHJvdmlkZTogQXBwVmFsaWRhdG9yU2VydmljZSxcbiAgICAgIHVzZUNsYXNzOiBUYWJsZVZhbGlkYXRvclNlcnZpY2UsXG4gICAgfSxcbiAgICB7XG4gICAgICBwcm92aWRlOiBBcHBUYWJsZSxcbiAgICAgIHVzZUV4aXN0aW5nOiBmb3J3YXJkUmVmKCgpID0+IFRhYmxlVGVzdFBhZ2UpLFxuICAgIH0sXG4gIF0sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBUYWJsZVRlc3RQYWdlIGV4dGVuZHMgQXBwVGFibGU8UmVmZXJlbnRpYWwsIFJlZmVyZW50aWFsRmlsdGVyPiBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95LCBBZnRlclZpZXdJbml0IHtcbiAgcmVhZG9ubHkgbWF4Um93Q291bnQgPSAxMDA7XG5cbiAgdGltZXI6IFN1YnNjcmlwdGlvbjtcbiAgY2FuRWRpdCA9IHRydWU7XG4gIGRhdGE6IFJlZmVyZW50aWFsW107XG4gIGZpbHRlckZvcm06IFVudHlwZWRGb3JtR3JvdXA7XG4gIGZpbHRlckNyaXRlcmlhQ291bnQgPSAwO1xuICBncm91cENvbHVtbnMgPSBbJ3RvcC1zdGFydCcsICdncm91cC0xJywgJ2dyb3VwLTInLCAndG9wLWVuZCddO1xuICByb3dIZWlnaHQgPSA0ODtcbiAgcGVybWFuZW50U2VsZWN0aW9uQWxsb3dlZCA9IHRydWU7XG5cbiAgcmVhZG9ubHkgc3RhdHVzTGlzdCA9IFN0YXR1c0xpc3Q7XG4gIHJlYWRvbmx5IHN0YXR1c0J5SWQgPSBTdGF0dXNCeUlkO1xuICByZWFkb25seSBjb2x1bW5EZWZpbml0aW9uczogRm9ybUZpZWxkRGVmaW5pdGlvbk1hcCA9IHt9O1xuXG4gIEBJbnB1dCgpIGVuYWJsZUluZmluaXRlU2Nyb2xsOiBib29sZWFuO1xuICBASW5wdXQoKSB1c2VTdGlja3kgPSB0cnVlO1xuXG4gIGdldCBoYXNNb3JlRGF0YSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5kYXRhLmxlbmd0aCA8IDEwMDtcbiAgfVxuXG4gIEBWaWV3Q2hpbGQoTWF0RXhwYW5zaW9uUGFuZWwsIHsgc3RhdGljOiB0cnVlIH0pIGZpbHRlckV4cGFuc2lvblBhbmVsOiBNYXRFeHBhbnNpb25QYW5lbDtcbiAgQFZpZXdDaGlsZChJb25JbmZpbml0ZVNjcm9sbCkgaW5maW5pdGVTY3JvbGw6IElvbkluZmluaXRlU2Nyb2xsO1xuXG4gIGdldCBkYXRhU2VydmljZSgpOiBJbk1lbW9yeUVudGl0aWVzU2VydmljZTxSZWZlcmVudGlhbD4ge1xuICAgIHJldHVybiB0aGlzLl9kYXRhU291cmNlLmRhdGFTZXJ2aWNlIGFzIEluTWVtb3J5RW50aXRpZXNTZXJ2aWNlPFJlZmVyZW50aWFsPjtcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKFxuICAgIGluamVjdG9yOiBJbmplY3RvcixcbiAgICBwcm90ZWN0ZWQgdmFsaWRhdG9yU2VydmljZTogQXBwVmFsaWRhdG9yU2VydmljZSxcbiAgICBwcm90ZWN0ZWQgZm9ybUJ1aWxkZXI6IFVudHlwZWRGb3JtQnVpbGRlcixcbiAgICBwcm90ZWN0ZWQgY2Q6IENoYW5nZURldGVjdG9yUmVmXG4gICkge1xuICAgIHN1cGVyKFxuICAgICAgaW5qZWN0b3IsXG4gICAgICBbXG4gICAgICAgIC4uLlJFU0VSVkVEX1NUQVJUX0NPTFVNTlMsXG4gICAgICAgICdsYWJlbCcsXG4gICAgICAgICduYW1lJyxcbiAgICAgICAgJ2xldmVsSWQnLFxuICAgICAgICAnc3RhdHVzSWQnLFxuICAgICAgICAnYm9vbGVhbicsXG4gICAgICAgICdkYXRlJyxcbiAgICAgICAgJ2xhdGl0dWRlJyxcbiAgICAgICAgJ3VwZGF0ZURhdGUnLFxuICAgICAgICAnY29tbWVudHMnLFxuICAgICAgICAuLi5SRVNFUlZFRF9FTkRfQ09MVU1OUyxcbiAgICAgIF0sXG4gICAgICBuZXcgRW50aXRpZXNUYWJsZURhdGFTb3VyY2UoXG4gICAgICAgIFJlZmVyZW50aWFsLFxuICAgICAgICBuZXcgSW5NZW1vcnlFbnRpdGllc1NlcnZpY2UoUmVmZXJlbnRpYWwsIFJlZmVyZW50aWFsRmlsdGVyLCB7XG4gICAgICAgICAgc29ydEJ5UmVwbGFjZW1lbnQ6IHsgaWQ6ICdpZCcgfSxcbiAgICAgICAgfSksXG4gICAgICAgIHZhbGlkYXRvclNlcnZpY2UsXG4gICAgICAgIHtcbiAgICAgICAgICBzdXBwcmVzc0Vycm9yczogZmFsc2UsXG4gICAgICAgIH1cbiAgICAgICksXG4gICAgICBudWxsXG4gICAgKTtcblxuICAgIC8vIFdvcmtzIHdpdGggdHJ1ZSBhbmQgZmFsc2VcbiAgICB0aGlzLmVuYWJsZUluZmluaXRlU2Nyb2xsID0gdGhpcy5tb2JpbGU7XG5cbiAgICB0aGlzLmF1dG9Mb2FkID0gZmFsc2U7XG4gICAgdGhpcy5pbmxpbmVFZGl0aW9uID0gdHJ1ZTtcbiAgICB0aGlzLmkxOG5Db2x1bW5QcmVmaXggPSAnVEFCTEUuVEVTVElORy4nO1xuXG4gICAgdGhpcy5jb25maXJtQmVmb3JlRGVsZXRlID0gdHJ1ZTtcbiAgICB0aGlzLmNvbmZpcm1CZWZvcmVDYW5jZWwgPSBmYWxzZTtcbiAgICB0aGlzLnVuZG9hYmxlRGVsZXRpb24gPSBmYWxzZTtcbiAgICB0aGlzLnNhdmVCZWZvcmVEZWxldGUgPSBmYWxzZTtcblxuICAgIHRoaXMuc2F2ZUJlZm9yZVNvcnQgPSB0cnVlO1xuICAgIHRoaXMuc2F2ZUJlZm9yZUZpbHRlciA9IHRydWU7XG4gICAgdGhpcy5wcm9wYWdhdGVSb3dFcnJvciA9IHRydWU7XG5cbiAgICB0aGlzLmZpbHRlckZvcm0gPSBmb3JtQnVpbGRlci5ncm91cCh7XG4gICAgICBzZWFyY2hUZXh0OiBbbnVsbF0sXG4gICAgfSk7XG5cbiAgICAvLyB0aGlzLmNvbHVtbkRlZmluaXRpb25zWyd2YWx1ZXMnXSA9IDxGb3JtRmllbGREZWZpbml0aW9uPntcbiAgICAvLyAgIGtleTogJ3ZhbHVlcycsXG4gICAgLy8gICB0eXBlOiAnZW51bXMnLFxuICAgIC8vICAgdmFsdWVzOiBbXG4gICAgLy8gICAgIHtrZXk6ICdBJywgdmFsdWU6ICdWYWx1ZSBBJ30sXG4gICAgLy8gICAgIHtrZXk6ICdCJywgdmFsdWU6ICdWYWx1ZSBCJ31cbiAgICAvLyAgIF1cbiAgICAvLyB9O1xuXG4gICAgLy8gSW5pdCBuZXcgZW50aXR5XG4gICAgdGhpcy5vblN0YXJ0RWRpdGluZ1Jvdy5zdWJzY3JpYmUoKHJvdykgPT4ge1xuICAgICAgcm93LnZhbGlkYXRvci5wYXRjaFZhbHVlKFxuICAgICAgICB7XG4gICAgICAgICAgZW50aXR5TmFtZTogJ1Rlc3RWTycsXG4gICAgICAgICAgcHJvcGVydGllczoge1xuICAgICAgICAgICAgYm9vbGVhbjogZmFsc2UsXG4gICAgICAgICAgICBkYXRlOiB0b0RhdGVJU09TdHJpbmcoRGF0ZVV0aWxzLm1vbWVudCgpKSxcbiAgICAgICAgICAgIGxhdGl0dWRlOiAxMS4xMTExLFxuICAgICAgICAgICAgLi4ucm93LmN1cnJlbnREYXRhLnByb3BlcnRpZXMsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgeyBlbWl0RXZlbnQ6IGZhbHNlIH1cbiAgICAgICk7XG4gICAgfSk7XG4gIH1cblxuICBuZ09uSW5pdCgpIHtcbiAgICBzdXBlci5uZ09uSW5pdCgpO1xuXG4gICAgLy8gVXBkYXRlIGZpbHRlciB3aGVuIGNoYW5nZXNcbiAgICB0aGlzLnJlZ2lzdGVyU3Vic2NyaXB0aW9uKFxuICAgICAgdGhpcy5maWx0ZXJGb3JtLnZhbHVlQ2hhbmdlc1xuICAgICAgICAucGlwZShcbiAgICAgICAgICBkZWJvdW5jZVRpbWUoMjUwKSxcbiAgICAgICAgICBmaWx0ZXIoKCkgPT4gdGhpcy5maWx0ZXJGb3JtLnZhbGlkKSxcbiAgICAgICAgICB0YXAoKHZhbHVlKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBmaWx0ZXIgPSBSZWZlcmVudGlhbEZpbHRlci5mcm9tT2JqZWN0KHZhbHVlKTtcbiAgICAgICAgICAgIHRoaXMuZmlsdGVyQ3JpdGVyaWFDb3VudCA9IGZpbHRlci5jb3VudE5vdEVtcHR5Q3JpdGVyaWEoKTtcbiAgICAgICAgICAgIHRoaXMubWFya0ZvckNoZWNrKCk7XG4gICAgICAgICAgICAvLyBBcHBseWluZyB0aGUgZmlsdGVyXG4gICAgICAgICAgICB0aGlzLnNldEZpbHRlcihmaWx0ZXIsIHsgZW1pdEV2ZW50OiBmYWxzZSB9KTtcbiAgICAgICAgICB9KSxcbiAgICAgICAgICAvLyBTYXZlIGZpbHRlciBpbiBzZXR0aW5ncyAoYWZ0ZXIgYSBkZWJvdW5jZSB0aW1lKVxuICAgICAgICAgIGRlYm91bmNlVGltZSg1MDApLFxuICAgICAgICAgIHRhcCgoanNvbikgPT4gdGhpcy5zZXR0aW5ncy5zYXZlUGFnZVNldHRpbmcodGhpcy5zZXR0aW5nc0lkLCBqc29uLCAnZmlsdGVyJykpXG4gICAgICAgIClcbiAgICAgICAgLnN1YnNjcmliZSgpXG4gICAgKTtcblxuICAgIHRoaXMucmVnaXN0ZXJBdXRvY29tcGxldGVGaWVsZCgnbGV2ZWwnLCB7XG4gICAgICBpdGVtczogW1xuICAgICAgICB7IGlkOiAxLCBsYWJlbDogJ0EnLCBuYW1lOiAnaXRlbSBBJyB9LFxuICAgICAgICB7IGlkOiAxLCBsYWJlbDogJ0InLCBuYW1lOiAnaXRlbSBCJyB9LFxuICAgICAgXSxcbiAgICAgIG1vYmlsZTogdGhpcy5tb2JpbGUsXG4gICAgfSk7XG5cbiAgICB0aGlzLnJlZ2lzdGVyU3Vic2NyaXB0aW9uKFxuICAgICAgdGhpcy5vblJlZnJlc2guc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgICAgdGhpcy5maWx0ZXJGb3JtLm1hcmtBc1VudG91Y2hlZCgpO1xuICAgICAgICB0aGlzLmZpbHRlckZvcm0ubWFya0FzUHJpc3RpbmUoKTtcbiAgICAgIH0pXG4gICAgKTtcblxuICAgIHRoaXMubWFya0FzUmVhZHkoKTtcbiAgfVxuXG4gIG5nQWZ0ZXJWaWV3SW5pdCgpIHtcbiAgICBzdXBlci5uZ0FmdGVyVmlld0luaXQoKTtcblxuICAgIC8vIFJlc3RvcmUgZmlsdGVyIGZyb20gc2V0dGluZ3NcbiAgICB0aGlzLnJlc3RvcmVGaWx0ZXIoKTtcblxuICAgIC8vIExvYWQgZGF0YVxuICAgIHRoaXMubG9hZCgpO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgY29uc29sZS5kZWJ1ZygnW3Rlc3QtdGFibGVdIERlc3Ryb3lpbmcgdGFibGUuLi4nKTtcbiAgICBzdXBlci5uZ09uRGVzdHJveSgpO1xuICAgIHRoaXMuc3RvcFRpbWVyKCk7XG4gICAgLy90aGlzLmRhdGFTZXJ2aWNlLnN0b3AoKTtcbiAgfVxuXG4gIHByb3RlY3RlZCByZXN0b3JlRmlsdGVyKCkge1xuICAgIGNvbnN0IGpzb24gPSB0aGlzLnNldHRpbmdzLmdldFBhZ2VTZXR0aW5ncyh0aGlzLnNldHRpbmdzSWQsICdmaWx0ZXInKTtcbiAgICBjb25zb2xlLmRlYnVnKCdbdGFibGUtdGVzdF0gUmVzdG9yaW5nIGZpbHRlciBmcm9tIHNldHRpbmdzLi4uJywganNvbik7XG5cbiAgICBpZiAoanNvbikge1xuICAgICAgY29uc3QgZmlsdGVyID0gUmVmZXJlbnRpYWxGaWx0ZXIuZnJvbU9iamVjdChqc29uKTtcbiAgICAgIHRoaXMuZmlsdGVyRm9ybS5wYXRjaFZhbHVlKGpzb24sIHsgZW1pdEV2ZW50OiBmYWxzZSB9KTtcbiAgICAgIHRoaXMuZmlsdGVyQ3JpdGVyaWFDb3VudCA9IGZpbHRlci5jb3VudE5vdEVtcHR5Q3JpdGVyaWEoKTtcbiAgICAgIHRoaXMuc2V0RmlsdGVyKGZpbHRlciwgeyBlbWl0RXZlbnQ6IGZhbHNlIH0pO1xuICAgICAgdGhpcy5tYXJrRm9yQ2hlY2soKTtcbiAgICB9XG4gIH1cblxuICB0b2dnbGVUaW1lcigpIHtcbiAgICBpZiAoaXNOb3ROaWwodGhpcy50aW1lcikpIHRoaXMuc3RvcFRpbWVyKCk7XG4gICAgZWxzZSB0aGlzLnN0YXJ0VGltZXIoKTtcbiAgfVxuXG4gIGxvYWQoKSB7XG4gICAgY29uc29sZS5kZWJ1ZygnW3Rlc3QtdGFibGVdIFVwZGF0aW5nIGRhdGEuLi4nKTtcbiAgICB0aGlzLm1hcmtBc0xvYWRpbmcoKTtcblxuICAgIGlmIChpc05pbCh0aGlzLmRhdGEpKSB7XG4gICAgICB0aGlzLmRhdGEgPSB0aGlzLmdlbmVyYXRlRGF0YSgwLCB0aGlzLm1heFJvd0NvdW50KTtcbiAgICB9XG4gICAgdGhpcy5kYXRhU2VydmljZS52YWx1ZSA9IHRoaXMuZGF0YTtcblxuICAgIHRoaXMub25SZWZyZXNoLmVtaXQoKTtcbiAgfVxuXG4gIGFzeW5jIGZldGNoTW9yZShldmVudCkge1xuICAgIGNvbnNvbGUuZGVidWcoJ1t0YWJsZS10ZXN0XSBMb2FkaW5nIG1vcmUuLi4nLCBldmVudCk7XG4gICAgY29uc3QgZmV0Y2hlZCA9IGF3YWl0IHRoaXMuX2RhdGFTb3VyY2UuZmV0Y2hNb3JlKCk7XG5cbiAgICBpZiAoZmV0Y2hlZCAmJiBldmVudD8udGFyZ2V0ICYmIGV2ZW50LnRhcmdldC5jb21wbGV0ZSkge1xuICAgICAgLy8gV2FpdCBlbmQgb2YgbG9hZFxuICAgICAgYXdhaXQgdGhpcy53YWl0SWRsZSgpO1xuICAgICAgLy8gTWFyayB0YXJnZXQgZXZlbnQgYXMgY29tcGxldGVkIChlLmcuIElvblJlZnJlc2hlcilcbiAgICAgIGV2ZW50LnRhcmdldC5jb21wbGV0ZSgpO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIHNhdmUob3B0cz86IHsga2VlcEVkaXRpbmc/OiBib29sZWFuIH0pOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCBzYXZlZCA9IGF3YWl0IHN1cGVyLnNhdmUob3B0cyk7XG4gICAgaWYgKHNhdmVkKSB7XG4gICAgICAvLyBVcGRhdGUgc291cmNlIGRhdGFcbiAgICAgIHRoaXMuZGF0YSA9IHRoaXMuZGF0YVNlcnZpY2UudmFsdWU7XG4gICAgfVxuICAgIHJldHVybiBzYXZlZDtcbiAgfVxuXG4gIGNsZWFyQ29udHJvbFZhbHVlKGV2ZW50OiBFdmVudCwgZm9ybUNvbnRyb2w6IEFic3RyYWN0Q29udHJvbCk6IGJvb2xlYW4ge1xuICAgIGlmIChldmVudCkgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7IC8vIEF2b2lkIHRvIGVudGVyIGlucHV0IHRoZSBmaWVsZFxuICAgIGZvcm1Db250cm9sLnNldFZhbHVlKG51bGwpO1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIGFwcGx5RmlsdGVyQW5kQ2xvc2VQYW5lbChldmVudD86IEV2ZW50KSB7XG4gICAgdGhpcy5kZWZhdWx0UGFnZVNpemUgPSBERUZBVUxUX1BBR0VfU0laRTtcbiAgICB0aGlzLm9uUmVmcmVzaC5lbWl0KGV2ZW50KTtcbiAgICB0aGlzLmZpbHRlckV4cGFuc2lvblBhbmVsLmNsb3NlKCk7XG4gIH1cblxuICByZXNldEZpbHRlcihfPzogRXZlbnQpIHtcbiAgICB0aGlzLmZpbHRlckZvcm0ucmVzZXQoe30sIHsgZW1pdEV2ZW50OiB0cnVlIH0pO1xuICAgIHRoaXMuc2V0RmlsdGVyKFJlZmVyZW50aWFsRmlsdGVyLmZyb21PYmplY3Qoe30pLCB7IGVtaXRFdmVudDogdHJ1ZSB9KTtcbiAgICB0aGlzLmZpbHRlckV4cGFuc2lvblBhbmVsLmNsb3NlKCk7XG4gIH1cblxuICBzdGFydFRpbWVyKCkge1xuICAgIHRoaXMuc3RvcFRpbWVyKCk7XG4gICAgdGhpcy50aW1lciA9IHRpbWVyKDUwMCkuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgIHRoaXMuZGF0YSA9IG51bGw7IC8vIFJlc2V0XG4gICAgICB0aGlzLmxvYWQoKTtcbiAgICB9KTtcbiAgfVxuXG4gIHN0b3BUaW1lcigpIHtcbiAgICB0aGlzLnRpbWVyPy51bnN1YnNjcmliZSgpO1xuICAgIHRoaXMudGltZXIgPSBudWxsO1xuICB9XG5cbiAgcHJvdGVjdGVkIGdlbmVyYXRlRGF0YShvZmZzZXQ/OiBudW1iZXIsIHNpemU/OiBudW1iZXIpOiBSZWZlcmVudGlhbFtdIHtcbiAgICBvZmZzZXQgPSBvZmZzZXQgfHwgMDtcbiAgICBzaXplID0gc2l6ZSB8fCAxMDA7XG5cbiAgICBjb25zdCByZXN1bHQgPSBuZXcgQXJyYXk8UmVmZXJlbnRpYWw+KCk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzaXplOyBpKyspIHtcbiAgICAgIGNvbnN0IGlkID0gaSArIDEgKyBvZmZzZXQ7XG4gICAgICBjb25zdCBpdGVtID0gUmVmZXJlbnRpYWwuZnJvbU9iamVjdCh7XG4gICAgICAgIGlkLFxuICAgICAgICBsYWJlbDogJ0NPREUtJyArIGlkLFxuICAgICAgICBuYW1lOiAnTmFtZSAjJyArIGlkLFxuICAgICAgICBsZXZlbElkOiB7IGlkOiAxLCBsYWJlbDogJ0EnLCBuYW1lOiAnSXRlbSBBJyB9LFxuICAgICAgICBzdGF0dXNJZDogU3RhdHVzSWRzLkVOQUJMRSxcbiAgICAgICAgY29tbWVudHM6IGkgJSAzID09PSAwID8gJ015IGNvbW1lbnQgIycgKyBpZCA6IHVuZGVmaW5lZCxcbiAgICAgICAgcHJvcGVydGllczoge1xuICAgICAgICAgIHZhbHVlczogaSAlIDIgPT09IDAgPyAnQScgOiAnQSxCJyxcbiAgICAgICAgICBib29sZWFuOiBmYWxzZSxcbiAgICAgICAgICBkYXRlOiBudWxsLCAvLyB0b0RhdGVJU09TdHJpbmcoRGF0ZVV0aWxzLm1vbWVudCgpKSxcbiAgICAgICAgICBsYXRpdHVkZTogbnVsbCwgLy8gMTEuMTExMVxuICAgICAgICB9LFxuICAgICAgICBjcmVhdGlvbkRhdGU6IGZyb21Vbml4TXNUaW1lc3RhbXAoRGF0ZS5ub3coKSAtIGkgKiA2MCAqIDEwMDApLFxuICAgICAgICB1cGRhdGVEYXRlOiBmcm9tVW5peE1zVGltZXN0YW1wKERhdGUubm93KCkgLSBpICogNjAgKiAxMDAwKSxcbiAgICAgICAgZW50aXR5TmFtZTogJ1Rlc3RWTycsXG4gICAgICB9KTtcbiAgICAgIHJlc3VsdC5wdXNoKGl0ZW0pO1xuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICBwcm90ZWN0ZWQgbWFya0ZvckNoZWNrKCkge1xuICAgIHRoaXMuY2QubWFya0ZvckNoZWNrKCk7XG4gIH1cbn1cbiIsIjxhcHAtdG9vbGJhclxuICBjb2xvcj1cInByaW1hcnlcIlxuICBbY2FuR29CYWNrXT1cInRydWVcIlxuICBbaGFzVmFsaWRhdGVdPVwiKGxvYWRpbmdTdWJqZWN0IHwgYXN5bmMpICE9PSB0cnVlICYmIChkaXJ0eVN1YmplY3QgfCBhc3luYykgPT09IHRydWVcIlxuICAob25WYWxpZGF0ZSk9XCJzYXZlKClcIlxuICBbYmFja0hyZWZdPVwiJy90ZXN0aW5nJ1wiXG4+XG4gIDxpb24tdGl0bGU+VGFibGUgKGNsaWNrIHRvIGVkaXQpPC9pb24tdGl0bGU+XG4gIDxpb24tYnV0dG9ucyBzbG90PVwiZW5kXCI+XG4gICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIiFzZWxlY3Rpb24uaGFzVmFsdWUoKTsgZWxzZSBoYXNTZWxlY3Rpb25cIj5cbiAgICAgIDxpbnB1dCBtYXRJbnB1dCB0eXBlPVwibnVtYmVyXCIgc3RlcD1cIjFcIiBzdHlsZT1cImNvbG9yOiBibGFjazsgd2lkdGg6IDUwcHhcIiBbKG5nTW9kZWwpXT1cInJvd0hlaWdodFwiIC8+XG5cbiAgICAgIDwhLS0gQWRkIC0tPlxuICAgICAgPGJ1dHRvbiBtYXQtaWNvbi1idXR0b24gKm5nSWY9XCJjYW5FZGl0ICYmICFtb2JpbGVcIiBbdGl0bGVdPVwiJ0NPTU1PTi5CVE5fQUREJyB8IHRyYW5zbGF0ZVwiIChjbGljayk9XCJhZGRSb3coKVwiPlxuICAgICAgICA8bWF0LWljb24+YWRkPC9tYXQtaWNvbj5cbiAgICAgIDwvYnV0dG9uPlxuXG4gICAgICA8IS0tIHJlc2V0IGZpbHRlciAtLT5cbiAgICAgIDxidXR0b24gbWF0LWljb24tYnV0dG9uIChjbGljayk9XCJyZXNldEZpbHRlcigpXCIgKm5nSWY9XCJmaWx0ZXJDcml0ZXJpYUNvdW50XCI+XG4gICAgICAgIDxtYXQtaWNvbiBjb2xvcj1cImFjY2VudFwiPmZpbHRlcl9saXN0X2FsdDwvbWF0LWljb24+XG4gICAgICAgIDxtYXQtaWNvbiBjbGFzcz1cImljb24tc2Vjb25kYXJ5XCIgc3R5bGU9XCJsZWZ0OiAxNnB4OyB0b3A6IDVweDsgZm9udC13ZWlnaHQ6IGJvbGRcIj5jbG9zZTwvbWF0LWljb24+XG4gICAgICA8L2J1dHRvbj5cblxuICAgICAgPCEtLSBzaG93IGZpbHRlciAtLT5cbiAgICAgIDxidXR0b24gbWF0LWljb24tYnV0dG9uIChjbGljayk9XCJmaWx0ZXJFeHBhbnNpb25QYW5lbC50b2dnbGUoKVwiPlxuICAgICAgICA8bWF0LWljb25cbiAgICAgICAgICAqbmdJZj1cImZpbHRlckNyaXRlcmlhQ291bnQ7IGVsc2UgZW1wdHlGaWx0ZXJcIlxuICAgICAgICAgIFttYXRCYWRnZV09XCJmaWx0ZXJDcml0ZXJpYUNvdW50XCJcbiAgICAgICAgICBtYXRCYWRnZUNvbG9yPVwiYWNjZW50XCJcbiAgICAgICAgICBtYXRCYWRnZVNpemU9XCJzbWFsbFwiXG4gICAgICAgICAgbWF0QmFkZ2VQb3NpdGlvbj1cImFib3ZlIGFmdGVyXCJcbiAgICAgICAgICBhcmlhLWhpZGRlbj1cImZhbHNlXCJcbiAgICAgICAgPlxuICAgICAgICAgIGZpbHRlcl9saXN0X2FsdFxuICAgICAgICA8L21hdC1pY29uPlxuICAgICAgICA8bmctdGVtcGxhdGUgI2VtcHR5RmlsdGVyPlxuICAgICAgICAgIDxtYXQtaWNvbj5maWx0ZXJfbGlzdF9hbHQ8L21hdC1pY29uPlxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgPC9idXR0b24+XG5cbiAgICAgIDwhLS0gc2F2ZSAtLT5cbiAgICAgIDxidXR0b24gbWF0LWljb24tYnV0dG9uICpuZ0lmPVwibW9iaWxlXCIgW2Rpc2FibGVkXT1cIihkaXJ0eVN1YmplY3QgfCBhc3luYykgIT09IHRydWVcIiAoY2xpY2spPVwic2F2ZSgpXCI+XG4gICAgICAgIDxtYXQtaWNvbj5zYXZlPC9tYXQtaWNvbj5cbiAgICAgIDwvYnV0dG9uPlxuXG4gICAgICA8IS0tIHN0YXJ0L3N0b3AgdGltZXIgdG8gYXV0by1sb2FkIGRhdGEgLS0+XG4gICAgICA8aW9uLWJ1dHRvbiAqbmdJZj1cIiF0aW1lclwiIChjbGljayk9XCJzdGFydFRpbWVyKClcIj5TdGFydCByZWxvYWQ8L2lvbi1idXR0b24+XG4gICAgICA8aW9uLWJ1dHRvbiAqbmdJZj1cInRpbWVyXCIgKGNsaWNrKT1cInN0b3BUaW1lcigpXCIgY29sb3I9XCJhY2NlbnRcIj5TdG9wIHJlbG9hZDwvaW9uLWJ1dHRvbj5cbiAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgIDwhLS0gaWYgcm93IHNlbGVjdGlvbiAtLT5cbiAgICA8bmctdGVtcGxhdGUgI2hhc1NlbGVjdGlvbj5cbiAgICAgIDwhLS0gZGVsZXRlIC0tPlxuICAgICAgPGJ1dHRvblxuICAgICAgICBtYXQtaWNvbi1idXR0b25cbiAgICAgICAgKm5nSWY9XCJjYW5FZGl0XCJcbiAgICAgICAgW3RpdGxlXT1cIidDT01NT04uQlROX0RFTEVURScgfCB0cmFuc2xhdGVcIlxuICAgICAgICAoY2xpY2spPVwiZGVsZXRlU2VsZWN0aW9uKCRldmVudClcIlxuICAgICAgPlxuICAgICAgICA8bWF0LWljb24+ZGVsZXRlPC9tYXQtaWNvbj5cbiAgICAgIDwvYnV0dG9uPlxuXG4gICAgICA8IS0tIGR1cGxpY2F0ZSAtLT5cbiAgICAgIDxidXR0b25cbiAgICAgICAgbWF0LWljb24tYnV0dG9uXG4gICAgICAgICpuZ0lmPVwiY2FuRWRpdCAmJiBzZWxlY3Rpb24uc2VsZWN0ZWQgfCBpc0FycmF5TGVuZ3RoOiB7IGVxdWFsczogMSB9XCJcbiAgICAgICAgW3RpdGxlXT1cIidDT01NT04uQlROX0RVUExJQ0FURScgfCB0cmFuc2xhdGVcIlxuICAgICAgICAoY2xpY2spPVwiZHVwbGljYXRlUm93KCRldmVudCwgc2VsZWN0aW9uLnNlbGVjdGVkWzBdKVwiXG4gICAgICA+XG4gICAgICAgIDxtYXQtaWNvbj5maWxlX2NvcHk8L21hdC1pY29uPlxuICAgICAgPC9idXR0b24+XG4gICAgPC9uZy10ZW1wbGF0ZT5cbiAgPC9pb24tYnV0dG9ucz5cbjwvYXBwLXRvb2xiYXI+XG48aW9uLWNvbnRlbnQgY2xhc3M9XCJpb24tbm8tcGFkZGluZ1wiPlxuICA8aW9uLXJlZnJlc2hlciBzbG90PVwiZml4ZWRcIiAqbmdJZj1cIm1vYmlsZVwiIChpb25SZWZyZXNoKT1cImRvUmVmcmVzaCgkZXZlbnQpXCI+XG4gICAgPGlvbi1yZWZyZXNoZXItY29udGVudD48L2lvbi1yZWZyZXNoZXItY29udGVudD5cbiAgPC9pb24tcmVmcmVzaGVyPlxuXG4gIDwhLS0gZXJyb3IgLS0+XG4gIDxpb24taXRlbSAqbmdJZj1cIm1vYmlsZSAmJiBlcnJvclwiIGxpbmVzPVwibm9uZVwiIEBzbGlkZVVwRG93bkFuaW1hdGlvbj5cbiAgICA8aW9uLWljb24gY29sb3I9XCJkYW5nZXJcIiBzbG90PVwic3RhcnRcIiBuYW1lPVwiYWxlcnQtY2lyY2xlXCI+PC9pb24taWNvbj5cbiAgICA8aW9uLWxhYmVsIGNvbG9yPVwiZGFuZ2VyXCIgY2xhc3M9XCJlcnJvclwiIFtpbm5lckhUTUxdPVwiZXJyb3IgfCB0cmFuc2xhdGVcIj48L2lvbi1sYWJlbD5cbiAgPC9pb24taXRlbT5cblxuICA8IS0tIHNlYXJjaCAtLT5cbiAgPG1hdC1leHBhbnNpb24tcGFuZWwgI2ZpbHRlckV4cGFuc2lvblBhbmVsIGNsYXNzPVwiZmlsdGVyLXBhbmVsIGZpbHRlci1wYW5lbC1mbG9hdGluZ1wiPlxuICAgIDxmb3JtIGNsYXNzPVwiZm9ybS1jb250YWluZXIgaW9uLXBhZGRpbmctdG9wXCIgW2Zvcm1Hcm91cF09XCJmaWx0ZXJGb3JtXCIgKG5nU3VibWl0KT1cImFwcGx5RmlsdGVyQW5kQ2xvc2VQYW5lbCgkZXZlbnQpXCI+XG4gICAgICA8aW9uLWdyaWQ+XG4gICAgICAgIDxpb24tcm93PlxuICAgICAgICAgIDxpb24tY29sPlxuICAgICAgICAgICAgPCEtLSBzZWFyY2ggdGV4dCAtLT5cbiAgICAgICAgICAgIDxtYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICAgICAgPG1hdC1sYWJlbD57eyAnVEFCTEUuVEVTVElORy5TRUFSQ0hfVEVYVCcgfCB0cmFuc2xhdGUgfX08L21hdC1sYWJlbD5cbiAgICAgICAgICAgICAgPGlvbi1pY29uIG1hdFByZWZpeCBuYW1lPVwic2VhcmNoXCI+PC9pb24taWNvbj5cbiAgICAgICAgICAgICAgPGlucHV0IG1hdElucHV0IGZvcm1Db250cm9sTmFtZT1cInNlYXJjaFRleHRcIiBhdXRvY29tcGxldGU9XCJvZmZcIiAvPlxuICAgICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgICAgbWF0LWljb24tYnV0dG9uXG4gICAgICAgICAgICAgICAgbWF0U3VmZml4XG4gICAgICAgICAgICAgICAgdGFiaW5kZXg9XCItMVwiXG4gICAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cImNsZWFyQ29udHJvbFZhbHVlKCRldmVudCwgZmlsdGVyRm9ybS5jb250cm9scy5zZWFyY2hUZXh0KVwiXG4gICAgICAgICAgICAgICAgW2hpZGRlbl09XCJmaWx0ZXJGb3JtLmNvbnRyb2xzLnNlYXJjaFRleHQuZGlzYWJsZWQgfHwgIWZpbHRlckZvcm0uY29udHJvbHMuc2VhcmNoVGV4dC52YWx1ZVwiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8bWF0LWljb24+Y2xvc2U8L21hdC1pY29uPlxuICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgICAgICAgPC9pb24tY29sPlxuICAgICAgICA8L2lvbi1yb3c+XG4gICAgICA8L2lvbi1ncmlkPlxuICAgIDwvZm9ybT5cblxuICAgIDxtYXQtYWN0aW9uLXJvdz5cbiAgICAgIDwhLS0gQ291bnRlciAgLS0+XG4gICAgICA8aW9uLWxhYmVsXG4gICAgICAgIFtoaWRkZW5dPVwiKGxvYWRpbmdTdWJqZWN0IHwgYXN5bmMpIHx8IGZpbHRlckZvcm0uZGlydHlcIlxuICAgICAgICBbY29sb3JdPVwiZW1wdHkgJiYgJ2RhbmdlcidcIlxuICAgICAgICBjbGFzcz1cImlvbi1wYWRkaW5nXCJcbiAgICAgID5cbiAgICAgICAge3tcbiAgICAgICAgICAodG90YWxSb3dDb3VudCA/ICdDT01NT04uUkVTVUxUX0NPVU5UJyA6ICdDT01NT04uTk9fUkVTVUxUJylcbiAgICAgICAgICAgIHwgdHJhbnNsYXRlXG4gICAgICAgICAgICAgIDoge1xuICAgICAgICAgICAgICAgICAgY291bnQ6ICh0b3RhbFJvd0NvdW50IHwgbnVtYmVyRm9ybWF0KVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgfX1cbiAgICAgIDwvaW9uLWxhYmVsPlxuXG4gICAgICA8ZGl2IGNsYXNzPVwidG9vbGJhci1zcGFjZXJcIj48L2Rpdj5cblxuICAgICAgPCEtLSBDbG9zZSBwYW5lbCAtLT5cbiAgICAgIDxpb24tYnV0dG9uXG4gICAgICAgIG1hdC1idXR0b25cbiAgICAgICAgZmlsbD1cImNsZWFyXCJcbiAgICAgICAgY29sb3I9XCJkYXJrXCJcbiAgICAgICAgKGNsaWNrKT1cImZpbHRlckV4cGFuc2lvblBhbmVsLmNsb3NlKClcIlxuICAgICAgICBbZGlzYWJsZWRdPVwibG9hZGluZ1N1YmplY3QgfCBhc3luY1wiXG4gICAgICA+XG4gICAgICAgIDxpb24tdGV4dCB0cmFuc2xhdGU+Q09NTU9OLkJUTl9DTE9TRTwvaW9uLXRleHQ+XG4gICAgICA8L2lvbi1idXR0b24+XG5cbiAgICAgIDwhLS0gU2VhcmNoIGJ1dHRvbiAtLT5cbiAgICAgIDxpb24tYnV0dG9uXG4gICAgICAgIG1hdC1idXR0b25cbiAgICAgICAgW2NvbG9yXT1cImZpbHRlckZvcm0uZGlydHkgPyAndGVydGlhcnknIDogJ2RhcmsnXCJcbiAgICAgICAgW2ZpbGxdPVwiZmlsdGVyRm9ybS5kaXJ0eSA/ICdzb2xpZCcgOiAnY2xlYXInXCJcbiAgICAgICAgKGNsaWNrKT1cImFwcGx5RmlsdGVyQW5kQ2xvc2VQYW5lbCgkZXZlbnQpXCJcbiAgICAgID5cbiAgICAgICAgPGlvbi10ZXh0IHRyYW5zbGF0ZT5DT01NT04uQlROX0FQUExZPC9pb24tdGV4dD5cbiAgICAgIDwvaW9uLWJ1dHRvbj5cbiAgICA8L21hdC1hY3Rpb24tcm93PlxuICA8L21hdC1leHBhbnNpb24tcGFuZWw+XG5cbiAgPCEtLSB0YWJsZSAtLT5cbiAgPGRpdiBbY2xhc3MudGFibGUtY29udGFpbmVyXT1cIiFlbmFibGVJbmZpbml0ZVNjcm9sbFwiPlxuICAgIDx0YWJsZVxuICAgICAgI3RhYmxlXG4gICAgICBtYXQtdGFibGVcbiAgICAgIG1hdFNvcnRcbiAgICAgIG1hdFNvcnREaXNhYmxlQ2xlYXJcbiAgICAgIFtkYXRhU291cmNlXT1cImRhdGFTb3VyY2VcIlxuICAgICAgW21hdFNvcnRBY3RpdmVdPVwiZGVmYXVsdFNvcnRCeVwiXG4gICAgICBbbWF0U29ydERpcmVjdGlvbl09XCJkZWZhdWx0U29ydERpcmVjdGlvblwiXG4gICAgICBbdHJhY2tCeV09XCJ0cmFja0J5Rm5cIlxuICAgICAgW3N0eWxlLi0tbWF0LXJvdy1oZWlnaHRdPVwicm93SGVpZ2h0ICsgJ3B4J1wiXG4gICAgPlxuICAgICAgPlxuXG4gICAgICA8IS0tIGdyb3VwIGhlYWRlciBjZWxscyAtLT5cblxuICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJ0b3Atc3RhcnRcIiBbc3RpY2t5XT1cInVzZVN0aWNreVwiPlxuICAgICAgICA8dGggbWF0LWhlYWRlci1jZWxsICptYXRIZWFkZXJDZWxsRGVmIFtjbGFzcy5jZGstdmlzdWFsbHktaGlkZGVuXT1cIiFjYW5FZGl0XCIgW2F0dHIuY29sc3Bhbl09XCIyXCI+XG4gICAgICAgICAgPCEtLSBzdGFydCBzcGFjZXIgLS0+XG4gICAgICAgIDwvdGg+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJncm91cC0xXCI+XG4gICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgKm1hdEhlYWRlckNlbGxEZWYgW2F0dHIuY29sc3Bhbl09XCIzXCI+XG4gICAgICAgICAgPGlvbi1sYWJlbCB0cmFuc2xhdGU+e3sgaTE4bkNvbHVtblByZWZpeCArICdHUk9VUF8xJyB9fTwvaW9uLWxhYmVsPlxuICAgICAgICA8L3RoPlxuICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgIDxuZy1jb250YWluZXIgbWF0Q29sdW1uRGVmPVwiZ3JvdXAtMlwiPlxuICAgICAgICA8dGggbWF0LWhlYWRlci1jZWxsICptYXRIZWFkZXJDZWxsRGVmIFthdHRyLmNvbHNwYW5dPVwiM1wiPlxuICAgICAgICAgIDxpb24tbGFiZWwgdHJhbnNsYXRlPnt7IGkxOG5Db2x1bW5QcmVmaXggKyAnR1JPVVBfMicgfX08L2lvbi1sYWJlbD5cbiAgICAgICAgPC90aD5cbiAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICA8bmctY29udGFpbmVyIG1hdENvbHVtbkRlZj1cInRvcC1lbmRcIj5cbiAgICAgICAgPHRoIG1hdC1oZWFkZXItY2VsbCAqbWF0SGVhZGVyQ2VsbERlZiBbYXR0ci5jb2xzcGFuXT1cIjJcIj5cbiAgICAgICAgICA8IS0tIGVuZCBzcGFjZXIgLS0+XG4gICAgICAgIDwvdGg+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJzZWxlY3RcIiBbc3RpY2t5XT1cInVzZVN0aWNreVwiIFtjbGFzcy5tYXQtY29sdW1uLXN0aWNreV09XCJ1c2VTdGlja3lcIj5cbiAgICAgICAgPHRoIG1hdC1oZWFkZXItY2VsbCAqbWF0SGVhZGVyQ2VsbERlZiBbY2xhc3MuY2RrLXZpc3VhbGx5LWhpZGRlbl09XCIhY2FuRWRpdFwiPlxuICAgICAgICAgIDxtYXQtY2hlY2tib3hcbiAgICAgICAgICAgIChjaGFuZ2UpPVwiJGV2ZW50ID8gbWFzdGVyVG9nZ2xlKCkgOiBudWxsXCJcbiAgICAgICAgICAgIFtjaGVja2VkXT1cInNlbGVjdGlvbi5oYXNWYWx1ZSgpICYmIGlzQWxsU2VsZWN0ZWQoKVwiXG4gICAgICAgICAgICBbaW5kZXRlcm1pbmF0ZV09XCJzZWxlY3Rpb24uaGFzVmFsdWUoKSAmJiAhaXNBbGxTZWxlY3RlZCgpXCJcbiAgICAgICAgICA+PC9tYXQtY2hlY2tib3g+XG4gICAgICAgIDwvdGg+XG4gICAgICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCByb3dcIiBbY2xhc3MuY2RrLXZpc3VhbGx5LWhpZGRlbl09XCIhY2FuRWRpdFwiPlxuICAgICAgICAgIDxtYXQtY2hlY2tib3ggKGNsaWNrKT1cInRvZ2dsZVNlbGVjdFJvdygkZXZlbnQsIHJvdylcIiBbY2hlY2tlZF09XCJzZWxlY3Rpb24uaXNTZWxlY3RlZChyb3cpXCI+PC9tYXQtY2hlY2tib3g+XG4gICAgICAgIDwvdGQ+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgPCEtLSBJZCBjb2x1bW4gLS0+XG4gICAgICA8bmctY29udGFpbmVyIG1hdENvbHVtbkRlZj1cImlkXCIgW3N0aWNreV09XCJ1c2VTdGlja3lcIiBbY2xhc3MubWF0LWNvbHVtbi1zdGlja3ldPVwidXNlU3RpY2t5XCI+XG4gICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgKm1hdEhlYWRlckNlbGxEZWYgbWF0LXNvcnQtaGVhZGVyPlxuICAgICAgICAgIDxpb24tbGFiZWw+IzwvaW9uLWxhYmVsPlxuICAgICAgICA8L3RoPlxuICAgICAgICA8dGQgbWF0LWNlbGwgKm1hdENlbGxEZWY9XCJsZXQgcm93XCI+e3sgcm93LmN1cnJlbnREYXRhPy5pZCB9fTwvdGQ+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgPCEtLSBMYWJlbCBjb2x1bW4gLS0+XG4gICAgICA8bmctY29udGFpbmVyIG1hdENvbHVtbkRlZj1cImxhYmVsXCI+XG4gICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgKm1hdEhlYWRlckNlbGxEZWYgbWF0LXNvcnQtaGVhZGVyPlxuICAgICAgICAgIDxpb24tbGFiZWwgdHJhbnNsYXRlPlRBQkxFLlRFU1RJTkcuTEFCRUw8L2lvbi1sYWJlbD5cbiAgICAgICAgPC90aD5cbiAgICAgICAgPHRkIG1hdC1jZWxsICptYXRDZWxsRGVmPVwibGV0IHJvd1wiIChjbGljayk9XCJmb2N1c0NvbHVtbiA9ICdsYWJlbCdcIj5cbiAgICAgICAgICA8bWF0LWZvcm0tZmllbGQgKm5nSWY9XCJyb3cuZWRpdGluZzsgZWxzZSByZWFkb25seUNlbGxcIiBbaGlkZVJlcXVpcmVkTWFya2VyXT1cImZhbHNlXCI+XG4gICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgbWF0SW5wdXRcbiAgICAgICAgICAgICAgYXV0b2NvbXBsZXRlPVwib2ZmXCJcbiAgICAgICAgICAgICAgW2Zvcm1Db250cm9sXT1cInJvdy52YWxpZGF0b3IuY29udHJvbHNbJ2xhYmVsJ11cIlxuICAgICAgICAgICAgICBbcGxhY2Vob2xkZXJdPVwiJ1RBQkxFLlRFU1RJTkcuTEFCRUwnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAgICAgW2FwcEF1dG9mb2N1c109XCJyb3cuZWRpdGluZyAmJiBmb2N1c0NvbHVtbiA9PT0gJ2xhYmVsJ1wiXG4gICAgICAgICAgICAgIFtyZWFkb25seV09XCIhcm93LmVkaXRpbmdcIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIDxtYXQtZXJyb3IgKm5nSWY9XCJyb3cudmFsaWRhdG9yLmNvbnRyb2xzWydsYWJlbCddLmhhc0Vycm9yKCdyZXF1aXJlZCcpXCIgdHJhbnNsYXRlPlxuICAgICAgICAgICAgICBFUlJPUi5GSUVMRF9SRVFVSVJFRFxuICAgICAgICAgICAgPC9tYXQtZXJyb3I+XG4gICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgI3JlYWRvbmx5Q2VsbD5cbiAgICAgICAgICAgIDxpb24tbGFiZWwgYXBwQXV0b1RpdGxlPlxuICAgICAgICAgICAgICB7eyByb3cudmFsaWRhdG9yIHwgZm9ybUdldFZhbHVlOiAnbGFiZWwnIH19XG4gICAgICAgICAgICA8L2lvbi1sYWJlbD5cbiAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICA8L3RkPlxuICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgIDwhLS0gTmFtZSBjb2x1bW4gLS0+XG4gICAgICA8bmctY29udGFpbmVyIG1hdENvbHVtbkRlZj1cIm5hbWVcIj5cbiAgICAgICAgPHRoIG1hdC1oZWFkZXItY2VsbCAqbWF0SGVhZGVyQ2VsbERlZiBtYXQtc29ydC1oZWFkZXI+XG4gICAgICAgICAgPGlvbi1sYWJlbCB0cmFuc2xhdGU+VEFCTEUuVEVTVElORy5OQU1FPC9pb24tbGFiZWw+XG4gICAgICAgIDwvdGg+XG4gICAgICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCByb3dcIiAoY2xpY2spPVwiZm9jdXNDb2x1bW4gPSAnbmFtZSdcIj5cbiAgICAgICAgICA8bWF0LWZvcm0tZmllbGQgKm5nSWY9XCJyb3cuZWRpdGluZzsgZWxzZSByZWFkb25seUNlbGxcIj5cbiAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICBtYXRJbnB1dFxuICAgICAgICAgICAgICBbZm9ybUNvbnRyb2xdPVwicm93LnZhbGlkYXRvcj8uY29udHJvbHMubmFtZVwiXG4gICAgICAgICAgICAgIFtwbGFjZWhvbGRlcl09XCInVEFCTEUuVEVTVElORy5OQU1FJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICAgIFthcHBBdXRvZm9jdXNdPVwicm93LmVkaXRpbmcgJiYgZm9jdXNDb2x1bW4gPT09ICduYW1lJ1wiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgICAgPG1hdC1lcnJvciAqbmdJZj1cInJvdy52YWxpZGF0b3I/LmNvbnRyb2xzLm5hbWUuaGFzRXJyb3IoJ3JlcXVpcmVkJylcIiB0cmFuc2xhdGU+XG4gICAgICAgICAgICAgIEVSUk9SLkZJRUxEX1JFUVVJUkVEXG4gICAgICAgICAgICA8L21hdC1lcnJvcj5cbiAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgICAgICAgIDxuZy10ZW1wbGF0ZSAjcmVhZG9ubHlDZWxsPlxuICAgICAgICAgICAgPGlvbi1sYWJlbCBhcHBBdXRvVGl0bGU+XG4gICAgICAgICAgICAgIHt7IHJvdy52YWxpZGF0b3IgfCBmb3JtR2V0VmFsdWU6ICduYW1lJyB9fVxuICAgICAgICAgICAgPC9pb24tbGFiZWw+XG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgPC90ZD5cbiAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICA8IS0tIExldmVsIGNvbHVtbiAtLT5cbiAgICAgIDxuZy1jb250YWluZXIgbWF0Q29sdW1uRGVmPVwibGV2ZWxJZFwiPlxuICAgICAgICA8dGggbWF0LWhlYWRlci1jZWxsICptYXRIZWFkZXJDZWxsRGVmIG1hdC1zb3J0LWhlYWRlcj5cbiAgICAgICAgICA8aW9uLWxhYmVsIHRyYW5zbGF0ZT5UQUJMRS5URVNUSU5HLkxFVkVMX0lEPC9pb24tbGFiZWw+XG4gICAgICAgIDwvdGg+XG4gICAgICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCByb3dcIiAoY2xpY2spPVwiZm9jdXNDb2x1bW4gPSAnbGV2ZWxJZCdcIj5cbiAgICAgICAgICA8bWF0LWF1dG9jb21wbGV0ZS1maWVsZFxuICAgICAgICAgICAgKm5nSWY9XCJyb3cuZWRpdGluZzsgZWxzZSByZWFkb25seUNlbGxcIlxuICAgICAgICAgICAgW2Zvcm1Db250cm9sXT1cInJvdy52YWxpZGF0b3IuY29udHJvbHMubGV2ZWxJZFwiXG4gICAgICAgICAgICBbcGxhY2Vob2xkZXJdPVwiJ1RBQkxFLlRFU1RJTkcuTEVWRUxfSUQnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAgIGZsb2F0TGFiZWw9XCJuZXZlclwiXG4gICAgICAgICAgICBbY29uZmlnXT1cImF1dG9jb21wbGV0ZUZpZWxkcy5sZXZlbFwiXG4gICAgICAgICAgICBbcmVhZG9ubHldPVwiIXJvdy5lZGl0aW5nXCJcbiAgICAgICAgICAgIFthdXRvZm9jdXNdPVwiZm9jdXNDb2x1bW4gPT09ICdsZXZlbElkJ1wiXG4gICAgICAgICAgICBbcmVxdWlyZWRdPVwidHJ1ZVwiXG4gICAgICAgICAgPjwvbWF0LWF1dG9jb21wbGV0ZS1maWVsZD5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgI3JlYWRvbmx5Q2VsbD5cbiAgICAgICAgICAgIDxpb24tbGFiZWwgYXBwQXV0b1RpdGxlPlxuICAgICAgICAgICAgICB7eyByb3cudmFsaWRhdG9yIHwgZm9ybUdldFZhbHVlOiAnbGV2ZWxJZCcgfCByZWZlcmVudGlhbFRvU3RyaW5nOiBhdXRvY29tcGxldGVGaWVsZHMubGV2ZWwuYXR0cmlidXRlcyB9fVxuICAgICAgICAgICAgPC9pb24tbGFiZWw+XG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgPC90ZD5cbiAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICA8IS0tIFN0YXR1cyBjb2x1bW4gIC0tPlxuICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJzdGF0dXNJZFwiPlxuICAgICAgICA8dGggbWF0LWhlYWRlci1jZWxsICptYXRIZWFkZXJDZWxsRGVmPlxuICAgICAgICAgIDxzcGFuIHRyYW5zbGF0ZT5VU0VSLlNUQVRVUzwvc3Bhbj5cbiAgICAgICAgPC90aD5cbiAgICAgICAgPHRkIG1hdC1jZWxsICptYXRDZWxsRGVmPVwibGV0IHJvd1wiXG4gICAgICAgICAgICBbY2xhc3MubWF0LWZvcm0tZmllbGQtZGlzYWJsZWRdPVwiIXJvdy5lZGl0aW5nXCJcbiAgICAgICAgICAgIChjbGljayk9XCJmb2N1c0NvbHVtbiA9ICdzdGF0dXNJZCdcIj5cbiAgICAgICAgICA8bWF0LWZvcm0tZmllbGQ+XG4gICAgICAgICAgICA8bWF0LXNlbGVjdFxuICAgICAgICAgICAgICBbZm9ybUNvbnRyb2xdPVwicm93LnZhbGlkYXRvci5jb250cm9sc1snc3RhdHVzSWQnXVwiXG4gICAgICAgICAgICAgIFtwbGFjZWhvbGRlcl09XCJpMThuQ29sdW1uUHJlZml4ICsgJ1NUQVRVU19JRCcgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICA8bWF0LW9wdGlvbiAqbmdGb3I9XCJsZXQgaXRlbSBvZiBzdGF0dXNMaXN0XCIgW3ZhbHVlXT1cIml0ZW0uaWRcIj5cbiAgICAgICAgICAgICAgICA8bWF0LWljb24+PGlvbi1pY29uIFtuYW1lXT1cIml0ZW0uaWNvblwiPjwvaW9uLWljb24+PC9tYXQtaWNvbj5cbiAgICAgICAgICAgICAgICA8bWF0LWxhYmVsPnt7IGl0ZW0ubGFiZWwgfCB0cmFuc2xhdGUgfX08L21hdC1sYWJlbD5cbiAgICAgICAgICAgICAgPC9tYXQtb3B0aW9uPlxuICAgICAgICAgICAgPC9tYXQtc2VsZWN0PlxuICAgICAgICAgICAgPG1hdC1lcnJvciAqbmdJZj1cInJvdy52YWxpZGF0b3IuY29udHJvbHNbJ3N0YXR1c0lkJ10uaGFzRXJyb3IoJ3JlcXVpcmVkJylcIiB0cmFuc2xhdGU+XG4gICAgICAgICAgICAgIEVSUk9SLkZJRUxEX1JFUVVJUkVEXG4gICAgICAgICAgICA8L21hdC1lcnJvcj5cbiAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgICAgICA8L3RkPlxuICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgIDwhLS0gRW51bSBjb2x1bW4gIC0tPlxuICAgICAgPCEtLSBOT1RFIDogTmV2ZXIgdXNlZCBpbiB0YWJsZSAgLS0+XG4gICAgICA8IS0tICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJ2YWx1ZXNcIj4tLT5cbiAgICAgIDwhLS0gICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgKm1hdEhlYWRlckNlbGxEZWY+LS0+XG4gICAgICA8IS0tICAgICAgICAgIDxzcGFuIHRyYW5zbGF0ZT5FbnVtczwvc3Bhbj4tLT5cbiAgICAgIDwhLS0gICAgICAgIDwvdGg+LS0+XG4gICAgICA8IS0tICAgICAgICA8dGQgbWF0LWNlbGwgKm1hdENlbGxEZWY9XCJsZXQgcm93XCIgW2NsYXNzLm1hdC1mb3JtLWZpZWxkLWRpc2FibGVkXT1cIiFyb3cuZWRpdGluZ1wiPi0tPlxuICAgICAgPCEtLSAgICAgICAgICA8YXBwLWZvcm0tZmllbGQtLT5cbiAgICAgIDwhLS0gICAgICAgICAgICBbZm9ybUNvbnRyb2xdPVwicm93LnZhbGlkYXRvcnxmb3JtR2V0Q29udHJvbDoncHJvcGVydGllcy52YWx1ZXMnXCItLT5cbiAgICAgIDwhLS0gICAgICAgICAgICBbZGVmaW5pdGlvbl09XCJjb2x1bW5EZWZpbml0aW9uc1sndmFsdWVzJ11cIi0tPlxuICAgICAgPCEtLSAgICAgICAgICA+PC9hcHAtZm9ybS1maWVsZD4tLT5cbiAgICAgIDwhLS0gICAgICAgIDwvdGQ+LS0+XG4gICAgICA8IS0tICAgICAgPC9uZy1jb250YWluZXI+LS0+XG5cbiAgICAgIDwhLS0gYm9vbGVhbiAoYXMgY2hlY2tib3gpIC0tPlxuICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJib29sZWFuXCI+XG4gICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgKm1hdEhlYWRlckNlbGxEZWYgY2RrRHJhZyBbcmVzaXphYmxlXT1cInRydWVcIj5cbiAgICAgICAgICA8IS0tIGlmIHNvcnRhYmxlLCB3cmFwIHRoZSBoZWFkZXIgd2l0aCBhIG1hdC1zb3J0LWhlYWRlciAtLT5cbiAgICAgICAgICA8c3BhbiBtYXQtc29ydC1oZWFkZXI+XG4gICAgICAgICAgICA8aW9uLWxhYmVsPkJvb2xlYW48L2lvbi1sYWJlbD5cbiAgICAgICAgICA8L3NwYW4+XG4gICAgICAgIDwvdGg+XG4gICAgICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCByb3dcIj5cbiAgICAgICAgICA8bWF0LWJvb2xlYW4tZmllbGRcbiAgICAgICAgICAgICpuZ0lmPVwiIXJlYWRPbmx5ICYmIHJvdy5lZGl0aW5nOyBlbHNlIHJlYWRPbmx5VGVtcGxhdGVcIlxuICAgICAgICAgICAgZmxvYXRMYWJlbD1cIm5ldmVyXCJcbiAgICAgICAgICAgIFtzdHlsZV09XCInY2hlY2tib3gnXCJcbiAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiT3VpL05vblwiXG4gICAgICAgICAgICBbZm9ybUNvbnRyb2xdPVwicm93LnZhbGlkYXRvciB8IGZvcm1HZXRDb250cm9sOiAncHJvcGVydGllcy5ib29sZWFuJ1wiXG4gICAgICAgICAgICBbY29tcGFjdF09XCJ0cnVlXCJcbiAgICAgICAgICA+PC9tYXQtYm9vbGVhbi1maWVsZD5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgI3JlYWRPbmx5VGVtcGxhdGU+XG4gICAgICAgICAgICA8aW9uLWxhYmVsIGFwcEF1dG9UaXRsZT5cbiAgICAgICAgICAgICAge3sgKHJvdy52YWxpZGF0b3IgfCBmb3JtR2V0VmFsdWU6ICdwcm9wZXJ0aWVzLmJvb2xlYW4nKSA/ICcmI3gyNzE0OycgOiAnJiN4MjcxODsnIH19XG4gICAgICAgICAgICA8L2lvbi1sYWJlbD5cbiAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICA8L3RkPlxuICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgIDwhLS0gZGF0ZSAtLT5cbiAgICAgIDxuZy1jb250YWluZXIgbWF0Q29sdW1uRGVmPVwiZGF0ZVwiPlxuICAgICAgICA8dGggbWF0LWhlYWRlci1jZWxsICptYXRIZWFkZXJDZWxsRGVmIGNka0RyYWcgW3Jlc2l6YWJsZV09XCJ0cnVlXCIgY2xhc3M9XCJtYXQtY2VsbC1kYXRlLXRpbWVcIj5cbiAgICAgICAgICA8IS0tIGlmIHNvcnRhYmxlLCB3cmFwIHRoZSBoZWFkZXIgd2l0aCBhIG1hdC1zb3J0LWhlYWRlciAtLT5cbiAgICAgICAgICA8c3BhbiBtYXQtc29ydC1oZWFkZXI+XG4gICAgICAgICAgICA8aW9uLWxhYmVsPkRhdGU8L2lvbi1sYWJlbD5cbiAgICAgICAgICA8L3NwYW4+XG4gICAgICAgIDwvdGg+XG4gICAgICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCByb3dcIiBjbGFzcz1cIm1hdC1jZWxsLWRhdGUtdGltZVwiIChjbGljayk9XCJmb2N1c0NvbHVtbj0nZGF0ZSdcIj5cbiAgICAgICAgICA8bWF0LWRhdGUtdGltZS1maWVsZFxuICAgICAgICAgICAgKm5nSWY9XCIhcmVhZE9ubHkgJiYgcm93LmVkaXRpbmcgJiYgcm93LnZhbGlkYXRvciB8IGZvcm1HZXRDb250cm9sOiAncHJvcGVydGllcy5kYXRlJzsgbGV0IGRhdGVDb250cm9sOyBlbHNlIHJlYWRPbmx5VGVtcGxhdGVcIlxuICAgICAgICAgICAgZmxvYXRMYWJlbD1cIm5ldmVyXCJcbiAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCJkYXRlQ29udHJvbFwiXG4gICAgICAgICAgICBbYXV0b2ZvY3VzXT1cImZvY3VzQ29sdW1uID09PSAnZGF0ZSdcIlxuICAgICAgICAgICAgW2NvbXBhY3RdPVwidHJ1ZVwiXG4gICAgICAgICAgPjwvbWF0LWRhdGUtdGltZS1maWVsZD5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgI3JlYWRPbmx5VGVtcGxhdGU+XG4gICAgICAgICAgICA8aW9uLWxhYmVsIGFwcEF1dG9UaXRsZT5cbiAgICAgICAgICAgICAge3sgKHJvdy52YWxpZGF0b3IgfCBmb3JtR2V0VmFsdWU6ICdwcm9wZXJ0aWVzLmRhdGUnKSB8IGRhdGVGb3JtYXQ6IHsgdGltZTogdHJ1ZSB9IH19XG4gICAgICAgICAgICA8L2lvbi1sYWJlbD5cbiAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICA8L3RkPlxuICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgIDwhLS0gbGF0aXR1ZGUgLS0+XG4gICAgICA8bmctY29udGFpbmVyIG1hdENvbHVtbkRlZj1cImxhdGl0dWRlXCI+XG4gICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgKm1hdEhlYWRlckNlbGxEZWYgY2RrRHJhZyBbcmVzaXphYmxlXT1cInRydWVcIj5cbiAgICAgICAgICA8IS0tIGlmIHNvcnRhYmxlLCB3cmFwIHRoZSBoZWFkZXIgd2l0aCBhIG1hdC1zb3J0LWhlYWRlciAtLT5cbiAgICAgICAgICA8c3BhbiBtYXQtc29ydC1oZWFkZXI+XG4gICAgICAgICAgICA8aW9uLWxhYmVsPkxhdGl0dWRlPC9pb24tbGFiZWw+XG4gICAgICAgICAgPC9zcGFuPlxuICAgICAgICA8L3RoPlxuICAgICAgICA8dGQgbWF0LWNlbGwgKm1hdENlbGxEZWY9XCJsZXQgcm93XCIgKGNsaWNrKT1cImZvY3VzQ29sdW1uPSdsYXRpdHVkZSdcIj5cbiAgICAgICAgICA8bWF0LWxhdGxvbmctZmllbGRcbiAgICAgICAgICAgICpuZ0lmPVwiIXJlYWRPbmx5ICYmIHJvdy5lZGl0aW5nICYmIHJvdy52YWxpZGF0b3IgfCBmb3JtR2V0Q29udHJvbDogJ3Byb3BlcnRpZXMubGF0aXR1ZGUnOyBsZXQgbGF0aXR1ZGVDb250cm9sOyBlbHNlIHJlYWRPbmx5VGVtcGxhdGVcIlxuICAgICAgICAgICAgZmxvYXRMYWJlbD1cIm5ldmVyXCJcbiAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCJsYXRpdHVkZUNvbnRyb2xcIlxuICAgICAgICAgICAgW2xhdExvbmdQYXR0ZXJuXT1cIidERE1NJ1wiXG4gICAgICAgICAgICBbYXV0b2ZvY3VzXT1cImZvY3VzQ29sdW1uID09PSAnbGF0aXR1ZGUnXCJcbiAgICAgICAgICA+PC9tYXQtbGF0bG9uZy1maWVsZD5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgI3JlYWRPbmx5VGVtcGxhdGU+XG4gICAgICAgICAgICA8aW9uLWxhYmVsIGFwcEF1dG9UaXRsZT5cbiAgICAgICAgICAgICAge3sgKHJvdy52YWxpZGF0b3IgfCBmb3JtR2V0VmFsdWU6ICdwcm9wZXJ0aWVzLmxhdGl0dWRlJykgfCBsYXRpdHVkZUZvcm1hdCB9fVxuICAgICAgICAgICAgPC9pb24tbGFiZWw+XG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgPC90ZD5cbiAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICA8IS0tIENyZWF0aW9uIGRhdGUgY29sdW1uIC0tPlxuICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJ1cGRhdGVEYXRlXCI+XG4gICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgKm1hdEhlYWRlckNlbGxEZWYgbWF0LXNvcnQtaGVhZGVyPlxuICAgICAgICAgIDxpb24tbGFiZWwgdHJhbnNsYXRlPlRBQkxFLlRFU1RJTkcuVVBEQVRFX0RBVEU8L2lvbi1sYWJlbD5cbiAgICAgICAgPC90aD5cbiAgICAgICAgPHRkIG1hdC1jZWxsICptYXRDZWxsRGVmPVwibGV0IHJvd1wiIGNsYXNzPVwibWF0LWZvcm0tZmllbGQtZGlzYWJsZWRcIj5cbiAgICAgICAgICA8aW9uLXRleHQgY29sb3I9XCJtZWRpdW1cIiAqbmdJZj1cInJvdy5pZCAhPT0gLTFcIj5cbiAgICAgICAgICAgIDxzbWFsbD5cbiAgICAgICAgICAgICAge3sgcm93LnZhbGlkYXRvciB8IGZvcm1HZXRWYWx1ZTogJ2NyZWF0aW9uRGF0ZScgfCBkYXRlRm9ybWF0OiB7IHRpbWU6IHRydWUgfSB9fVxuICAgICAgICAgICAgPC9zbWFsbD5cbiAgICAgICAgICA8L2lvbi10ZXh0PlxuICAgICAgICA8L3RkPlxuICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgIDwhLS0gQ29tbWVudCBjb2x1bW4gLS0+XG4gICAgICA8bmctY29udGFpbmVyIG1hdENvbHVtbkRlZj1cImNvbW1lbnRzXCI+XG4gICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgKm1hdEhlYWRlckNlbGxEZWY+XG4gICAgICAgICAgPGlvbi1sYWJlbCB0cmFuc2xhdGU+VEFCTEUuVEVTVElORy5DT01NRU5UUzwvaW9uLWxhYmVsPlxuICAgICAgICA8L3RoPlxuICAgICAgICA8dGQgbWF0LWNlbGwgKm1hdENlbGxEZWY9XCJsZXQgcm93XCI+XG4gICAgICAgICAgPG1hdC1mb3JtLWZpZWxkICpuZ0lmPVwicm93LmVkaXRpbmc7IGVsc2UgaWNvbkNvbW1lbnRcIj5cbiAgICAgICAgICAgIDwhLS08dGV4dGFyZWEgbWF0SW5wdXQgW2Zvcm1Db250cm9sXT1cInJvdy52YWxpZGF0b3I/LmNvbnRyb2xzLmNvbW1lbnRzXCJcbiAgICAgICAgICAgICAgICAgICAgICBbcGxhY2Vob2xkZXJdPVwiJ1RBQkxFLlRFU1RJTkcuQ09NTUVOVFMnfHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICAgICAgICAgICAgW3JlYWRvbmx5XT1cIiFyb3cuZWRpdGluZ1wiPjwvdGV4dGFyZWE+LS0+XG5cbiAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICB0eXBlPVwidGV4dFwiXG4gICAgICAgICAgICAgIG1hdElucHV0XG4gICAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCJyb3cudmFsaWRhdG9yPy5jb250cm9scy5jb21tZW50c1wiXG4gICAgICAgICAgICAgIFtwbGFjZWhvbGRlcl09XCInVEFCTEUuVEVTVElORy5DT01NRU5UUycgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgICBbcmVhZG9ubHldPVwiIXJvdy5lZGl0aW5nXCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cblxuICAgICAgICAgIDxuZy10ZW1wbGF0ZSAjaWNvbkNvbW1lbnQ+XG4gICAgICAgICAgICA8aW9uLWljb25cbiAgICAgICAgICAgICAgW2NvbG9yXT1cInJvdy52YWxpZGF0b3I/LmNvbnRyb2xzLmNvbW1lbnRzLnZhbHVlID8gJ3RlcnRpYXJ5JyA6ICdtZWRpdW0nXCJcbiAgICAgICAgICAgICAgbmFtZT1cImNoYXRib3hcIlxuICAgICAgICAgICAgICBzbG90PVwiaWNvbi1vbmx5XCJcbiAgICAgICAgICAgID48L2lvbi1pY29uPlxuICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgIDwvdGQ+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgPCEtLSBBY3Rpb25zIGJ1dHRvbnMgY29sdW1uIC0tPlxuICAgICAgPGFwcC1hY3Rpb25zLWNvbHVtblxuICAgICAgICBbc3RpY2t5RW5kXT1cInRydWVcIlxuICAgICAgICBbY2FuQ2FuY2VsXT1cImZhbHNlXCJcbiAgICAgICAgW3N0eWxlXT1cIid0YWJsZSdcIlxuICAgICAgICAob3B0aW9uc0NsaWNrKT1cIm9wZW5TZWxlY3RDb2x1bW5zTW9kYWwoJGV2ZW50KVwiXG4gICAgICAgIChjYW5jZWxPckRlbGV0ZUNsaWNrKT1cImNhbmNlbE9yRGVsZXRlKCRldmVudC5ldmVudCwgJGV2ZW50LnJvdylcIlxuICAgICAgICAoY29uZmlybUFuZEFkZENsaWNrKT1cImNvbmZpcm1BbmRBZGQoJGV2ZW50LmV2ZW50LCAkZXZlbnQucm93KVwiXG4gICAgICAgIChiYWNrd2FyZCk9XCJjb25maXJtQW5kQmFja3dhcmQoJGV2ZW50LmV2ZW50LCAkZXZlbnQucm93KVwiXG4gICAgICAgIChmb3J3YXJkKT1cImNvbmZpcm1BbmRGb3J3YXJkKCRldmVudC5ldmVudCwgJGV2ZW50LnJvdylcIlxuICAgICAgICBbY2VsbFRlbXBsYXRlXT1cImNlbGxJbmplY3Rpb25cIlxuICAgICAgPlxuICAgICAgICA8IS0tIGNlbGwgaW5qZWN0aW9uLS0+XG4gICAgICAgIDxuZy10ZW1wbGF0ZSAjY2VsbEluamVjdGlvbiBsZXQtcm93PlxuICAgICAgICAgIDxzcGFuICpuZ0lmPVwicm93LmVkaXRpbmcgJiYgIXJvdy52YWxpZGF0b3IuZGlydHlcIj4tPC9zcGFuPlxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgPC9hcHAtYWN0aW9ucy1jb2x1bW4+XG5cbiAgICAgIDx0ciBtYXQtaGVhZGVyLXJvdyAqbWF0SGVhZGVyUm93RGVmPVwiZ3JvdXBDb2x1bW5zXCIgY2xhc3M9XCJtYXQtdG9vbGJhclwiPjwvdHI+XG4gICAgICA8dHIgbWF0LWhlYWRlci1yb3cgKm1hdEhlYWRlclJvd0RlZj1cImRpc3BsYXllZENvbHVtbnM7IHN0aWNreTogdHJ1ZVwiPjwvdHI+XG4gICAgICA8dHJcbiAgICAgICAgbWF0LXJvd1xuICAgICAgICAqbWF0Um93RGVmPVwibGV0IHJvdzsgY29sdW1uczogZGlzcGxheWVkQ29sdW1uc1wiXG4gICAgICAgIFtjbGFzcy5tYXQtbWRjLXJvdy1zZWxlY3RlZF09XCJyb3cuZWRpdGluZ1wiXG4gICAgICAgIFtjbGFzcy5tYXQtbWRjLXJvdy1lcnJvcl09XCJyb3cudmFsaWRhdG9yPy5pbnZhbGlkXCJcbiAgICAgICAgW2NsYXNzLm1hdC1tZGMtcm93LWRpc2FibGVkXT1cIiFyb3cuZWRpdGluZ1wiXG4gICAgICAgIFtjbGFzcy5tYXQtbWRjLXJvdy1kaXJ0eV09XCJyb3cudmFsaWRhdG9yPy5kaXJ0eVwiXG4gICAgICAgIChjbGljayk9XCJjbGlja1JvdygkZXZlbnQsIHJvdylcIlxuICAgICAgICAoa2V5ZG93bi5lc2NhcGUpPVwiZXNjYXBlRWRpdGluZ1JvdygkZXZlbnQpXCJcbiAgICAgICAgW2Nka1RyYXBGb2N1c109XCJyb3cudmFsaWRhdG9yPy5pbnZhbGlkXCJcbiAgICAgID48L3RyPlxuICAgIDwvdGFibGU+XG5cbiAgICA8bmctY29udGFpbmVyICpuZ0lmPVwibG9hZGluZ1N1YmplY3QgfCBhc3luYzsgZWxzZSBub1Jlc3VsdFwiPlxuICAgICAgPGlvbi1pdGVtPlxuICAgICAgICA8aW9uLXNrZWxldG9uLXRleHQgYW5pbWF0ZWQ+PC9pb24tc2tlbGV0b24tdGV4dD5cbiAgICAgIDwvaW9uLWl0ZW0+XG4gICAgPC9uZy1jb250YWluZXI+XG5cbiAgICA8bmctdGVtcGxhdGUgI25vUmVzdWx0PlxuICAgICAgPGlvbi1pdGVtICpuZ0lmPVwidG90YWxSb3dDb3VudCA9PT0gMFwiPlxuICAgICAgICA8aW9uLXRleHQgY29sb3I9XCJkYW5nZXJcIiBjbGFzcz1cInRleHQtaXRhbGljXCIgdHJhbnNsYXRlPkNPTU1PTi5OT19SRVNVTFQ8L2lvbi10ZXh0PlxuICAgICAgPC9pb24taXRlbT5cbiAgICA8L25nLXRlbXBsYXRlPlxuXG4gICAgPGlvbi1pbmZpbml0ZS1zY3JvbGxcbiAgICAgICpuZ0lmPVwiZW5hYmxlSW5maW5pdGVTY3JvbGxcIlxuICAgICAgW3RocmVzaG9sZF09XCJtb2JpbGUgPyAnMTAlJyA6ICcyJSdcIlxuICAgICAgcG9zaXRpb249XCJib3R0b21cIlxuICAgICAgKGlvbkluZmluaXRlKT1cImZldGNoTW9yZSgkZXZlbnQpXCJcbiAgICA+XG4gICAgICA8aW9uLWluZmluaXRlLXNjcm9sbC1jb250ZW50XG4gICAgICAgIGxvYWRpbmdTcGlubmVyPVwiY2lyY2xlc1wiXG4gICAgICAgIFtsb2FkaW5nVGV4dF09XCInQ09NTU9OLkxPQURJTkdfRE9UUycgfCB0cmFuc2xhdGVcIlxuICAgICAgPjwvaW9uLWluZmluaXRlLXNjcm9sbC1jb250ZW50PlxuICAgIDwvaW9uLWluZmluaXRlLXNjcm9sbD5cbiAgPC9kaXY+XG48L2lvbi1jb250ZW50PlxuXG48aW9uLWZvb3Rlcj5cbiAgPCEtLSBQYWdpbmF0b3IgIC0tPlxuICA8bWF0LXBhZ2luYXRvclxuICAgICpuZ0lmPVwiIWVuYWJsZUluZmluaXRlU2Nyb2xsXCJcbiAgICBbbGVuZ3RoXT1cInRvdGFsUm93Q291bnRcIlxuICAgIFtwYWdlU2l6ZV09XCJkZWZhdWx0UGFnZVNpemVcIlxuICAgIFtwYWdlU2l6ZU9wdGlvbnNdPVwiZGVmYXVsdFBhZ2VTaXplT3B0aW9uc1wiXG4gICAgc2hvd0ZpcnN0TGFzdEJ1dHRvbnNcbiAgPjwvbWF0LXBhZ2luYXRvcj5cblxuICA8YXBwLWZvcm0tYnV0dG9ucy1iYXJcbiAgICAqbmdJZj1cImNhbkVkaXQgJiYgIW1vYmlsZVwiXG4gICAgKG9uQ2FuY2VsKT1cImxvYWQoKVwiXG4gICAgKG9uU2F2ZSk9XCJzYXZlKClcIlxuICAgIFtkaXNhYmxlZF09XCIobG9hZGluZ1N1YmplY3QgfCBhc3luYykgfHwgIWRpcnR5XCJcbiAgPlxuICAgIDwhLS0gZXJyb3IgLS0+XG4gICAgPGlvbi1pdGVtICpuZ0lmPVwiZXJyb3IkIHwgYXN5bmNcIiBsaW5lcz1cIm5vbmVcIj5cbiAgICAgIDxpb24taWNvbiBjb2xvcj1cImRhbmdlclwiIHNsb3Q9XCJzdGFydFwiIG5hbWU9XCJhbGVydC1jaXJjbGVcIj48L2lvbi1pY29uPlxuICAgICAgPGlvbi1sYWJlbCBjb2xvcj1cImRhbmdlclwiIFtpbm5lckhUTUxdPVwiZXJyb3IgfCB0cmFuc2xhdGVcIj48L2lvbi1sYWJlbD5cbiAgICA8L2lvbi1pdGVtPlxuICA8L2FwcC1mb3JtLWJ1dHRvbnMtYmFyPlxuPC9pb24tZm9vdGVyPlxuXG48aW9uLWZhYiBzbG90PVwiZml4ZWRcIiB2ZXJ0aWNhbD1cImJvdHRvbVwiIGhvcml6b250YWw9XCJlbmRcIiAqbmdJZj1cImNhbkVkaXQgJiYgbW9iaWxlXCI+XG4gIDxpb24tZmFiLWJ1dHRvbiBjb2xvcj1cInRlcnRpYXJ5XCIgKGNsaWNrKT1cImFkZFJvdygkZXZlbnQpXCI+XG4gICAgPGlvbi1pY29uIG5hbWU9XCJhZGRcIj48L2lvbi1pY29uPlxuICA8L2lvbi1mYWItYnV0dG9uPlxuPC9pb24tZmFiPlxuIl19
|
|
333
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFibGUudGVzdGluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcHAvY29yZS90YWJsZS90ZXN0aW5nL3RhYmxlLnRlc3RpbmcudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBwL2NvcmUvdGFibGUvdGVzdGluZy90YWJsZS50ZXN0aW5nLmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUVMLHVCQUF1QixFQUV2QixTQUFTLEVBQ1QsVUFBVSxFQUVWLEtBQUssRUFHTCxTQUFTLEdBQ1YsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzFDLE9BQU8sRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLE1BQU0sd0NBQXdDLENBQUM7QUFDakYsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDbkQsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFDN0UsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sc0RBQXNELENBQUM7QUFDL0YsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sK0NBQStDLENBQUM7QUFFcEYsT0FBTyxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUM1RCxPQUFPLEVBQUUsU0FBUyxFQUFFLG1CQUFtQixFQUFFLGVBQWUsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3hGLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGlEQUFpRCxDQUFDO0FBQ3BGLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzNELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztB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QUFXLEVBQUUsVUFBVSxDQUFDLEdBQUcsRUFBRSxjQUFjLENBQUM7eUJBQzdDO3FCQUNGLG1CQUNnQix1QkFBdUIsQ0FBQyxNQUFNO2dMQWdCdEMsbUJBQW1CO3NCQUEzQixLQUFLO2dCQUNHLG9CQUFvQjtzQkFBNUIsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUs7Z0JBQ0csU0FBUztzQkFBakIsS0FBSztnQkFNMEMsb0JBQW9CO3NCQUFuRSxTQUFTO3VCQUFDLGlCQUFpQixFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRTtnQkFDaEIsY0FBYztzQkFBM0MsU0FBUzt1QkFBQyxpQkFBaUIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBBZnRlclZpZXdJbml0LFxuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gIENvbXBvbmVudCxcbiAgZm9yd2FyZFJlZixcbiAgSW5qZWN0b3IsXG4gIElucHV0LFxuICBPbkRlc3Ryb3ksXG4gIE9uSW5pdCxcbiAgVmlld0NoaWxkLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEFwcFRhYmxlIH0gZnJvbSAnLi4vdGFibGUuY2xhc3MnO1xuaW1wb3J0IHsgUmVmZXJlbnRpYWwsIFN0YXR1c0xpc3QgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9tb2RlbC9yZWZlcmVudGlhbC5tb2RlbCc7XG5pbXBvcnQgeyBJb25JbmZpbml0ZVNjcm9sbCB9IGZyb20gJ0Bpb25pYy9hbmd1bGFyJztcbmltcG9ydCB7IEVudGl0aWVzVGFibGVEYXRhU291cmNlIH0gZnJvbSAnLi4vZW50aXRpZXMtdGFibGUtZGF0YXNvdXJjZS5jbGFzcyc7XG5pbXBvcnQgeyBJbk1lbW9yeUVudGl0aWVzU2VydmljZSB9IGZyb20gJy4uLy4uLy4uL3NoYXJlZC9zZXJ2aWNlcy9tZW1vcnktZW50aXR5LXNlcnZpY2UuY2xhc3MnO1xuaW1wb3J0IHsgQXBwVmFsaWRhdG9yU2VydmljZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL3ZhbGlkYXRvci9iYXNlLnZhbGlkYXRvci5jbGFzcyc7XG5pbXBvcnQgeyBBYnN0cmFjdENvbnRyb2wsIFVudHlwZWRGb3JtQnVpbGRlciwgVW50eXBlZEZvcm1Hcm91cCB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IGlzTmlsLCBpc05vdE5pbCB9IGZyb20gJy4uLy4uLy4uL3NoYXJlZC9mdW5jdGlvbnMnO1xuaW1wb3J0IHsgRGF0ZVV0aWxzLCBmcm9tVW5peE1zVGltZXN0YW1wLCB0b0RhdGVJU09TdHJpbmcgfSBmcm9tICcuLi8uLi8uLi9zaGFyZWQvZGF0ZXMnO1xuaW1wb3J0IHsgUmVmZXJlbnRpYWxGaWx0ZXIgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy90ZXN0aW5nL3JlZmVyZW50aWFsLWZpbHRlci5tb2RlbCc7XG5pbXBvcnQgeyBkZWJvdW5jZVRpbWUsIGZpbHRlciwgdGFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgTWF0RXhwYW5zaW9uUGFuZWwgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9leHBhbnNpb24nO1xuaW1wb3J0IHsgU3RhdHVzSWRzIH0gZnJvbSAnLi4vLi4vc2VydmljZXMvbW9kZWwvbW9kZWwuZW51bSc7XG5pbXBvcnQgeyBTdWJzY3JpcHRpb24sIHRpbWVyIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBSRVNFUlZFRF9FTkRfQ09MVU1OUywgUkVTRVJWRURfU1RBUlRfQ09MVU1OUyB9IGZyb20gJy4uL3RhYmxlLm1vZGVsJztcbmltcG9ydCB7IFRhYmxlVmFsaWRhdG9yU2VydmljZSB9IGZyb20gJy4vdGFibGUtdmFsaWRhdG9yLnNlcnZpY2UnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdhcHAtdGFibGUtdGVzdGluZycsXG4gIHN0eWxlVXJsczogWyd0YWJsZS50ZXN0aW5nLnNjc3MnXSxcbiAgdGVtcGxhdGVVcmw6ICd0YWJsZS50ZXN0aW5nLmh0bWwnLFxuICBwcm92aWRlcnM6IFtcbiAgICB7XG4gICAgICBwcm92aWRlOiBBcHBWYWxpZGF0b3JTZXJ2aWNlLFxuICAgICAgdXNlQ2xhc3M6IFRhYmxlVmFsaWRhdG9yU2VydmljZSxcbiAgICB9LFxuICAgIHtcbiAgICAgIHByb3ZpZGU6IEFwcFRhYmxlLFxuICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gVGFibGVUZXN0UGFnZSksXG4gICAgfSxcbiAgXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG59KVxuZXhwb3J0IGNsYXNzIFRhYmxlVGVzdFBhZ2UgZXh0ZW5kcyBBcHBUYWJsZTxSZWZlcmVudGlhbCwgUmVmZXJlbnRpYWxGaWx0ZXI+IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3ksIEFmdGVyVmlld0luaXQge1xuICByZWFkb25seSBtYXhSb3dDb3VudCA9IDEwMDtcblxuICB0aW1lcjogU3Vic2NyaXB0aW9uO1xuICBjYW5FZGl0ID0gdHJ1ZTtcbiAgZGF0YTogUmVmZXJlbnRpYWxbXTtcbiAgZmlsdGVyRm9ybTogVW50eXBlZEZvcm1Hcm91cDtcbiAgZmlsdGVyQ3JpdGVyaWFDb3VudCA9IDA7XG4gIGdyb3VwQ29sdW1ucyA9IFsndG9wLXN0YXJ0JywgJ2dyb3VwLTEnLCAnZ3JvdXAtMicsICd0b3AtZW5kJ107XG4gIHJvd0hlaWdodCA9IDQ4O1xuICBwZXJtYW5lbnRTZWxlY3Rpb25BbGxvd2VkID0gdHJ1ZTtcblxuICByZWFkb25seSBzdGF0dXNMaXN0ID0gU3RhdHVzTGlzdDtcblxuICBASW5wdXQoKSBmaWx0ZXJQYW5lbEZsb2F0aW5nID0gdHJ1ZTtcbiAgQElucHV0KCkgZW5hYmxlSW5maW5pdGVTY3JvbGw6IGJvb2xlYW47XG4gIEBJbnB1dCgpIHN0aWNreSA9IHRydWU7XG4gIEBJbnB1dCgpIHN0aWNreUVuZCA9IHRydWU7XG5cbiAgZ2V0IGhhc01vcmVEYXRhKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmRhdGEubGVuZ3RoIDwgMTAwO1xuICB9XG5cbiAgQFZpZXdDaGlsZChNYXRFeHBhbnNpb25QYW5lbCwgeyBzdGF0aWM6IHRydWUgfSkgZmlsdGVyRXhwYW5zaW9uUGFuZWw6IE1hdEV4cGFuc2lvblBhbmVsO1xuICBAVmlld0NoaWxkKElvbkluZmluaXRlU2Nyb2xsKSBpbmZpbml0ZVNjcm9sbDogSW9uSW5maW5pdGVTY3JvbGw7XG5cbiAgZ2V0IGRhdGFTZXJ2aWNlKCk6IEluTWVtb3J5RW50aXRpZXNTZXJ2aWNlPFJlZmVyZW50aWFsPiB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGFTb3VyY2UuZGF0YVNlcnZpY2UgYXMgSW5NZW1vcnlFbnRpdGllc1NlcnZpY2U8UmVmZXJlbnRpYWw+O1xuICB9XG5cbiAgY29uc3RydWN0b3IoXG4gICAgaW5qZWN0b3I6IEluamVjdG9yLFxuICAgIHByb3RlY3RlZCB2YWxpZGF0b3JTZXJ2aWNlOiBBcHBWYWxpZGF0b3JTZXJ2aWNlLFxuICAgIHByb3RlY3RlZCBmb3JtQnVpbGRlcjogVW50eXBlZEZvcm1CdWlsZGVyLFxuICAgIHByb3RlY3RlZCBjZDogQ2hhbmdlRGV0ZWN0b3JSZWZcbiAgKSB7XG4gICAgc3VwZXIoXG4gICAgICBpbmplY3RvcixcbiAgICAgIFtcbiAgICAgICAgLi4uUkVTRVJWRURfU1RBUlRfQ09MVU1OUyxcbiAgICAgICAgJ2xhYmVsJyxcbiAgICAgICAgJ25hbWUnLFxuICAgICAgICAnbGV2ZWxJZCcsXG4gICAgICAgICdzdGF0dXNJZCcsXG4gICAgICAgICdib29sZWFuJyxcbiAgICAgICAgJ2RhdGUnLFxuICAgICAgICAnbGF0aXR1ZGUnLFxuICAgICAgICAndXBkYXRlRGF0ZScsXG4gICAgICAgICdjb21tZW50cycsXG4gICAgICAgIC4uLlJFU0VSVkVEX0VORF9DT0xVTU5TLFxuICAgICAgXSxcbiAgICAgIG5ldyBFbnRpdGllc1RhYmxlRGF0YVNvdXJjZShcbiAgICAgICAgUmVmZXJlbnRpYWwsXG4gICAgICAgIG5ldyBJbk1lbW9yeUVudGl0aWVzU2VydmljZShSZWZlcmVudGlhbCwgUmVmZXJlbnRpYWxGaWx0ZXIsIHtcbiAgICAgICAgICBzb3J0QnlSZXBsYWNlbWVudDogeyBpZDogJ2lkJyB9LFxuICAgICAgICB9KSxcbiAgICAgICAgdmFsaWRhdG9yU2VydmljZSxcbiAgICAgICAge1xuICAgICAgICAgIHN1cHByZXNzRXJyb3JzOiBmYWxzZSxcbiAgICAgICAgfVxuICAgICAgKSxcbiAgICAgIG51bGxcbiAgICApO1xuXG4gICAgLy8gV29ya3Mgd2l0aCB0cnVlIGFuZCBmYWxzZVxuICAgIHRoaXMuZW5hYmxlSW5maW5pdGVTY3JvbGwgPSB0aGlzLm1vYmlsZTtcblxuICAgIHRoaXMuYXV0b0xvYWQgPSBmYWxzZTtcbiAgICB0aGlzLmlubGluZUVkaXRpb24gPSB0cnVlO1xuICAgIHRoaXMuaTE4bkNvbHVtblByZWZpeCA9ICdUQUJMRS5URVNUSU5HLic7XG5cbiAgICB0aGlzLmNvbmZpcm1CZWZvcmVEZWxldGUgPSB0cnVlO1xuICAgIHRoaXMuY29uZmlybUJlZm9yZUNhbmNlbCA9IGZhbHNlO1xuICAgIHRoaXMudW5kb2FibGVEZWxldGlvbiA9IGZhbHNlO1xuICAgIHRoaXMuc2F2ZUJlZm9yZURlbGV0ZSA9IGZhbHNlO1xuXG4gICAgdGhpcy5zYXZlQmVmb3JlU29ydCA9IHRydWU7XG4gICAgdGhpcy5zYXZlQmVmb3JlRmlsdGVyID0gdHJ1ZTtcbiAgICB0aGlzLnByb3BhZ2F0ZVJvd0Vycm9yID0gdHJ1ZTtcblxuICAgIHRoaXMuZmlsdGVyRm9ybSA9IGZvcm1CdWlsZGVyLmdyb3VwKHtcbiAgICAgIHNlYXJjaFRleHQ6IFtudWxsXSxcbiAgICB9KTtcblxuICAgIC8vIHRoaXMuY29sdW1uRGVmaW5pdGlvbnNbJ3ZhbHVlcyddID0gPEZvcm1GaWVsZERlZmluaXRpb24+e1xuICAgIC8vICAga2V5OiAndmFsdWVzJyxcbiAgICAvLyAgIHR5cGU6ICdlbnVtcycsXG4gICAgLy8gICB2YWx1ZXM6IFtcbiAgICAvLyAgICAge2tleTogJ0EnLCB2YWx1ZTogJ1ZhbHVlIEEnfSxcbiAgICAvLyAgICAge2tleTogJ0InLCB2YWx1ZTogJ1ZhbHVlIEInfVxuICAgIC8vICAgXVxuICAgIC8vIH07XG5cbiAgICAvLyBJbml0IG5ldyBlbnRpdHlcbiAgICB0aGlzLm9uU3RhcnRFZGl0aW5nUm93LnN1YnNjcmliZSgocm93KSA9PiB7XG4gICAgICByb3cudmFsaWRhdG9yLnBhdGNoVmFsdWUoXG4gICAgICAgIHtcbiAgICAgICAgICBlbnRpdHlOYW1lOiAnVGVzdFZPJyxcbiAgICAgICAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgICBib29sZWFuOiBmYWxzZSxcbiAgICAgICAgICAgIGRhdGU6IHRvRGF0ZUlTT1N0cmluZyhEYXRlVXRpbHMubW9tZW50KCkpLFxuICAgICAgICAgICAgbGF0aXR1ZGU6IDExLjExMTEsXG4gICAgICAgICAgICAuLi5yb3cuY3VycmVudERhdGEucHJvcGVydGllcyxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICB7IGVtaXRFdmVudDogZmFsc2UgfVxuICAgICAgKTtcbiAgICB9KTtcbiAgfVxuXG4gIG5nT25Jbml0KCkge1xuICAgIHN1cGVyLm5nT25Jbml0KCk7XG5cbiAgICAvLyBVcGRhdGUgZmlsdGVyIHdoZW4gY2hhbmdlc1xuICAgIHRoaXMucmVnaXN0ZXJTdWJzY3JpcHRpb24oXG4gICAgICB0aGlzLmZpbHRlckZvcm0udmFsdWVDaGFuZ2VzXG4gICAgICAgIC5waXBlKFxuICAgICAgICAgIGRlYm91bmNlVGltZSgyNTApLFxuICAgICAgICAgIGZpbHRlcigoKSA9PiB0aGlzLmZpbHRlckZvcm0udmFsaWQpLFxuICAgICAgICAgIHRhcCgodmFsdWUpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGZpbHRlciA9IFJlZmVyZW50aWFsRmlsdGVyLmZyb21PYmplY3QodmFsdWUpO1xuICAgICAgICAgICAgdGhpcy5maWx0ZXJDcml0ZXJpYUNvdW50ID0gZmlsdGVyLmNvdW50Tm90RW1wdHlDcml0ZXJpYSgpO1xuICAgICAgICAgICAgdGhpcy5tYXJrRm9yQ2hlY2soKTtcbiAgICAgICAgICAgIC8vIEFwcGx5aW5nIHRoZSBmaWx0ZXJcbiAgICAgICAgICAgIHRoaXMuc2V0RmlsdGVyKGZpbHRlciwgeyBlbWl0RXZlbnQ6IGZhbHNlIH0pO1xuICAgICAgICAgIH0pLFxuICAgICAgICAgIC8vIFNhdmUgZmlsdGVyIGluIHNldHRpbmdzIChhZnRlciBhIGRlYm91bmNlIHRpbWUpXG4gICAgICAgICAgZGVib3VuY2VUaW1lKDUwMCksXG4gICAgICAgICAgdGFwKChqc29uKSA9PiB0aGlzLnNldHRpbmdzLnNhdmVQYWdlU2V0dGluZyh0aGlzLnNldHRpbmdzSWQsIGpzb24sICdmaWx0ZXInKSlcbiAgICAgICAgKVxuICAgICAgICAuc3Vic2NyaWJlKClcbiAgICApO1xuXG4gICAgdGhpcy5yZWdpc3RlckF1dG9jb21wbGV0ZUZpZWxkKCdsZXZlbCcsIHtcbiAgICAgIGl0ZW1zOiBbXG4gICAgICAgIHsgaWQ6IDEsIGxhYmVsOiAnQScsIG5hbWU6ICdpdGVtIEEnIH0sXG4gICAgICAgIHsgaWQ6IDEsIGxhYmVsOiAnQicsIG5hbWU6ICdpdGVtIEInIH0sXG4gICAgICBdLFxuICAgICAgbW9iaWxlOiB0aGlzLm1vYmlsZSxcbiAgICB9KTtcblxuICAgIHRoaXMucmVnaXN0ZXJTdWJzY3JpcHRpb24oXG4gICAgICB0aGlzLm9uUmVmcmVzaC5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgICB0aGlzLmZpbHRlckZvcm0ubWFya0FzVW50b3VjaGVkKCk7XG4gICAgICAgIHRoaXMuZmlsdGVyRm9ybS5tYXJrQXNQcmlzdGluZSgpO1xuICAgICAgfSlcbiAgICApO1xuXG4gICAgdGhpcy5tYXJrQXNSZWFkeSgpO1xuICB9XG5cbiAgYXN5bmMgbmdBZnRlclZpZXdJbml0KCkge1xuICAgIHN1cGVyLm5nQWZ0ZXJWaWV3SW5pdCgpO1xuXG4gICAgLy8gUmVzdG9yZSBmaWx0ZXIgZnJvbSBzZXR0aW5nc1xuICAgIGF3YWl0IHRoaXMucmVzdG9yZUZpbHRlcigpO1xuXG4gICAgLy8gTG9hZCBkYXRhXG4gICAgdGhpcy5sb2FkKCk7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpIHtcbiAgICBjb25zb2xlLmRlYnVnKCdbdGVzdC10YWJsZV0gRGVzdHJveWluZyB0YWJsZS4uLicpO1xuICAgIHN1cGVyLm5nT25EZXN0cm95KCk7XG4gICAgdGhpcy5zdG9wVGltZXIoKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyByZXN0b3JlRmlsdGVyKCkge1xuICAgIGF3YWl0IHRoaXMuc2V0dGluZ3MucmVhZHkoKTtcblxuICAgIGNvbnN0IGpzb24gPSB0aGlzLnNldHRpbmdzLmdldFBhZ2VTZXR0aW5ncyh0aGlzLnNldHRpbmdzSWQsICdmaWx0ZXInKTtcbiAgICBjb25zb2xlLmRlYnVnKCdbdGFibGUtdGVzdF0gUmVzdG9yaW5nIGZpbHRlciBmcm9tIHNldHRpbmdzLi4uJywganNvbik7XG5cbiAgICBpZiAoanNvbikge1xuICAgICAgY29uc3QgZmlsdGVyID0gUmVmZXJlbnRpYWxGaWx0ZXIuZnJvbU9iamVjdChqc29uKTtcbiAgICAgIHRoaXMuZmlsdGVyRm9ybS5wYXRjaFZhbHVlKGpzb24sIHsgZW1pdEV2ZW50OiBmYWxzZSB9KTtcbiAgICAgIHRoaXMuZmlsdGVyQ3JpdGVyaWFDb3VudCA9IGZpbHRlci5jb3VudE5vdEVtcHR5Q3JpdGVyaWEoKTtcbiAgICAgIHRoaXMuc2V0RmlsdGVyKGZpbHRlciwgeyBlbWl0RXZlbnQ6IHRydWUgfSk7XG4gICAgICB0aGlzLm1hcmtGb3JDaGVjaygpO1xuICAgIH1cbiAgfVxuXG4gIHRvZ2dsZVRpbWVyKCkge1xuICAgIGlmIChpc05vdE5pbCh0aGlzLnRpbWVyKSkgdGhpcy5zdG9wVGltZXIoKTtcbiAgICBlbHNlIHRoaXMuc3RhcnRUaW1lcigpO1xuICB9XG5cbiAgYXN5bmMgbG9hZCgpIHtcbiAgICBjb25zb2xlLmRlYnVnKCdbdGVzdC10YWJsZV0gVXBkYXRpbmcgZGF0YS4uLicpO1xuICAgIHRoaXMubWFya0FzTG9hZGluZygpO1xuXG4gICAgaWYgKGlzTmlsKHRoaXMuZGF0YSkpIHtcbiAgICAgIHRoaXMuZGF0YSA9IHRoaXMuZ2VuZXJhdGVEYXRhKDAsIHRoaXMubWF4Um93Q291bnQpO1xuICAgIH1cbiAgICB0aGlzLmRhdGFTZXJ2aWNlLnZhbHVlID0gdGhpcy5kYXRhO1xuXG4gICAgdGhpcy5vblJlZnJlc2guZW1pdCgpO1xuICB9XG5cbiAgYXN5bmMgZmV0Y2hNb3JlKGV2ZW50KSB7XG4gICAgY29uc29sZS5kZWJ1ZygnW3RhYmxlLXRlc3RdIExvYWRpbmcgbW9yZS4uLicsIGV2ZW50KTtcbiAgICBjb25zdCBmZXRjaGVkID0gYXdhaXQgdGhpcy5fZGF0YVNvdXJjZS5mZXRjaE1vcmUoKTtcblxuICAgIGlmIChmZXRjaGVkICYmIGV2ZW50Py50YXJnZXQgJiYgZXZlbnQudGFyZ2V0LmNvbXBsZXRlKSB7XG4gICAgICAvLyBXYWl0IGVuZCBvZiBsb2FkXG4gICAgICBhd2FpdCB0aGlzLndhaXRJZGxlKCk7XG4gICAgICAvLyBNYXJrIHRhcmdldCBldmVudCBhcyBjb21wbGV0ZWQgKGUuZy4gSW9uUmVmcmVzaGVyKVxuICAgICAgZXZlbnQudGFyZ2V0LmNvbXBsZXRlKCk7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgc2F2ZShvcHRzPzogeyBrZWVwRWRpdGluZz86IGJvb2xlYW4gfSk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IHNhdmVkID0gYXdhaXQgc3VwZXIuc2F2ZShvcHRzKTtcbiAgICBpZiAoc2F2ZWQpIHtcbiAgICAgIC8vIFVwZGF0ZSBzb3VyY2UgZGF0YVxuICAgICAgdGhpcy5kYXRhID0gdGhpcy5kYXRhU2VydmljZS52YWx1ZTtcbiAgICB9XG4gICAgcmV0dXJuIHNhdmVkO1xuICB9XG5cbiAgY2xlYXJDb250cm9sVmFsdWUoZXZlbnQ6IEV2ZW50LCBmb3JtQ29udHJvbDogQWJzdHJhY3RDb250cm9sKTogYm9vbGVhbiB7XG4gICAgaWYgKGV2ZW50KSBldmVudC5zdG9wUHJvcGFnYXRpb24oKTsgLy8gQXZvaWQgdG8gZW50ZXIgaW5wdXQgdGhlIGZpZWxkXG4gICAgZm9ybUNvbnRyb2wuc2V0VmFsdWUobnVsbCk7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgdG9nZ2xlRmlsdGVyUGFuZWxGbG9hdGluZygpIHtcbiAgICB0aGlzLmZpbHRlclBhbmVsRmxvYXRpbmcgPSAhdGhpcy5maWx0ZXJQYW5lbEZsb2F0aW5nO1xuICAgIHRoaXMubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICBhcHBseUZpbHRlckFuZENsb3NlUGFuZWwoZXZlbnQ/OiBFdmVudCkge1xuICAgIGNvbnN0IGZpbHRlciA9IHRoaXMuZmlsdGVyRm9ybS52YWx1ZTtcbiAgICB0aGlzLnNldEZpbHRlcihmaWx0ZXIsIHsgZW1pdEV2ZW50OiBmYWxzZSB9KTtcbiAgICB0aGlzLm9uUmVmcmVzaC5lbWl0KGV2ZW50KTtcbiAgICBpZiAodGhpcy5maWx0ZXJFeHBhbnNpb25QYW5lbCAmJiB0aGlzLmZpbHRlclBhbmVsRmxvYXRpbmcpIHRoaXMuZmlsdGVyRXhwYW5zaW9uUGFuZWwuY2xvc2UoKTtcbiAgfVxuXG4gIGNsb3NlRmlsdGVyUGFuZWwoKSB7XG4gICAgaWYgKHRoaXMuZmlsdGVyRXhwYW5zaW9uUGFuZWwpIHRoaXMuZmlsdGVyRXhwYW5zaW9uUGFuZWwuY2xvc2UoKTtcbiAgICBpZiAoIXRoaXMuZmlsdGVyUGFuZWxGbG9hdGluZykge1xuICAgICAgdGhpcy5maWx0ZXJQYW5lbEZsb2F0aW5nID0gdHJ1ZTtcbiAgICAgIHRoaXMubWFya0ZvckNoZWNrKCk7XG4gICAgfVxuICB9XG5cbiAgcmVzZXRGaWx0ZXIoXz86IEV2ZW50KSB7XG4gICAgdGhpcy5maWx0ZXJGb3JtLnJlc2V0KHt9LCB7IGVtaXRFdmVudDogdHJ1ZSB9KTtcbiAgICB0aGlzLnNldEZpbHRlcihSZWZlcmVudGlhbEZpbHRlci5mcm9tT2JqZWN0KHt9KSwgeyBlbWl0RXZlbnQ6IHRydWUgfSk7XG4gICAgdGhpcy5maWx0ZXJFeHBhbnNpb25QYW5lbC5jbG9zZSgpO1xuICB9XG5cbiAgc3RhcnRUaW1lcigpIHtcbiAgICB0aGlzLnN0b3BUaW1lcigpO1xuICAgIHRoaXMudGltZXIgPSB0aW1lcig1MDApLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICB0aGlzLmRhdGEgPSBudWxsOyAvLyBSZXNldFxuICAgICAgdGhpcy5sb2FkKCk7XG4gICAgfSk7XG4gIH1cblxuICBzdG9wVGltZXIoKSB7XG4gICAgdGhpcy50aW1lcj8udW5zdWJzY3JpYmUoKTtcbiAgICB0aGlzLnRpbWVyID0gbnVsbDtcbiAgfVxuXG4gIHByb3RlY3RlZCBnZW5lcmF0ZURhdGEob2Zmc2V0PzogbnVtYmVyLCBzaXplPzogbnVtYmVyKTogUmVmZXJlbnRpYWxbXSB7XG4gICAgb2Zmc2V0ID0gb2Zmc2V0IHx8IDA7XG4gICAgc2l6ZSA9IHNpemUgfHwgMTAwO1xuXG4gICAgY29uc3QgcmVzdWx0ID0gbmV3IEFycmF5PFJlZmVyZW50aWFsPigpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc2l6ZTsgaSsrKSB7XG4gICAgICBjb25zdCBpZCA9IGkgKyAxICsgb2Zmc2V0O1xuICAgICAgY29uc3QgaXRlbSA9IFJlZmVyZW50aWFsLmZyb21PYmplY3Qoe1xuICAgICAgICBpZCxcbiAgICAgICAgbGFiZWw6ICdDT0RFLScgKyBpZCxcbiAgICAgICAgbmFtZTogJ05hbWUgIycgKyBpZCxcbiAgICAgICAgbGV2ZWxJZDogeyBpZDogMSwgbGFiZWw6ICdBJywgbmFtZTogJ0l0ZW0gQScgfSxcbiAgICAgICAgc3RhdHVzSWQ6IFN0YXR1c0lkcy5FTkFCTEUsXG4gICAgICAgIGNvbW1lbnRzOiBpICUgMyA9PT0gMCA/ICdNeSBjb21tZW50ICMnICsgaWQgOiB1bmRlZmluZWQsXG4gICAgICAgIHByb3BlcnRpZXM6IHtcbiAgICAgICAgICB2YWx1ZXM6IGkgJSAyID09PSAwID8gJ0EnIDogJ0EsQicsXG4gICAgICAgICAgYm9vbGVhbjogZmFsc2UsXG4gICAgICAgICAgZGF0ZTogbnVsbCwgLy8gdG9EYXRlSVNPU3RyaW5nKERhdGVVdGlscy5tb21lbnQoKSksXG4gICAgICAgICAgbGF0aXR1ZGU6IG51bGwsIC8vIDExLjExMTFcbiAgICAgICAgfSxcbiAgICAgICAgY3JlYXRpb25EYXRlOiBmcm9tVW5peE1zVGltZXN0YW1wKERhdGUubm93KCkgLSBpICogNjAgKiAxMDAwKSxcbiAgICAgICAgdXBkYXRlRGF0ZTogZnJvbVVuaXhNc1RpbWVzdGFtcChEYXRlLm5vdygpIC0gaSAqIDYwICogMTAwMCksXG4gICAgICAgIGVudGl0eU5hbWU6ICdUZXN0Vk8nLFxuICAgICAgfSk7XG4gICAgICByZXN1bHQucHVzaChpdGVtKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgcHJvdGVjdGVkIG1hcmtGb3JDaGVjaygpIHtcbiAgICB0aGlzLmNkLm1hcmtGb3JDaGVjaygpO1xuICB9XG59XG4iLCI8YXBwLXRvb2xiYXJcbiAgY29sb3I9XCJwcmltYXJ5XCJcbiAgW2NhbkdvQmFja109XCJ0cnVlXCJcbiAgW2hhc1ZhbGlkYXRlXT1cIihsb2FkaW5nU3ViamVjdCB8IGFzeW5jKSAhPT0gdHJ1ZSAmJiAoZGlydHlTdWJqZWN0IHwgYXN5bmMpID09PSB0cnVlXCJcbiAgKG9uVmFsaWRhdGUpPVwic2F2ZSgpXCJcbiAgW2JhY2tIcmVmXT1cIicvdGVzdGluZydcIlxuPlxuICA8aW9uLXRpdGxlPlRhYmxlIChjbGljayB0byBlZGl0KTwvaW9uLXRpdGxlPlxuICA8aW9uLWJ1dHRvbnMgc2xvdD1cImVuZFwiPlxuICAgIEBpZiAoc2VsZWN0aW9uIHwgaXNFbXB0eVNlbGVjdGlvbikge1xuICAgICAgPGlucHV0IG1hdElucHV0IHR5cGU9XCJudW1iZXJcIiBzdGVwPVwiMVwiIHN0eWxlPVwiY29sb3I6IGJsYWNrOyB3aWR0aDogNTBweFwiIFsobmdNb2RlbCldPVwicm93SGVpZ2h0XCIgLz5cblxuICAgICAgPCEtLSBBZGQgLS0+XG4gICAgICA8YnV0dG9uIG1hdC1pY29uLWJ1dHRvbiAqbmdJZj1cImNhbkVkaXQgJiYgIW1vYmlsZVwiIFt0aXRsZV09XCInQ09NTU9OLkJUTl9BREQnIHwgdHJhbnNsYXRlXCIgKGNsaWNrKT1cImFkZFJvdygpXCI+XG4gICAgICAgIDxtYXQtaWNvbj5hZGQ8L21hdC1pY29uPlxuICAgICAgPC9idXR0b24+XG5cbiAgICAgIDwhLS0gcmVzZXQgZmlsdGVyIC0tPlxuICAgICAgPGJ1dHRvbiBtYXQtaWNvbi1idXR0b24gKGNsaWNrKT1cInJlc2V0RmlsdGVyKClcIiAqbmdJZj1cImZpbHRlckNyaXRlcmlhQ291bnRcIj5cbiAgICAgICAgPG1hdC1pY29uIGNvbG9yPVwiYWNjZW50XCI+ZmlsdGVyX2xpc3RfYWx0PC9tYXQtaWNvbj5cbiAgICAgICAgPG1hdC1pY29uIGNsYXNzPVwiaWNvbi1zZWNvbmRhcnlcIiBzdHlsZT1cImxlZnQ6IDE2cHg7IHRvcDogNXB4OyBmb250LXdlaWdodDogYm9sZFwiPmNsb3NlPC9tYXQtaWNvbj5cbiAgICAgIDwvYnV0dG9uPlxuXG4gICAgICA8IS0tIHNob3cgZmlsdGVyIC0tPlxuICAgICAgPGJ1dHRvbiBtYXQtaWNvbi1idXR0b24gKGNsaWNrKT1cImZpbHRlckV4cGFuc2lvblBhbmVsLnRvZ2dsZSgpXCI+XG4gICAgICAgIDxtYXQtaWNvblxuICAgICAgICAgICpuZ0lmPVwiZmlsdGVyQ3JpdGVyaWFDb3VudDsgZWxzZSBlbXB0eUZpbHRlclwiXG4gICAgICAgICAgW21hdEJhZGdlXT1cImZpbHRlckNyaXRlcmlhQ291bnRcIlxuICAgICAgICAgIG1hdEJhZGdlQ29sb3I9XCJhY2NlbnRcIlxuICAgICAgICAgIG1hdEJhZGdlU2l6ZT1cInNtYWxsXCJcbiAgICAgICAgICBtYXRCYWRnZVBvc2l0aW9uPVwiYWJvdmUgYWZ0ZXJcIlxuICAgICAgICAgIGFyaWEtaGlkZGVuPVwiZmFsc2VcIlxuICAgICAgICA+XG4gICAgICAgICAgZmlsdGVyX2xpc3RfYWx0XG4gICAgICAgIDwvbWF0LWljb24+XG4gICAgICAgIDxuZy10ZW1wbGF0ZSAjZW1wdHlGaWx0ZXI+XG4gICAgICAgICAgPG1hdC1pY29uPmZpbHRlcl9saXN0X2FsdDwvbWF0LWljb24+XG4gICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICA8L2J1dHRvbj5cblxuICAgICAgPCEtLSBzYXZlIC0tPlxuICAgICAgPGJ1dHRvbiBtYXQtaWNvbi1idXR0b24gKm5nSWY9XCJtb2JpbGVcIiBbZGlzYWJsZWRdPVwiKGRpcnR5U3ViamVjdCB8IGFzeW5jKSAhPT0gdHJ1ZVwiIChjbGljayk9XCJzYXZlKClcIj5cbiAgICAgICAgPG1hdC1pY29uPnNhdmU8L21hdC1pY29uPlxuICAgICAgPC9idXR0b24+XG5cbiAgICAgIDwhLS0gc3RhcnQvc3RvcCB0aW1lciB0byBhdXRvLWxvYWQgZGF0YSAtLT5cbiAgICAgIDxpb24tYnV0dG9uICpuZ0lmPVwiIXRpbWVyXCIgKGNsaWNrKT1cInN0YXJ0VGltZXIoKVwiPlN0YXJ0IHJlbG9hZDwvaW9uLWJ1dHRvbj5cbiAgICAgIDxpb24tYnV0dG9uICpuZ0lmPVwidGltZXJcIiAoY2xpY2spPVwic3RvcFRpbWVyKClcIiBjb2xvcj1cImFjY2VudFwiPlN0b3AgcmVsb2FkPC9pb24tYnV0dG9uPlxuICAgIH0gQGVsc2Uge1xuICAgICAgPCEtLSBpZiByb3cgc2VsZWN0aW9uIC0tPlxuICAgICAgPCEtLSBkZWxldGUgLS0+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIG1hdC1pY29uLWJ1dHRvblxuICAgICAgICAqbmdJZj1cImNhbkVkaXRcIlxuICAgICAgICBbdGl0bGVdPVwiJ0NPTU1PTi5CVE5fREVMRVRFJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgIChjbGljayk9XCJkZWxldGVTZWxlY3Rpb24oJGV2ZW50KVwiXG4gICAgICA+XG4gICAgICAgIDxtYXQtaWNvbj5kZWxldGU8L21hdC1pY29uPlxuICAgICAgPC9idXR0b24+XG5cbiAgICAgIDwhLS0gZHVwbGljYXRlIC0tPlxuICAgICAgPGJ1dHRvblxuICAgICAgICBtYXQtaWNvbi1idXR0b25cbiAgICAgICAgKm5nSWY9XCJjYW5FZGl0ICYmIHNlbGVjdGlvbi5zZWxlY3RlZCB8IGlzQXJyYXlMZW5ndGg6IHsgZXF1YWxzOiAxIH1cIlxuICAgICAgICBbdGl0bGVdPVwiJ0NPTU1PTi5CVE5fRFVQTElDQVRFJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgIChjbGljayk9XCJkdXBsaWNhdGVSb3coJGV2ZW50LCBzZWxlY3Rpb24uc2VsZWN0ZWRbMF0pXCJcbiAgICAgID5cbiAgICAgICAgPG1hdC1pY29uPmZpbGVfY29weTwvbWF0LWljb24+XG4gICAgICA8L2J1dHRvbj5cbiAgICB9XG4gIDwvaW9uLWJ1dHRvbnM+XG48L2FwcC10b29sYmFyPlxuPGlvbi1jb250ZW50IGNsYXNzPVwiaW9uLW5vLXBhZGRpbmdcIj5cbiAgPGlvbi1yZWZyZXNoZXIgc2xvdD1cImZpeGVkXCIgKm5nSWY9XCJtb2JpbGVcIiAoaW9uUmVmcmVzaCk9XCJkb1JlZnJlc2goJGV2ZW50KVwiPlxuICAgIDxpb24tcmVmcmVzaGVyLWNvbnRlbnQ+PC9pb24tcmVmcmVzaGVyLWNvbnRlbnQ+XG4gIDwvaW9uLXJlZnJlc2hlcj5cblxuICA8IS0tIGVycm9yIC0tPlxuICA8aW9uLWl0ZW0gKm5nSWY9XCJtb2JpbGUgJiYgZXJyb3JcIiBsaW5lcz1cIm5vbmVcIiBAc2xpZGVVcERvd25BbmltYXRpb24+XG4gICAgPGlvbi1pY29uIGNvbG9yPVwiZGFuZ2VyXCIgc2xvdD1cInN0YXJ0XCIgbmFtZT1cImFsZXJ0LWNpcmNsZVwiPjwvaW9uLWljb24+XG4gICAgPGlvbi1sYWJlbCBjb2xvcj1cImRhbmdlclwiIGNsYXNzPVwiZXJyb3JcIiBbaW5uZXJIVE1MXT1cImVycm9yIHwgdHJhbnNsYXRlXCI+PC9pb24tbGFiZWw+XG4gIDwvaW9uLWl0ZW0+XG5cbiAgPCEtLSBzZWFyY2ggLS0+XG4gIDxtYXQtZXhwYW5zaW9uLXBhbmVsXG4gICAgI2ZpbHRlckV4cGFuc2lvblBhbmVsXG4gICAgY2xhc3M9XCJmaWx0ZXItcGFuZWxcIlxuICAgIFtjbGFzcy5maWx0ZXItcGFuZWwtZmxvYXRpbmddPVwiZmlsdGVyUGFuZWxGbG9hdGluZ1wiXG4gICAgW2NsYXNzLmZpbHRlci1wYW5lbC1waW5uZWRdPVwiIWZpbHRlclBhbmVsRmxvYXRpbmdcIlxuICA+XG4gICAgPGZvcm0gY2xhc3M9XCJmb3JtLWNvbnRhaW5lciBpb24tcGFkZGluZy10b3BcIiBbZm9ybUdyb3VwXT1cImZpbHRlckZvcm1cIiAobmdTdWJtaXQpPVwiYXBwbHlGaWx0ZXJBbmRDbG9zZVBhbmVsKCRldmVudClcIj5cbiAgICAgIDxpb24tZ3JpZD5cbiAgICAgICAgPGlvbi1yb3c+XG4gICAgICAgICAgPGlvbi1jb2w+XG4gICAgICAgICAgICA8IS0tIHNlYXJjaCB0ZXh0IC0tPlxuICAgICAgICAgICAgPG1hdC1mb3JtLWZpZWxkPlxuICAgICAgICAgICAgICA8bWF0LWxhYmVsPnt7ICdUQUJMRS5URVNUSU5HLlNFQVJDSF9URVhUJyB8IHRyYW5zbGF0ZSB9fTwvbWF0LWxhYmVsPlxuICAgICAgICAgICAgICA8aW9uLWljb24gbWF0UHJlZml4IG5hbWU9XCJzZWFyY2hcIj48L2lvbi1pY29uPlxuICAgICAgICAgICAgICA8aW5wdXQgbWF0SW5wdXQgZm9ybUNvbnRyb2xOYW1lPVwic2VhcmNoVGV4dFwiIGF1dG9jb21wbGV0ZT1cIm9mZlwiIC8+XG4gICAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICBtYXQtaWNvbi1idXR0b25cbiAgICAgICAgICAgICAgICBtYXRTdWZmaXhcbiAgICAgICAgICAgICAgICB0YWJpbmRleD1cIi0xXCJcbiAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwiY2xlYXJDb250cm9sVmFsdWUoJGV2ZW50LCBmaWx0ZXJGb3JtLmNvbnRyb2xzLnNlYXJjaFRleHQpXCJcbiAgICAgICAgICAgICAgICBbaGlkZGVuXT1cImZpbHRlckZvcm0uY29udHJvbHMuc2VhcmNoVGV4dC5kaXNhYmxlZCB8fCAhZmlsdGVyRm9ybS5jb250cm9scy5zZWFyY2hUZXh0LnZhbHVlXCJcbiAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgIDxtYXQtaWNvbj5jbG9zZTwvbWF0LWljb24+XG4gICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICA8L2lvbi1jb2w+XG4gICAgICAgIDwvaW9uLXJvdz5cbiAgICAgIDwvaW9uLWdyaWQ+XG4gICAgPC9mb3JtPlxuXG4gICAgPG1hdC1hY3Rpb24tcm93PlxuICAgICAgPCEtLSBDb3VudGVyICAtLT5cbiAgICAgIDxpb24tbGFiZWxcbiAgICAgICAgW2hpZGRlbl09XCIobG9hZGluZ1N1YmplY3QgfCBhc3luYykgfHwgZmlsdGVyRm9ybS5kaXJ0eVwiXG4gICAgICAgIFtjb2xvcl09XCJlbXB0eSAmJiAnZGFuZ2VyJ1wiXG4gICAgICAgIGNsYXNzPVwiaW9uLXBhZGRpbmdcIlxuICAgICAgPlxuICAgICAgICB7e1xuICAgICAgICAgICh0b3RhbFJvd0NvdW50ID8gJ0NPTU1PTi5SRVNVTFRfQ09VTlQnIDogJ0NPTU1PTi5OT19SRVNVTFQnKVxuICAgICAgICAgICAgfCB0cmFuc2xhdGVcbiAgICAgICAgICAgICAgOiB7XG4gICAgICAgICAgICAgICAgICBjb3VudDogKHRvdGFsUm93Q291bnQgfCBudW1iZXJGb3JtYXQpXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICB9fVxuICAgICAgPC9pb24tbGFiZWw+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJ0b29sYmFyLXNwYWNlclwiPjwvZGl2PlxuXG4gICAgICA8YnV0dG9uXG4gICAgICAgIG1hdC1pY29uLWJ1dHRvblxuICAgICAgICBjb2xvcj1cImFjY2VudFwiXG4gICAgICAgICpuZ0lmPVwiZmlsdGVyUGFuZWxGbG9hdGluZ1wiXG4gICAgICAgIChjbGljayk9XCJ0b2dnbGVGaWx0ZXJQYW5lbEZsb2F0aW5nKClcIlxuICAgICAgICBjbGFzcz1cImhpZGRlbi14cyBoaWRkZW4tc20gaGlkZGVuLW1kXCJcbiAgICAgICAgW3RpdGxlXT1cIihmaWx0ZXJQYW5lbEZsb2F0aW5nID8gJ0NPTU1PTi5CVE5fRVhQQU5EJyA6ICdDT01NT04uQlROX0hJREUnKSB8IHRyYW5zbGF0ZVwiXG4gICAgICA+XG4gICAgICAgIDxtYXQtaWNvbj5cbiAgICAgICAgICA8c3BhbiBzdHlsZT1cInRyYW5zZm9ybTogcm90YXRlKDkwZGVnKVwiPnt7IGZpbHRlclBhbmVsRmxvYXRpbmcgPyAnJiN4YmI7JyA6ICcmI3hhYjsnIH19PC9zcGFuPlxuICAgICAgICA8L21hdC1pY29uPlxuICAgICAgPC9idXR0b24+XG5cbiAgICAgIDwhLS0gQ2xvc2UgcGFuZWwgLS0+XG4gICAgICA8aW9uLWJ1dHRvbiBtYXQtYnV0dG9uIGZpbGw9XCJjbGVhclwiIGNvbG9yPVwiZGFya1wiIChjbGljayk9XCJjbG9zZUZpbHRlclBhbmVsKClcIiBbZGlzYWJsZWRdPVwibG9hZGluZ1N1YmplY3QgfCBhc3luY1wiPlxuICAgICAgICA8aW9uLXRleHQgdHJhbnNsYXRlPkNPTU1PTi5CVE5fQ0xPU0U8L2lvbi10ZXh0PlxuICAgICAgPC9pb24tYnV0dG9uPlxuXG4gICAgICA8IS0tIFNlYXJjaCBidXR0b24gLS0+XG4gICAgICA8aW9uLWJ1dHRvblxuICAgICAgICBtYXQtYnV0dG9uXG4gICAgICAgIFtjb2xvcl09XCJmaWx0ZXJGb3JtLmRpcnR5ID8gJ3RlcnRpYXJ5JyA6ICdkYXJrJ1wiXG4gICAgICAgIFtmaWxsXT1cImZpbHRlckZvcm0uZGlydHkgPyAnc29saWQnIDogJ2NsZWFyJ1wiXG4gICAgICAgIChjbGljayk9XCJhcHBseUZpbHRlckFuZENsb3NlUGFuZWwoJGV2ZW50KVwiXG4gICAgICA+XG4gICAgICAgIDxpb24tdGV4dCB0cmFuc2xhdGU+Q09NTU9OLkJUTl9BUFBMWTwvaW9uLXRleHQ+XG4gICAgICA8L2lvbi1idXR0b24+XG4gICAgPC9tYXQtYWN0aW9uLXJvdz5cbiAgPC9tYXQtZXhwYW5zaW9uLXBhbmVsPlxuXG4gIDwhLS0gdGFibGUgLS0+XG4gIDxkaXYgW2NsYXNzLnRhYmxlLWNvbnRhaW5lcl09XCIhZW5hYmxlSW5maW5pdGVTY3JvbGxcIj5cbiAgICA8dGFibGVcbiAgICAgICN0YWJsZVxuICAgICAgbWF0LXRhYmxlXG4gICAgICBtYXRTb3J0XG4gICAgICBtYXRTb3J0RGlzYWJsZUNsZWFyXG4gICAgICBbZGF0YVNvdXJjZV09XCJkYXRhU291cmNlXCJcbiAgICAgIFttYXRTb3J0QWN0aXZlXT1cImRlZmF1bHRTb3J0QnlcIlxuICAgICAgW21hdFNvcnREaXJlY3Rpb25dPVwiZGVmYXVsdFNvcnREaXJlY3Rpb25cIlxuICAgICAgW3RyYWNrQnldPVwidHJhY2tCeUZuXCJcbiAgICAgIFtzdHlsZS4tLW1hdC1yb3ctaGVpZ2h0XT1cInJvd0hlaWdodCArICdweCdcIlxuICAgID5cbiAgICAgIDwhLS0gZ3JvdXAgaGVhZGVyIGNlbGxzIC0tPlxuICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJ0b3Atc3RhcnRcIiBbc3RpY2t5XT1cInN0aWNreVwiPlxuICAgICAgICA8dGggbWF0LWhlYWRlci1jZWxsICptYXRIZWFkZXJDZWxsRGVmIFtjbGFzcy5jZGstdmlzdWFsbHktaGlkZGVuXT1cIiFjYW5FZGl0XCIgW2F0dHIuY29sc3Bhbl09XCIyXCI+XG4gICAgICAgICAgPCEtLSBzdGFydCBzcGFjZXIgLS0+XG4gICAgICAgIDwvdGg+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJncm91cC0xXCI+XG4gICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgKm1hdEhlYWRlckNlbGxEZWYgW2F0dHIuY29sc3Bhbl09XCIzXCI+XG4gICAgICAgICAgPGlvbi1sYWJlbCB0cmFuc2xhdGU+e3sgaTE4bkNvbHVtblByZWZpeCArICdHUk9VUF8xJyB9fTwvaW9uLWxhYmVsPlxuICAgICAgICA8L3RoPlxuICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgIDxuZy1jb250YWluZXIgbWF0Q29sdW1uRGVmPVwiZ3JvdXAtMlwiPlxuICAgICAgICA8dGggbWF0LWhlYWRlci1jZWxsICptYXRIZWFkZXJDZWxsRGVmIFthdHRyLmNvbHNwYW5dPVwiZGlzcGxheWVkQ29sdW1ucy5sZW5ndGggLSA2XCI+XG4gICAgICAgICAgPGlvbi1sYWJlbCB0cmFuc2xhdGU+e3sgaTE4bkNvbHVtblByZWZpeCArICdHUk9VUF8yJyB9fTwvaW9uLWxhYmVsPlxuICAgICAgICA8L3RoPlxuICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgIDxuZy1jb250YWluZXIgbWF0Q29sdW1uRGVmPVwidG9wLWVuZFwiIFtzdGlja3lFbmRdPVwic3RpY2t5RW5kXCI+XG4gICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgKm1hdEhlYWRlckNlbGxEZWY+XG4gICAgICAgICAgPCEtLSBlbmQgc3BhY2VyIC0tPlxuICAgICAgICAgIDxpb24tbGFiZWw+PC9pb24tbGFiZWw+XG4gICAgICAgIDwvdGg+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJzZWxlY3RcIiBbc3RpY2t5XT1cInN0aWNreVwiIFtjbGFzcy5tYXQtY29sdW1uLXN0aWNreV09XCJzdGlja3lcIj5cbiAgICAgICAgPHRoIG1hdC1oZWFkZXItY2VsbCAqbWF0SGVhZGVyQ2VsbERlZiBbY2xhc3MuY2RrLXZpc3VhbGx5LWhpZGRlbl09XCIhY2FuRWRpdFwiPlxuICAgICAgICAgIEBpZiAoc2VsZWN0aW9uIHwgaXNNdWx0aXBsZVNlbGVjdGlvbikge1xuICAgICAgICAgICAgPG1hdC1jaGVja2JveFxuICAgICAgICAgICAgICBbY2hlY2tlZF09XCJ0aGlzIHwgaXNBbGxTZWxlY3RlZFwiXG4gICAgICAgICAgICAgIFtpbmRldGVybWluYXRlXT1cInRoaXMgfCBpc05vdEFsbFNlbGVjdGVkXCJcbiAgICAgICAgICAgICAgKGNoYW5nZSk9XCIkZXZlbnQgPyBtYXN0ZXJUb2dnbGUoKSA6IG51bGxcIlxuICAgICAgICAgICAgPjwvbWF0LWNoZWNrYm94PlxuICAgICAgICAgIH1cbiAgICAgICAgPC90aD5cbiAgICAgICAgPHRkIG1hdC1jZWxsICptYXRDZWxsRGVmPVwibGV0IHJvd1wiIFtjbGFzcy5jZGstdmlzdWFsbHktaGlkZGVuXT1cIiFjYW5FZGl0XCI+XG4gICAgICAgICAgPG1hdC1jaGVja2JveCBbY2hlY2tlZF09XCJzZWxlY3Rpb24gfCBpc1NlbGVjdGVkOiByb3dcIiAoY2xpY2spPVwidG9nZ2xlU2VsZWN0Um93KCRldmVudCwgcm93KVwiPjwvbWF0LWNoZWNrYm94PlxuICAgICAgICA8L3RkPlxuICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgIDwhLS0gSWQgY29sdW1uIC0tPlxuICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJpZFwiIFtzdGlja3ldPVwic3RpY2t5XCIgW2NsYXNzLm1hdC1jb2x1bW4tc3RpY2t5XT1cInN0aWNreVwiPlxuICAgICAgICA8dGggbWF0LWhlYWRlci1jZWxsICptYXRIZWFkZXJDZWxsRGVmIG1hdC1zb3J0LWhlYWRlcj5cbiAgICAgICAgICA8aW9uLWxhYmVsPiM8L2lvbi1sYWJlbD5cbiAgICAgICAgPC90aD5cbiAgICAgICAgPHRkIG1hdC1jZWxsICptYXRDZWxsRGVmPVwibGV0IHJvd1wiPnt7IHJvdy5jdXJyZW50RGF0YT8uaWQgfX08L3RkPlxuICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgIDwhLS0gTGFiZWwgY29sdW1uIC0tPlxuICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJsYWJlbFwiPlxuICAgICAgICA8dGggbWF0LWhlYWRlci1jZWxsICptYXRIZWFkZXJDZWxsRGVmIG1hdC1zb3J0LWhlYWRlcj5cbiAgICAgICAgICA8aW9uLWxhYmVsIHRyYW5zbGF0ZT5UQUJMRS5URVNUSU5HLkxBQkVMPC9pb24tbGFiZWw+XG4gICAgICAgIDwvdGg+XG4gICAgICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCByb3dcIiAoY2xpY2spPVwiZm9jdXNDb2x1bW4gPSAnbGFiZWwnXCI+XG4gICAgICAgICAgPG1hdC1mb3JtLWZpZWxkICpuZ0lmPVwicm93LmVkaXRpbmc7IGVsc2UgcmVhZG9ubHlDZWxsXCIgW2hpZGVSZXF1aXJlZE1hcmtlcl09XCJmYWxzZVwiPlxuICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgIG1hdElucHV0XG4gICAgICAgICAgICAgIGF1dG9jb21wbGV0ZT1cIm9mZlwiXG4gICAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCJyb3cudmFsaWRhdG9yLmNvbnRyb2xzWydsYWJlbCddXCJcbiAgICAgICAgICAgICAgW3BsYWNlaG9sZGVyXT1cIidUQUJMRS5URVNUSU5HLkxBQkVMJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICAgIFthcHBBdXRvZm9jdXNdPVwicm93LmVkaXRpbmcgJiYgZm9jdXNDb2x1bW4gPT09ICdsYWJlbCdcIlxuICAgICAgICAgICAgICBbcmVhZG9ubHldPVwiIXJvdy5lZGl0aW5nXCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgICAgICA8bWF0LWVycm9yICpuZ0lmPVwicm93LnZhbGlkYXRvci5jb250cm9sc1snbGFiZWwnXS5oYXNFcnJvcigncmVxdWlyZWQnKVwiIHRyYW5zbGF0ZT5cbiAgICAgICAgICAgICAgRVJST1IuRklFTERfUkVRVUlSRURcbiAgICAgICAgICAgIDwvbWF0LWVycm9yPlxuICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgICAgICAgPG5nLXRlbXBsYXRlICNyZWFkb25seUNlbGw+XG4gICAgICAgICAgICA8aW9uLWxhYmVsIGFwcEF1dG9UaXRsZT5cbiAgICAgICAgICAgICAge3sgcm93LnZhbGlkYXRvciB8IGZvcm1HZXRWYWx1ZTogJ2xhYmVsJyB9fVxuICAgICAgICAgICAgPC9pb24tbGFiZWw+XG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgPC90ZD5cbiAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICA8IS0tIE5hbWUgY29sdW1uIC0tPlxuICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJuYW1lXCI+XG4gICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgKm1hdEhlYWRlckNlbGxEZWYgbWF0LXNvcnQtaGVhZGVyPlxuICAgICAgICAgIDxpb24tbGFiZWwgdHJhbnNsYXRlPlRBQkxFLlRFU1RJTkcuTkFNRTwvaW9uLWxhYmVsPlxuICAgICAgICA8L3RoPlxuICAgICAgICA8dGQgbWF0LWNlbGwgKm1hdENlbGxEZWY9XCJsZXQgcm93XCIgKGNsaWNrKT1cImZvY3VzQ29sdW1uID0gJ25hbWUnXCI+XG4gICAgICAgICAgPG1hdC1mb3JtLWZpZWxkICpuZ0lmPVwicm93LmVkaXRpbmc7IGVsc2UgcmVhZG9ubHlDZWxsXCI+XG4gICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgbWF0SW5wdXRcbiAgICAgICAgICAgICAgW2Zvcm1Db250cm9sXT1cInJvdy52YWxpZGF0b3I/LmNvbnRyb2xzLm5hbWVcIlxuICAgICAgICAgICAgICBbcGxhY2Vob2xkZXJdPVwiJ1RBQkxFLlRFU1RJTkcuTkFNRScgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgICBbYXBwQXV0b2ZvY3VzXT1cInJvdy5lZGl0aW5nICYmIGZvY3VzQ29sdW1uID09PSAnbmFtZSdcIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIDxtYXQtZXJyb3IgKm5nSWY9XCJyb3cudmFsaWRhdG9yPy5jb250cm9scy5uYW1lLmhhc0Vycm9yKCdyZXF1aXJlZCcpXCIgdHJhbnNsYXRlPlxuICAgICAgICAgICAgICBFUlJPUi5GSUVMRF9SRVFVSVJFRFxuICAgICAgICAgICAgPC9tYXQtZXJyb3I+XG4gICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgI3JlYWRvbmx5Q2VsbD5cbiAgICAgICAgICAgIDxpb24tbGFiZWwgYXBwQXV0b1RpdGxlPlxuICAgICAgICAgICAgICB7eyByb3cudmFsaWRhdG9yIHwgZm9ybUdldFZhbHVlOiAnbmFtZScgfX1cbiAgICAgICAgICAgIDwvaW9uLWxhYmVsPlxuICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgIDwvdGQ+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgPCEtLSBMZXZlbCBjb2x1bW4gLS0+XG4gICAgICA8bmctY29udGFpbmVyIG1hdENvbHVtbkRlZj1cImxldmVsSWRcIj5cbiAgICAgICAgPHRoIG1hdC1oZWFkZXItY2VsbCAqbWF0SGVhZGVyQ2VsbERlZiBtYXQtc29ydC1oZWFkZXI+XG4gICAgICAgICAgPGlvbi1sYWJlbCB0cmFuc2xhdGU+VEFCTEUuVEVTVElORy5MRVZFTF9JRDwvaW9uLWxhYmVsPlxuICAgICAgICA8L3RoPlxuICAgICAgICA8dGQgbWF0LWNlbGwgKm1hdENlbGxEZWY9XCJsZXQgcm93XCIgKGNsaWNrKT1cImZvY3VzQ29sdW1uID0gJ2xldmVsSWQnXCI+XG4gICAgICAgICAgPG1hdC1hdXRvY29tcGxldGUtZmllbGRcbiAgICAgICAgICAgICpuZ0lmPVwicm93LmVkaXRpbmc7IGVsc2UgcmVhZG9ubHlDZWxsXCJcbiAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCJyb3cudmFsaWRhdG9yLmNvbnRyb2xzLmxldmVsSWRcIlxuICAgICAgICAgICAgW3BsYWNlaG9sZGVyXT1cIidUQUJMRS5URVNUSU5HLkxFVkVMX0lEJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICBmbG9hdExhYmVsPVwibmV2ZXJcIlxuICAgICAgICAgICAgW2NvbmZpZ109XCJhdXRvY29tcGxldGVGaWVsZHMubGV2ZWxcIlxuICAgICAgICAgICAgW3JlYWRvbmx5XT1cIiFyb3cuZWRpdGluZ1wiXG4gICAgICAgICAgICBbYXV0b2ZvY3VzXT1cImZvY3VzQ29sdW1uID09PSAnbGV2ZWxJZCdcIlxuICAgICAgICAgICAgW3JlcXVpcmVkXT1cInRydWVcIlxuICAgICAgICAgID48L21hdC1hdXRvY29tcGxldGUtZmllbGQ+XG4gICAgICAgICAgPG5nLXRlbXBsYXRlICNyZWFkb25seUNlbGw+XG4gICAgICAgICAgICA8aW9uLWxhYmVsIGFwcEF1dG9UaXRsZT5cbiAgICAgICAgICAgICAge3sgcm93LnZhbGlkYXRvciB8IGZvcm1HZXRWYWx1ZTogJ2xldmVsSWQnIHwgcmVmZXJlbnRpYWxUb1N0cmluZzogYXV0b2NvbXBsZXRlRmllbGRzLmxldmVsLmF0dHJpYnV0ZXMgfX1cbiAgICAgICAgICAgIDwvaW9uLWxhYmVsPlxuICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgIDwvdGQ+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgPCEtLSBTdGF0dXMgY29sdW1uICAtLT5cbiAgICAgIDxuZy1jb250YWluZXIgbWF0Q29sdW1uRGVmPVwic3RhdHVzSWRcIj5cbiAgICAgICAgPHRoIG1hdC1oZWFkZXItY2VsbCAqbWF0SGVhZGVyQ2VsbERlZj5cbiAgICAgICAgICA8c3BhbiB0cmFuc2xhdGU+VVNFUi5TVEFUVVM8L3NwYW4+XG4gICAgICAgIDwvdGg+XG4gICAgICAgIDx0ZFxuICAgICAgICAgIG1hdC1jZWxsXG4gICAgICAgICAgKm1hdENlbGxEZWY9XCJsZXQgcm93XCJcbiAgICAgICAgICBbY2xhc3MubWF0LWZvcm0tZmllbGQtZGlzYWJsZWRdPVwiIXJvdy5lZGl0aW5nXCJcbiAgICAgICAgICAoY2xpY2spPVwiZm9jdXNDb2x1bW4gPSAnc3RhdHVzSWQnXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxtYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICAgIDxtYXQtc2VsZWN0XG4gICAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCJyb3cudmFsaWRhdG9yLmNvbnRyb2xzWydzdGF0dXNJZCddXCJcbiAgICAgICAgICAgICAgW3BsYWNlaG9sZGVyXT1cImkxOG5Db2x1bW5QcmVmaXggKyAnU1RBVFVTX0lEJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDxtYXQtb3B0aW9uICpuZ0Zvcj1cImxldCBpdGVtIG9mIHN0YXR1c0xpc3RcIiBbdmFsdWVdPVwiaXRlbS5pZFwiPlxuICAgICAgICAgICAgICAgIDxtYXQtaWNvbj48aW9uLWljb24gW25hbWVdPVwiaXRlbS5pY29uXCI+PC9pb24taWNvbj48L21hdC1pY29uPlxuICAgICAgICAgICAgICAgIDxtYXQtbGFiZWw+e3sgaXRlbS5sYWJlbCB8IHRyYW5zbGF0ZSB9fTwvbWF0LWxhYmVsPlxuICAgICAgICAgICAgICA8L21hdC1vcHRpb24+XG4gICAgICAgICAgICA8L21hdC1zZWxlY3Q+XG4gICAgICAgICAgICA8bWF0LWVycm9yICpuZ0lmPVwicm93LnZhbGlkYXRvci5jb250cm9sc1snc3RhdHVzSWQnXS5oYXNFcnJvcigncmVxdWlyZWQnKVwiIHRyYW5zbGF0ZT5cbiAgICAgICAgICAgICAgRVJST1IuRklFTERfUkVRVUlSRURcbiAgICAgICAgICAgIDwvbWF0LWVycm9yPlxuICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgICAgIDwvdGQ+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgPCEtLSBFbnVtIGNvbHVtbiAgLS0+XG4gICAgICA8IS0tIE5PVEUgOiBOZXZlciB1c2VkIGluIHRhYmxlICAtLT5cbiAgICAgIDwhLS0gICAgICA8bmctY29udGFpbmVyIG1hdENvbHVtbkRlZj1cInZhbHVlc1wiPi0tPlxuICAgICAgPCEtLSAgICAgICAgPHRoIG1hdC1oZWFkZXItY2VsbCAqbWF0SGVhZGVyQ2VsbERlZj4tLT5cbiAgICAgIDwhLS0gICAgICAgICAgPHNwYW4gdHJhbnNsYXRlPkVudW1zPC9zcGFuPi0tPlxuICAgICAgPCEtLSAgICAgICAgPC90aD4tLT5cbiAgICAgIDwhLS0gICAgICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCByb3dcIiBbY2xhc3MubWF0LWZvcm0tZmllbGQtZGlzYWJsZWRdPVwiIXJvdy5lZGl0aW5nXCI+LS0+XG4gICAgICA8IS0tICAgICAgICAgIDxhcHAtZm9ybS1maWVsZC0tPlxuICAgICAgPCEtLSAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCJyb3cudmFsaWRhdG9yfGZvcm1HZXRDb250cm9sOidwcm9wZXJ0aWVzLnZhbHVlcydcIi0tPlxuICAgICAgPCEtLSAgICAgICAgICAgIFtkZWZpbml0aW9uXT1cImNvbHVtbkRlZmluaXRpb25zWyd2YWx1ZXMnXVwiLS0+XG4gICAgICA8IS0tICAgICAgICAgID48L2FwcC1mb3JtLWZpZWxkPi0tPlxuICAgICAgPCEtLSAgICAgICAgPC90ZD4tLT5cbiAgICAgIDwhLS0gICAgICA8L25nLWNvbnRhaW5lcj4tLT5cblxuICAgICAgPCEtLSBib29sZWFuIChhcyBjaGVja2JveCkgLS0+XG4gICAgICA8bmctY29udGFpbmVyIG1hdENvbHVtbkRlZj1cImJvb2xlYW5cIj5cbiAgICAgICAgPHRoIG1hdC1oZWFkZXItY2VsbCAqbWF0SGVhZGVyQ2VsbERlZiBjZGtEcmFnIFtyZXNpemFibGVdPVwidHJ1ZVwiPlxuICAgICAgICAgIDwhLS0gaWYgc29ydGFibGUsIHdyYXAgdGhlIGhlYWRlciB3aXRoIGEgbWF0LXNvcnQtaGVhZGVyIC0tPlxuICAgICAgICAgIDxzcGFuIG1hdC1zb3J0LWhlYWRlcj5cbiAgICAgICAgICAgIDxpb24tbGFiZWw+Qm9vbGVhbjwvaW9uLWxhYmVsPlxuICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgPC90aD5cbiAgICAgICAgPHRkIG1hdC1jZWxsICptYXRDZWxsRGVmPVwibGV0IHJvd1wiPlxuICAgICAgICAgIDxtYXQtYm9vbGVhbi1maWVsZFxuICAgICAgICAgICAgKm5nSWY9XCIhcmVhZE9ubHkgJiYgcm93LmVkaXRpbmc7IGVsc2UgcmVhZE9ubHlUZW1wbGF0ZVwiXG4gICAgICAgICAgICBmbG9hdExhYmVsPVwibmV2ZXJcIlxuICAgICAgICAgICAgW3N0eWxlXT1cIidjaGVja2JveCdcIlxuICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJPdWkvTm9uXCJcbiAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCJyb3cudmFsaWRhdG9yIHwgZm9ybUdldENvbnRyb2w6ICdwcm9wZXJ0aWVzLmJvb2xlYW4nXCJcbiAgICAgICAgICAgIFtjb21wYWN0XT1cInRydWVcIlxuICAgICAgICAgID48L21hdC1ib29sZWFuLWZpZWxkPlxuICAgICAgICAgIDxuZy10ZW1wbGF0ZSAjcmVhZE9ubHlUZW1wbGF0ZT5cbiAgICAgICAgICAgIDxpb24tbGFiZWwgYXBwQXV0b1RpdGxlPlxuICAgICAgICAgICAgICB7eyAocm93LnZhbGlkYXRvciB8IGZvcm1HZXRWYWx1ZTogJ3Byb3BlcnRpZXMuYm9vbGVhbicpID8gJyYjeDI3MTQ7JyA6ICcmI3gyNzE4OycgfX1cbiAgICAgICAgICAgIDwvaW9uLWxhYmVsPlxuICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgIDwvdGQ+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgPCEtLSBkYXRlIC0tPlxuICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJkYXRlXCI+XG4gICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgKm1hdEhlYWRlckNlbGxEZWYgY2RrRHJhZyBbcmVzaXphYmxlXT1cInRydWVcIiBjbGFzcz1cIm1hdC1jZWxsLWRhdGUtdGltZVwiPlxuICAgICAgICAgIDwhLS0gaWYgc29ydGFibGUsIHdyYXAgdGhlIGhlYWRlciB3aXRoIGEgbWF0LXNvcnQtaGVhZGVyIC0tPlxuICAgICAgICAgIDxzcGFuIG1hdC1zb3J0LWhlYWRlcj5cbiAgICAgICAgICAgIDxpb24tbGFiZWw+RGF0ZTwvaW9uLWxhYmVsPlxuICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgPC90aD5cbiAgICAgICAgPHRkIG1hdC1jZWxsICptYXRDZWxsRGVmPVwibGV0IHJvd1wiIGNsYXNzPVwibWF0LWNlbGwtZGF0ZS10aW1lXCIgKGNsaWNrKT1cImZvY3VzQ29sdW1uID0gJ2RhdGUnXCI+XG4gICAgICAgICAgPG1hdC1kYXRlLXRpbWUtZmllbGRcbiAgICAgICAgICAgICpuZ0lmPVwiXG4gICAgICAgICAgICAgICFyZWFkT25seSAmJiByb3cuZWRpdGluZyAmJiByb3cudmFsaWRhdG9yIHwgZm9ybUdldENvbnRyb2w6ICdwcm9wZXJ0aWVzLmRhdGUnO1xuICAgICAgICAgICAgICBsZXQgZGF0ZUNvbnRyb2w7XG4gICAgICAgICAgICAgIGVsc2U6IHJlYWRPbmx5VGVtcGxhdGVcbiAgICAgICAgICAgIFwiXG4gICAgICAgICAgICBmbG9hdExhYmVsPVwibmV2ZXJcIlxuICAgICAgICAgICAgW2Zvcm1Db250cm9sXT1cImRhdGVDb250cm9sXCJcbiAgICAgICAgICAgIFthdXRvZm9jdXNdPVwiZm9jdXNDb2x1bW4gPT09ICdkYXRlJ1wiXG4gICAgICAgICAgICBbY29tcGFjdF09XCJ0cnVlXCJcbiAgICAgICAgICA+PC9tYXQtZGF0ZS10aW1lLWZpZWxkPlxuICAgICAgICAgIDxuZy10ZW1wbGF0ZSAjcmVhZE9ubHlUZW1wbGF0ZT5cbiAgICAgICAgICAgIDxpb24tbGFiZWwgYXBwQXV0b1RpdGxlPlxuICAgICAgICAgICAgICB7eyByb3cudmFsaWRhdG9yIHwgZm9ybUdldFZhbHVlOiAncHJvcGVydGllcy5kYXRlJyB8IGRhdGVGb3JtYXQ6IHsgdGltZTogdHJ1ZSB9IH19XG4gICAgICAgICAgICA8L2lvbi1sYWJlbD5cbiAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICA8L3RkPlxuICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgIDwhLS0gbGF0aXR1ZGUgLS0+XG4gICAgICA8bmctY29udGFpbmVyIG1hdENvbHVtbkRlZj1cImxhdGl0dWRlXCI+XG4gICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgKm1hdEhlYWRlckNlbGxEZWYgY2RrRHJhZyBbcmVzaXphYmxlXT1cInRydWVcIj5cbiAgICAgICAgICA8IS0tIGlmIHNvcnRhYmxlLCB3cmFwIHRoZSBoZWFkZXIgd2l0aCBhIG1hdC1zb3J0LWhlYWRlciAtLT5cbiAgICAgICAgICA8c3BhbiBtYXQtc29ydC1oZWFkZXI+XG4gICAgICAgICAgICA8aW9uLWxhYmVsPkxhdGl0dWRlPC9pb24tbGFiZWw+XG4gICAgICAgICAgPC9zcGFuPlxuICAgICAgICA8L3RoPlxuICAgICAgICA8dGQgbWF0LWNlbGwgKm1hdENlbGxEZWY9XCJsZXQgcm93XCIgKGNsaWNrKT1cImZvY3VzQ29sdW1uID0gJ2xhdGl0dWRlJ1wiPlxuICAgICAgICAgIDxtYXQtbGF0bG9uZy1maWVsZFxuICAgICAgICAgICAgKm5nSWY9XCJcbiAgICAgICAgICAgICAgIXJlYWRPbmx5ICYmIHJvdy5lZGl0aW5nICYmIHJvdy52YWxpZGF0b3IgfCBmb3JtR2V0Q29udHJvbDogJ3Byb3BlcnRpZXMubGF0aXR1ZGUnO1xuICAgICAgICAgICAgICBsZXQgbGF0aXR1ZGVDb250cm9sO1xuICAgICAgICAgICAgICBlbHNlOiByZWFkT25seVRlbXBsYXRlXG4gICAgICAgICAgICBcIlxuICAgICAgICAgICAgZmxvYXRMYWJlbD1cIm5ldmVyXCJcbiAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCJsYXRpdHVkZUNvbnRyb2xcIlxuICAgICAgICAgICAgW2xhdExvbmdQYXR0ZXJuXT1cIidERE1NJ1wiXG4gICAgICAgICAgICBbYXV0b2ZvY3VzXT1cImZvY3VzQ29sdW1uID09PSAnbGF0aXR1ZGUnXCJcbiAgICAgICAgICA+PC9tYXQtbGF0bG9uZy1maWVsZD5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgI3JlYWRPbmx5VGVtcGxhdGU+XG4gICAgICAgICAgICA8aW9uLWxhYmVsIGFwcEF1dG9UaXRsZT5cbiAgICAgICAgICAgICAge3sgcm93LnZhbGlkYXRvciB8IGZvcm1HZXRWYWx1ZTogJ3Byb3BlcnRpZXMubGF0aXR1ZGUnIHwgbGF0aXR1ZGVGb3JtYXQgfX1cbiAgICAgICAgICAgIDwvaW9uLWxhYmVsPlxuICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgIDwvdGQ+XG4gICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgPCEtLSBDcmVhdGlvbiBkYXRlIGNvbHVtbiAtLT5cbiAgICAgIDxuZy1jb250YWluZXIgbWF0Q29sdW1uRGVmPVwidXBkYXRlRGF0ZVwiPlxuICAgICAgICA8dGggbWF0LWhlYWRlci1jZWxsICptYXRIZWFkZXJDZWxsRGVmIG1hdC1zb3J0LWhlYWRlcj5cbiAgICAgICAgICA8aW9uLWxhYmVsIHRyYW5zbGF0ZT5UQUJMRS5URVNUSU5HLlVQREFURV9EQVRFPC9pb24tbGFiZWw+XG4gICAgICAgIDwvdGg+XG4gICAgICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCByb3dcIiBjbGFzcz1cIm1hdC1mb3JtLWZpZWxkLWRpc2FibGVkXCI+XG4gICAgICAgICAgPGlvbi10ZXh0IGNvbG9yPVwibWVkaXVtXCIgKm5nSWY9XCJyb3cuaWQgIT09IC0xXCI+XG4gICAgICAgICAgICA8c21hbGw+XG4gICAgICAgICAgICAgIHt7IHJvdy52YWxpZGF0b3IgfCBmb3JtR2V0VmFsdWU6ICdjcmVhdGlvbkRhdGUnIHwgZGF0ZUZvcm1hdDogeyB0aW1lOiB0cnVlIH0gfX1cbiAgICAgICAgICAgIDwvc21hbGw+XG4gICAgICAgICAgPC9pb24tdGV4dD5cbiAgICAgICAgPC90ZD5cbiAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICA8IS0tIENvbW1lbnQgY29sdW1uIC0tPlxuICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJjb21tZW50c1wiPlxuICAgICAgICA8dGggbWF0LWhlYWRlci1jZWxsICptYXRIZWFkZXJDZWxsRGVmPlxuICAgICAgICAgIDxpb24tbGFiZWwgdHJhbnNsYXRlPlRBQkxFLlRFU1RJTkcuQ09NTUVOVFM8L2lvbi1sYWJlbD5cbiAgICAgICAgPC90aD5cbiAgICAgICAgPHRkIG1hdC1jZWxsICptYXRDZWxsRGVmPVwibGV0IHJvd1wiPlxuICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCAqbmdJZj1cInJvdy5lZGl0aW5nOyBlbHNlIGljb25Db21tZW50XCI+XG4gICAgICAgICAgICA8IS0tPHRleHRhcmVhIG1hdElucHV0IFtmb3JtQ29udHJvbF09XCJyb3cudmFsaWRhdG9yPy5jb250cm9scy5jb21tZW50c1wiXG4gICAgICAgICAgICAgICAgICAgICAgW3BsYWNlaG9sZGVyXT1cIidUQUJMRS5URVNUSU5HLkNPTU1FTlRTJ3x0cmFuc2xhdGVcIlxuICAgICAgICAgICAgICAgICAgICAgIFtyZWFkb25seV09XCIhcm93LmVkaXRpbmdcIj48L3RleHRhcmVhPi0tPlxuXG4gICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgdHlwZT1cInRleHRcIlxuICAgICAgICAgICAgICBtYXRJbnB1dFxuICAgICAgICAgICAgICBbZm9ybUNvbnRyb2xdPVwicm93LnZhbGlkYXRvcj8uY29udHJvbHMuY29tbWVudHNcIlxuICAgICAgICAgICAgICBbcGxhY2Vob2xkZXJdPVwiJ1RBQkxFLlRFU1RJTkcuQ09NTUVOVFMnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAgICAgW3JlYWRvbmx5XT1cIiFyb3cuZWRpdGluZ1wiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgI2ljb25Db21tZW50PlxuICAgICAgICAgICAgPGlvbi1pY29uXG4gICAgICAgICAgICAgIFtjb2xvcl09XCJyb3cudmFsaWRhdG9yPy5jb250cm9scy5jb21tZW50cy52YWx1ZSA/ICd0ZXJ0aWFyeScgOiAnbWVkaXVtJ1wiXG4gICAgICAgICAgICAgIG5hbWU9XCJjaGF0Ym94XCJcbiAgICAgICAgICAgICAgc2xvdD1cImljb24tb25seVwiXG4gICAgICAgICAgICA+PC9pb24taWNvbj5cbiAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICA8L3RkPlxuICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgIDwhLS0gQWN0aW9ucyBidXR0b25zIGNvbHVtbiAtLT5cbiAgICAgIDxhcHAtYWN0aW9ucy1jb2x1bW5cbiAgICAgICAgW3N0aWNreUVuZF09XCJzdGlja3lFbmRcIlxuICAgICAgICBbY2FuQ2FuY2VsXT1cImZhbHNlXCJcbiAgICAgICAgW3N0eWxlXT1cIid0YWJsZSdcIlxuICAgICAgICAob3B0aW9uc0NsaWNrKT1cIm9wZW5TZWxlY3RDb2x1bW5zTW9kYWwoJGV2ZW50KVwiXG4gICAgICAgIChjYW5jZWxPckRlbGV0ZUNsaWNrKT1cImNhbmNlbE9yRGVsZXRlKCRldmVudC5ldmVudCwgJGV2ZW50LnJvdylcIlxuICAgICAgICAoY29uZmlybUFuZEFkZENsaWNrKT1cImNvbmZpcm1BbmRBZGQoJGV2ZW50LmV2ZW50LCAkZXZlbnQucm93KVwiXG4gICAgICAgIChiYWNrd2FyZCk9XCJjb25maXJtQW5kQmFja3dhcmQoJGV2ZW50LmV2ZW50LCAkZXZlbnQucm93KVwiXG4gICAgICAgIChmb3J3YXJkKT1cImNvbmZpcm1BbmRGb3J3YXJkKCRldmVudC5ldmVudCwgJGV2ZW50LnJvdylcIlxuICAgICAgICBbY2VsbFRlbXBsYXRlXT1cImNlbGxJbmplY3Rpb25cIlxuICAgICAgPlxuICAgICAgICA8IS0tIGNlbGwgaW5qZWN0aW9uLS0+XG4gICAgICAgIDxuZy10ZW1wbGF0ZSAjY2VsbEluamVjdGlvbiBsZXQtcm93PlxuICAgICAgICAgIDxzcGFuICpuZ0lmPVwicm93LmVkaXRpbmcgJiYgIXJvdy52YWxpZGF0b3IuZGlydHlcIj4tPC9zcGFuPlxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgPC9hcHAtYWN0aW9ucy1jb2x1bW4+XG5cbiAgICAgIDx0ciBtYXQtaGVhZGVyLXJvdyAqbWF0SGVhZGVyUm93RGVmPVwiZ3JvdXBDb2x1bW5zXCI+PC90cj5cbiAgICAgIDx0ciBtYXQtaGVhZGVyLXJvdyAqbWF0SGVhZGVyUm93RGVmPVwiZGlzcGxheWVkQ29sdW1uczsgc3RpY2t5OiB0cnVlXCI+PC90cj5cbiAgICAgIDx0clxuICAgICAgICBtYXQtcm93XG4gICAgICAgICptYXRSb3dEZWY9XCJsZXQgcm93OyBjb2x1bW5zOiBkaXNwbGF5ZWRDb2x1bW5zXCJcbiAgICAgICAgW2NsYXNzLm1hdC1tZGMtcm93LXNlbGVjdGVkXT1cInJvdy5lZGl0aW5nXCJcbiAgICAgICAgW2NsYXNzLm1hdC1tZGMtcm93LWVycm9yXT1cInJvdy5pbnZhbGlkXCJcbiAgICAgICAgW2NsYXNzLm1hdC1tZGMtcm93LWRpc2FibGVkXT1cIiFyb3cuZWRpdGluZ1wiXG4gICAgICAgIFtjbGFzcy5tYXQtbWRjLXJvdy1kaXJ0eV09XCJyb3cuZGlydHlcIlxuICAgICAgICAoY2xpY2spPVwiY2xpY2tSb3coJGV2ZW50LCByb3cpXCJcbiAgICAgICAgKGtleWRvd24uZXNjYXBlKT1cImVzY2FwZUVkaXRpbmdSb3coJGV2ZW50KVwiXG4gICAgICAgIFtjZGtUcmFwRm9jdXNdPVwicm93LmludmFsaWRcIlxuICAgICAgPjwvdHI+XG4gICAgPC90YWJsZT5cblxuICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJsb2FkaW5nU3ViamVjdCB8IGFzeW5jOyBlbHNlIG5vUmVzdWx0XCI+XG4gICAgICA8aW9uLWl0ZW0+XG4gICAgICAgIDxpb24tc2tlbGV0b24tdGV4dCBhbmltYXRlZD48L2lvbi1za2VsZXRvbi10ZXh0PlxuICAgICAgPC9pb24taXRlbT5cbiAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgIDxuZy10ZW1wbGF0ZSAjbm9SZXN1bHQ+XG4gICAgICA8aW9uLWl0ZW0gKm5nSWY9XCJ0b3RhbFJvd0NvdW50ID09PSAwXCI+XG4gICAgICAgIDxpb24tdGV4dCBjb2xvcj1cImRhbmdlclwiIGNsYXNzPVwidGV4dC1pdGFsaWNcIiB0cmFuc2xhdGU+Q09NTU9OLk5PX1JFU1VMVDwvaW9uLXRleHQ+XG4gICAgICA8L2lvbi1pdGVtPlxuICAgIDwvbmctdGVtcGxhdGU+XG5cbiAgICA8aW9uLWluZmluaXRlLXNjcm9sbFxuICAgICAgKm5nSWY9XCJlbmFibGVJbmZpbml0ZVNjcm9sbFwiXG4gICAgICBbdGhyZXNob2xkXT1cIm1vYmlsZSA/ICcxMCUnIDogJzIlJ1wiXG4gICAgICBwb3NpdGlvbj1cImJvdHRvbVwiXG4gICAgICAoaW9uSW5maW5pdGUpPVwiZmV0Y2hNb3JlKCRldmVudClcIlxuICAgID5cbiAgICAgIDxpb24taW5maW5pdGUtc2Nyb2xsLWNvbnRlbnRcbiAgICAgICAgbG9hZGluZ1NwaW5uZXI9XCJjaXJjbGVzXCJcbiAgICAgICAgW2xvYWRpbmdUZXh0XT1cIidDT01NT04uTE9BRElOR19ET1RTJyB8IHRyYW5zbGF0ZVwiXG4gICAgICA+PC9pb24taW5maW5pdGUtc2Nyb2xsLWNvbnRlbnQ+XG4gICAgPC9pb24taW5maW5pdGUtc2Nyb2xsPlxuICA8L2Rpdj5cbjwvaW9uLWNvbnRlbnQ+XG5cbjxpb24tZm9vdGVyPlxuICA8IS0tIFBhZ2luYXRvciAgLS0+XG4gIDxtYXQtcGFnaW5hdG9yXG4gICAgKm5nSWY9XCIhZW5hYmxlSW5maW5pdGVTY3JvbGxcIlxuICAgIFtsZW5ndGhdPVwidG90YWxSb3dDb3VudFwiXG4gICAgW3BhZ2VTaXplXT1cImRlZmF1bHRQYWdlU2l6ZVwiXG4gICAgW3BhZ2VTaXplT3B0aW9uc109XCJkZWZhdWx0UGFnZVNpemVPcHRpb25zXCJcbiAgICBzaG93Rmlyc3RMYXN0QnV0dG9uc1xuICA+PC9tYXQtcGFnaW5hdG9yPlxuXG4gIDxhcHAtZm9ybS1idXR0b25zLWJhclxuICAgICpuZ0lmPVwiY2FuRWRpdCAmJiAhbW9iaWxlXCJcbiAgICAob25DYW5jZWwpPVwibG9hZCgpXCJcbiAgICAob25TYXZlKT1cInNhdmUoKVwiXG4gICAgW2Rpc2FibGVkXT1cIihsb2FkaW5nU3ViamVjdCB8IGFzeW5jKSB8fCAhZGlydHlcIlxuICA+XG4gICAgPCEtLSBlcnJvciAtLT5cbiAgICA8aW9uLWl0ZW0gKm5nSWY9XCJlcnJvciQgfCBhc3luY1wiIGxpbmVzPVwibm9uZVwiPlxuICAgICAgPGlvbi1pY29uIGNvbG9yPVwiZGFuZ2VyXCIgc2xvdD1cInN0YXJ0XCIgbmFtZT1cImFsZXJ0LWNpcmNsZVwiPjwvaW9uLWljb24+XG4gICAgICA8aW9uLWxhYmVsIGNvbG9yPVwiZGFuZ2VyXCIgW2lubmVySFRNTF09XCJlcnJvciB8IHRyYW5zbGF0ZVwiPjwvaW9uLWxhYmVsPlxuICAgIDwvaW9uLWl0ZW0+XG4gIDwvYXBwLWZvcm0tYnV0dG9ucy1iYXI+XG48L2lvbi1mb290ZXI+XG5cbjxpb24tZmFiIHNsb3Q9XCJmaXhlZFwiIHZlcnRpY2FsPVwiYm90dG9tXCIgaG9yaXpvbnRhbD1cImVuZFwiICpuZ0lmPVwiY2FuRWRpdCAmJiBtb2JpbGVcIj5cbiAgPGlvbi1mYWItYnV0dG9uIGNvbG9yPVwidGVydGlhcnlcIiAoY2xpY2spPVwiYWRkUm93KCRldmVudClcIj5cbiAgICA8aW9uLWljb24gbmFtZT1cImFkZFwiPjwvaW9uLWljb24+XG4gIDwvaW9uLWZhYi1idXR0b24+XG48L2lvbi1mYWI+XG4iXX0=
|