@sumaris-net/ngx-components 18.2.24 → 18.2.26

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.
Files changed (29) hide show
  1. package/doc/changelog.md +4 -0
  2. package/esm2022/src/app/core/install/install-upgrade-card.component.mjs +29 -10
  3. package/esm2022/src/app/core/peer/select-peer.modal.mjs +159 -18
  4. package/esm2022/src/app/core/peer/select-peer.module.mjs +11 -5
  5. package/esm2022/src/app/core/services/config/core.config.mjs +6 -1
  6. package/esm2022/src/app/core/services/model/node-feature.model.mjs +31 -0
  7. package/esm2022/src/app/core/services/model/peer.model.mjs +23 -3
  8. package/esm2022/src/app/core/services/network.service.mjs +4 -8
  9. package/esm2022/src/app/core/services/network.utils.mjs +1 -1
  10. package/esm2022/src/app/core/table/testing/table.testing.mjs +3 -3
  11. package/esm2022/src/app/shared/inputs.mjs +6 -7
  12. package/esm2022/src/app/shared/rx-state/rx-state.decorators.mjs +2 -2
  13. package/esm2022/src/environments/environment.class.mjs +4 -1
  14. package/esm2022/src/environments/environment.mjs +3 -1
  15. package/fesm2022/sumaris-net.ngx-components.mjs +640 -439
  16. package/fesm2022/sumaris-net.ngx-components.mjs.map +1 -1
  17. package/package.json +1 -1
  18. package/src/app/core/peer/select-peer.modal.d.ts +47 -6
  19. package/src/app/core/peer/select-peer.module.d.ts +3 -1
  20. package/src/app/core/services/config/core.config.d.ts +1 -0
  21. package/src/app/core/services/model/node-feature.model.d.ts +14 -0
  22. package/src/app/core/services/model/peer.model.d.ts +5 -0
  23. package/src/app/core/services/network.utils.d.ts +2 -0
  24. package/src/assets/i18n/en-US.json +6 -1
  25. package/src/assets/i18n/en.json +6 -1
  26. package/src/assets/i18n/fr.json +7 -2
  27. package/src/assets/manifest.json +1 -1
  28. package/src/environments/environment.class.d.ts +2 -0
  29. package/src/theme/_ngx-components.scss +2 -1
@@ -1,6 +1,6 @@
1
- import { booleanAttribute, ChangeDetectionStrategy, Component, EventEmitter, Inject, Input, Optional, } from '@angular/core';
1
+ import { booleanAttribute, ChangeDetectionStrategy, Component, EventEmitter, Inject, Input, numberAttribute, Optional, ViewChild, } from '@angular/core';
2
2
  import { Peer } from '../services/model/peer.model';
3
- import { Subject, Subscription } from 'rxjs';
3
+ import { Subscription } from 'rxjs';
4
4
  import { fadeInAnimation } from '../../shared/material/material.animations';
5
5
  import { NetworkUtils } from '../services/network.utils';
6
6
  import { VersionUtils } from '../../shared/version/versions';
@@ -10,17 +10,30 @@ import { isMobile } from '../../shared/platforms';
10
10
  import { Validators } from '@angular/forms';
11
11
  import { PEER_URL_REGEXP } from '../services/network.service';
12
12
  import { APP_LOGGING_SERVICE } from '../../shared/logging/logging-service.class';
13
+ import { map } from 'rxjs/operators';
14
+ import { EntityUtils } from '../services/model/entity.model';
15
+ import { RxState } from '@rx-angular/state';
16
+ import { suggestFromArray } from '../../shared/services';
17
+ import { isNilOrBlank, isNotEmptyArray, isNotNil } from '../../shared/functions';
18
+ import { NodeFeature } from '../services/model/node-feature.model';
13
19
  import * as i0 from "@angular/core";
14
20
  import * as i1 from "@ionic/angular";
15
21
  import * as i2 from "@ngx-translate/core";
16
22
  import * as i3 from "@angular/common/http";
17
23
  import * as i4 from "@angular/common";
18
- import * as i5 from "@rx-angular/template/for";
24
+ import * as i5 from "@angular/forms";
19
25
  import * as i6 from "@angular/material/icon";
20
- import * as i7 from "@angular/material/core";
21
- import * as i8 from "@angular/material/tooltip";
22
- import * as i9 from "../../../environments/environment.class";
23
- export class SelectPeerModal {
26
+ import * as i7 from "@angular/material/tabs";
27
+ import * as i8 from "@angular/material/badge";
28
+ import * as i9 from "@angular/material/core";
29
+ import * as i10 from "@angular/material/tooltip";
30
+ import * as i11 from "../../shared/pipes/highlight.pipe";
31
+ import * as i12 from "../../shared/pipes/arrays.pipe";
32
+ import * as i13 from "../../shared/pipes/string.pipes";
33
+ import * as i14 from "../../shared/pipes/badge.pipes";
34
+ import * as i15 from "../services/pipes/referential-to-string.pipe";
35
+ import * as i16 from "../../../environments/environment.class";
36
+ export class SelectPeerModal extends RxState {
24
37
  modalCtrl;
25
38
  popoverController;
26
39
  translate;
@@ -30,17 +43,56 @@ export class SelectPeerModal {
30
43
  loggingService;
31
44
  _subscription = new Subscription();
32
45
  _logger;
46
+ defaultPeers$ = this.select('defaultPeers');
47
+ peers$ = this.select('peers');
48
+ filteredPeers$ = this.select('filteredPeers');
49
+ filteredPeersByFeatures$ = this.select('filteredPeersByFeatures');
50
+ filteredPeerCount$ = this.select('filteredPeerCount');
51
+ filteredFeaturesCount$ = this.select('filteredFeaturesCount');
33
52
  loading = true;
34
53
  mobile;
35
- $peers = new Subject();
36
54
  peerMinVersion;
37
55
  peerDefaultPrefix;
56
+ enableSelectPeerByFeature;
57
+ collapsedPeers = {};
58
+ set peers(value) {
59
+ this.set('peers', () => value);
60
+ }
61
+ get peers() {
62
+ return this.get('peers');
63
+ }
64
+ set searchText(value) {
65
+ this.set('searchText', () => value);
66
+ }
67
+ get searchText() {
68
+ return this.get('searchText');
69
+ }
70
+ set filteredPeers(value) {
71
+ this.set('filteredPeers', () => value);
72
+ }
73
+ get filteredPeers() {
74
+ return this.get('filteredPeers');
75
+ }
76
+ set selectedTabIndex(value) {
77
+ this.set('selectedTabIndex', () => value);
78
+ }
79
+ get selectedTabIndex() {
80
+ return this.get('selectedTabIndex');
81
+ }
38
82
  selectedPeer;
83
+ title = 'NETWORK.PEER.SELECT_MODAL.TITLE';
39
84
  canCancel = true;
40
85
  allowSelectDownPeer = true;
41
86
  showSetManuallyButton = true;
87
+ showSearchBar;
88
+ tabGroupAnimationDuration;
42
89
  onRefresh = new EventEmitter();
90
+ set defaultPeers(value) {
91
+ this.set('defaultPeers', () => value);
92
+ }
93
+ searchbar;
43
94
  constructor(modalCtrl, popoverController, translate, http, cd, environment, loggingService) {
95
+ super();
44
96
  this.modalCtrl = modalCtrl;
45
97
  this.popoverController = popoverController;
46
98
  this.translate = translate;
@@ -48,13 +100,51 @@ export class SelectPeerModal {
48
100
  this.cd = cd;
49
101
  this.environment = environment;
50
102
  this.loggingService = loggingService;
103
+ this.set({ searchText: null, selectedTabIndex: 0 });
51
104
  this.mobile = isMobile(window);
52
105
  this._logger = loggingService?.getLogger('network-modal');
53
106
  this.peerMinVersion = environment.peerMinVersion;
54
107
  this.peerDefaultPrefix = environment.peerDefaultPrefix || 'https://';
55
- }
56
- set peers(peers) {
57
- this._subscription.add(peers.subscribe((res) => this.refreshPeers(res)));
108
+ this.enableSelectPeerByFeature = environment.enableSelectPeerByFeature || false;
109
+ this.showSearchBar = this.enableSelectPeerByFeature; // Show search bar by default, if two tabs
110
+ // Refreshing peers
111
+ this.hold(this.defaultPeers$, (res) => this.refreshPeers(res));
112
+ // Search on host
113
+ this.connect('filteredPeers', this.select(['peers', 'searchText'], (res) => res).pipe(map(({ peers, searchText }) => {
114
+ if (isNilOrBlank(searchText))
115
+ return peers; // All
116
+ console.debug('[select-peer-modal] Searching on hosts: ' + searchText);
117
+ const { data } = suggestFromArray(peers, searchText, {
118
+ anySearch: true,
119
+ searchAttributes: ['label', 'hostAndPort'],
120
+ });
121
+ return data;
122
+ })));
123
+ this.connect('filteredPeerCount', this.filteredPeers$.pipe(map((peers) => peers?.length ?? 0)));
124
+ // Search on features
125
+ if (this.enableSelectPeerByFeature) {
126
+ this.connect('filteredPeersByFeatures', this.select(['peers', 'searchText'], (res) => res).pipe(map(({ peers, searchText }) => {
127
+ if (isNilOrBlank(searchText)) {
128
+ return (peers || []).filter((p) => isNotEmptyArray(p?.features));
129
+ }
130
+ console.debug('[select-peer-modal] Searching on features: ' + searchText);
131
+ return peers
132
+ .map((peer) => {
133
+ const { data: features } = suggestFromArray(peer.features || [], searchText, {
134
+ anySearch: true,
135
+ searchAttributes: ['label', 'name', 'description'],
136
+ });
137
+ if (isNotEmptyArray(features)) {
138
+ const filteredPeer = peer.clone();
139
+ filteredPeer.features = features;
140
+ return filteredPeer;
141
+ }
142
+ return null;
143
+ })
144
+ .filter(isNotNil);
145
+ })));
146
+ this.connect('filteredFeaturesCount', this.filteredPeersByFeatures$.pipe(map(Peer.countAllFeatures)));
147
+ }
58
148
  }
59
149
  cancel() {
60
150
  this.modalCtrl.dismiss();
@@ -69,6 +159,21 @@ export class SelectPeerModal {
69
159
  this.modalCtrl.dismiss(peer);
70
160
  }
71
161
  }
162
+ async toggleSearchBar() {
163
+ this.showSearchBar = !this.showSearchBar;
164
+ if (this.showSearchBar && this.searchbar) {
165
+ setTimeout(() => {
166
+ this.searchbar.setFocus();
167
+ this.markForCheck();
168
+ }, 300);
169
+ }
170
+ }
171
+ togglePeerFeatures(peerUrl) {
172
+ if (!peerUrl)
173
+ return;
174
+ this.collapsedPeers[peerUrl] = isNotNil(this.collapsedPeers[peerUrl]) ? !this.collapsedPeers[peerUrl] : true;
175
+ this.markForCheck();
176
+ }
72
177
  /**
73
178
  * Check the min pod version, defined by the app
74
179
  *
@@ -90,6 +195,14 @@ export class SelectPeerModal {
90
195
  }
91
196
  }
92
197
  /* -- protected methods -- */
198
+ clearLogo(peer) {
199
+ if (peer instanceof Peer) {
200
+ peer.favicon = 'skip';
201
+ }
202
+ else {
203
+ peer.logo = 'skip';
204
+ }
205
+ }
93
206
  async refreshPeers(peers) {
94
207
  peers = peers || [];
95
208
  const data = [];
@@ -110,10 +223,9 @@ export class SelectPeerModal {
110
223
  return 1;
111
224
  return 0;
112
225
  });
113
- this.$peers.next(data);
226
+ this.peers = data.slice(); // Copy to force update
114
227
  return peer;
115
228
  }));
116
- this._subscription.add(this.$peers.subscribe(() => this.cd.markForCheck()));
117
229
  try {
118
230
  await jobs;
119
231
  }
@@ -126,12 +238,15 @@ export class SelectPeerModal {
126
238
  }
127
239
  async refreshPeer(peer) {
128
240
  try {
241
+ // DEBUG
242
+ //await sleep(Math.random() * 100);
129
243
  const summary = await NetworkUtils.getNodeInfo(this.http, peer.url);
130
244
  peer.status = 'UP';
131
245
  peer.softwareName = summary.softwareName;
132
246
  peer.softwareVersion = summary.softwareVersion;
133
247
  peer.label = summary.nodeLabel;
134
248
  peer.name = summary.nodeName;
249
+ peer.features = summary.features?.map(NodeFeature.fromObject) || [];
135
250
  }
136
251
  catch (err) {
137
252
  // If modal was not closed (e.g. response arrived too late => ignore)
@@ -169,16 +284,27 @@ export class SelectPeerModal {
169
284
  return data;
170
285
  }
171
286
  }
287
+ updateFilteredPeer(event) {
288
+ if (event) {
289
+ event.preventDefault();
290
+ event.stopPropagation();
291
+ }
292
+ const value = event.target.value;
293
+ const test = this.filteredPeers$.pipe(map((peers) => peers.filter(EntityUtils.searchTextFilter(['features.label', 'features.name', 'features.description'], value))));
294
+ console.log(test);
295
+ // (event.target.value);
296
+ this.markForCheck();
297
+ }
172
298
  markForCheck() {
173
299
  this.cd.markForCheck();
174
300
  }
175
301
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.11", ngImport: i0, type: SelectPeerModal, deps: [{ token: i1.ModalController }, { token: i1.PopoverController }, { token: i2.TranslateService }, { token: i3.HttpClient }, { token: i0.ChangeDetectorRef }, { token: ENVIRONMENT }, { token: APP_LOGGING_SERVICE, optional: true }], target: i0.ɵɵFactoryTarget.Component });
176
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.11", type: SelectPeerModal, selector: "select-peer-modal", inputs: { selectedPeer: "selectedPeer", canCancel: ["canCancel", "canCancel", booleanAttribute], allowSelectDownPeer: ["allowSelectDownPeer", "allowSelectDownPeer", booleanAttribute], showSetManuallyButton: ["showSetManuallyButton", "showSetManuallyButton", booleanAttribute], onRefresh: "onRefresh" }, ngImport: i0, template: "<ion-header>\n <ion-toolbar color=\"light\">\n <ion-buttons slot=\"start\">\n <ion-button (click)=\"cancel()\" *ngIf=\"canCancel\" visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title>\n {{ 'NETWORK.PEER.SELECT_MODAL.TITLE' | translate }}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <!-- loader -->\n <ion-spinner *ngIf=\"loading; else endButtons\"></ion-spinner>\n\n <ng-template #endButtons>\n <!-- refresh button -->\n <ion-button\n *ngIf=\"onRefresh.observed\"\n [matTooltip]=\"'COMMON.BTN_REFRESH' | translate\"\n (click)=\"refresh($event)\"\n >\n <mat-icon slot=\"icon-only\">refresh</mat-icon>\n </ion-button>\n </ng-template>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n <ion-list>\n <ion-list-header>\n <ion-label class=\"ion-text-wrap\">\n <p translate>NETWORK.PEER.SELECT_MODAL.HELP</p>\n </ion-label>\n </ion-list-header>\n\n <ion-item\n *rxFor=\"let peer of $peers\"\n (click)=\"selectPeer(peer)\"\n [class.selected]=\"selectedPeer && selectedPeer === peer.url\"\n tappable\n matRipple\n detail\n @fadeInAnimation\n >\n <!-- Peer is UP -->\n @if (peer.reachable) {\n <!-- icon -->\n <ion-avatar slot=\"start\">\n <ion-img [src]=\"peer.favicon || peer.url + '/api/favicon'\"></ion-img>\n </ion-avatar>\n\n <ion-grid>\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding\">\n <ion-label class=\"ion-text-wrap\">\n <ion-text>\n <h3>{{ peer.hostAndPort }}{{ peer.path }}</h3>\n </ion-text>\n <ion-text color=\"primary\">\n <h4>{{ peer.label }}</h4>\n </ion-text>\n </ion-label>\n </ion-col>\n <ion-col class=\"ion-no-padding\">\n <ion-label class=\"ion-text-wrap ion-text-center\" color=\"medium\">\n <h3>{{ peer.softwareName }}</h3>\n <h4 *ngIf=\"!peerMinVersion || isCompatible(peer); else invalidVersion\">\n <small>v{{ peer.softwareVersion }}</small>\n </h4>\n <ng-template #invalidVersion>\n <ion-text\n color=\"danger\"\n [matTooltip]=\"\n 'NETWORK.PEER.SELECT_MODAL.NOT_COMPATIBLE_HELP' | translate: { version: peerMinVersion }\n \"\n >\n <h4 class=\"ion-color-danger\">\n <small>\n <mat-icon>warning</mat-icon>\n v{{ peer.softwareVersion }}\n </small>\n </h4>\n </ion-text>\n </ng-template>\n </ion-label>\n </ion-col>\n </ion-row>\n </ion-grid>\n } @else {\n <!-- Peer is DOWN -->\n <ion-icon slot=\"start\" name=\"desktop\" class=\"disabled ion-icon-avatar\"></ion-icon>\n\n <ion-label class=\"ion-text-wrap\">\n <ion-text color=\"medium\">\n <h3>{{ peer.hostAndPort }}{{ peer.path }}</h3>\n </ion-text>\n <ion-text color=\"danger\">\n <h4>\n <small><ion-icon size=\"small\" name=\"close-circle\"></ion-icon></small>\n <span translate>NETWORK.PEER.OFFLINE</span>\n </h4>\n </ion-text>\n </ion-label>\n }\n </ion-item>\n </ion-list>\n</ion-content>\n\n@if ((canCancel && !mobile) || showSetManuallyButton) {\n <ion-footer>\n <ion-toolbar>\n <ion-row class=\"ion-no-padding ion-text-nowrap\">\n <ion-col></ion-col>\n\n <!-- buttons -->\n @if (showSetManuallyButton) {\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"clickSetManually($event)\">\n <ion-label translate>NETWORK.PEER.SELECT_MODAL.BTN_SET_MANUALLY</ion-label>\n </ion-button>\n </ion-col>\n }\n\n @if (canCancel) {\n <ion-col size=\"auto\" hidden-xs hidden-sm hidden-mobile>\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n </ion-col>\n }\n </ion-row>\n </ion-toolbar>\n </ion-footer>\n}\n", styles: ["ion-item .ion-icon-avatar{font-size:40px;width:40px;height:40px}ion-item .ion-icon-avatar.disabled{color:rgba(var(--ion-color-medium-rgb),.7)}ion-item h4 ion-icon,ion-item h4 mat-icon{height:14px;width:14px;font-size:14px;line-height:14px}ion-item h4 small ion-icon,ion-item h4 small mat-icon{height:12px;width:12px;font-size:12px;line-height:12px}ion-item.selected{--ion-color-base: var(--ion-color-secondary100-contrast) !important;--ion-item-background: var(--ion-color-secondary100)}\n"], dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i1.IonAvatar, selector: "ion-avatar" }, { kind: "component", type: i1.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: i1.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i1.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: i1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i1.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i1.IonGrid, selector: "ion-grid", inputs: ["fixed"] }, { kind: "component", type: i1.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i1.IonImg, selector: "ion-img", inputs: ["alt", "src"] }, { kind: "component", type: i1.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: i1.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i1.IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: i1.IonListHeader, selector: "ion-list-header", inputs: ["color", "lines", "mode"] }, { kind: "component", type: i1.IonRow, selector: "ion-row" }, { kind: "component", type: i1.IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: i1.IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: i1.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: i1.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "directive", type: i2.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: i5.RxFor, selector: "[rxFor][rxForOf]", inputs: ["rxForOf", "rxForTemplate", "rxForStrategy", "rxForParent", "rxForPatchZone", "rxForTrackBy", "rxForRenderCallback"] }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i7.MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }], animations: [fadeInAnimation], changeDetection: i0.ChangeDetectionStrategy.OnPush });
302
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.11", type: SelectPeerModal, selector: "select-peer-modal", inputs: { selectedTabIndex: ["selectedTabIndex", "selectedTabIndex", numberAttribute], selectedPeer: "selectedPeer", title: "title", canCancel: ["canCancel", "canCancel", booleanAttribute], allowSelectDownPeer: ["allowSelectDownPeer", "allowSelectDownPeer", booleanAttribute], showSetManuallyButton: ["showSetManuallyButton", "showSetManuallyButton", booleanAttribute], showSearchBar: ["showSearchBar", "showSearchBar", booleanAttribute], tabGroupAnimationDuration: "tabGroupAnimationDuration", onRefresh: "onRefresh", defaultPeers: "defaultPeers" }, viewQueries: [{ propertyName: "searchbar", first: true, predicate: ["searchbar"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<ion-header>\n <ion-toolbar color=\"light\" style=\"z-index: 900\">\n <ion-buttons slot=\"start\">\n @if (canCancel) {\n <ion-button (click)=\"cancel()\" visible-mobile visible-sm visible-xs>\n <ion-icon name=\"arrow-back\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n </ion-buttons>\n\n <ion-title>\n {{ title | translate }}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <!-- loader -->\n @if (loading) {\n <ion-spinner></ion-spinner>\n } @else {\n <!-- refresh button -->\n <ion-button\n (click)=\"refresh($event)\"\n *ngIf=\"onRefresh.observed\"\n [matTooltip]=\"'COMMON.BTN_REFRESH' | translate\"\n >\n <mat-icon slot=\"icon-only\">refresh</mat-icon>\n </ion-button>\n }\n <!-- search button -->\n @if (!showSearchBar) {\n <ion-button (click)=\"toggleSearchBar()\">\n <ion-icon slot=\"icon-only\" name=\"search\"></ion-icon>\n </ion-button>\n }\n </ion-buttons>\n </ion-toolbar>\n\n <!-- search bar -->\n <ion-toolbar *ngIf=\"showSearchBar\">\n <ion-searchbar\n #searchbar\n animated\n type=\"search\"\n [class.cdk-visually-hidden]=\"!showSearchBar\"\n show-clear-button=\"always\"\n [placeholder]=\"'COMMON.BTN_SEARCH' | translate\"\n [cancelButtonText]=\"'COMMON.BTN_CANCEL' | translate\"\n [(ngModel)]=\"searchText\"\n (ionCancel)=\"toggleSearchBar()\"\n ></ion-searchbar>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n <mat-tab-group\n #tabGroup\n [(selectedIndex)]=\"selectedTabIndex\"\n class=\"mat-mdc-tab-disabled-hidden\"\n [class.mat-mdc-tab-group-header-hidden]=\"!enableSelectPeerByFeature\"\n [dynamicHeight]=\"false\"\n [mat-stretch-tabs]=\"mobile\"\n [animationDuration]=\"mobile ? tabGroupAnimationDuration : '0s'\"\n >\n <mat-tab>\n <ng-template mat-tab-label>\n <ion-label\n [matBadge]=\"filteredPeerCount$ | async | badgeNumber\"\n [matBadgeHidden]=\"filteredPeerCount$ | async | isNil\"\n [matBadgeColor]=\"(filteredPeerCount$ | async) ? 'primary' : 'accent'\"\n matBadgeOverlap=\"false\"\n matBadgeColor=\"primary\"\n matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n >\n {{ 'NETWORK.PEER.SELECT_MODAL.TAB_NETWORK' | translate }}\n </ion-label>\n </ng-template>\n <ion-list>\n <ion-list-header>\n <ion-label class=\"ion-text-wrap ion-padding-end\">\n <p [innerHTML]=\"'NETWORK.PEER.SELECT_MODAL.NETWORK_HELP' | translate\"></p>\n </ion-label>\n </ion-list-header>\n\n @for (peer of filteredPeers$ | async; track $index) {\n <ion-item\n (click)=\"selectPeer(peer)\"\n @fadeInAnimation\n [class.selected]=\"selectedPeer && selectedPeer === peer.url\"\n detail\n matRipple\n tappable\n >\n <!-- Peer is UP -->\n @if (peer.reachable) {\n <!-- icon -->\n @if (peer.favicon != 'skip') {\n <ion-avatar slot=\"start\">\n <ion-img [src]=\"peer.favicon || peer.url + '/api/favicon'\" (ionError)=\"clearLogo(peer)\"></ion-img>\n <ion-icon name=\"server\" class=\"icon-secondary\" style=\"top: 12px; left: 44px\" color=\"dark\"></ion-icon>\n </ion-avatar>\n } @else {\n <ion-icon slot=\"start\" name=\"server\" class=\"ion-icon-avatar\" color=\"dark\"></ion-icon>\n }\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <ion-label class=\"ion-text-wrap\">\n <ion-text>\n @let url = peer.hostAndPort + peer.path;\n <h3 [innerHTML]=\"url | highlight: searchText\"></h3>\n </ion-text>\n <ion-text color=\"primary\">\n <h4 [innerHTML]=\"peer.label | highlight: searchText\"></h4>\n </ion-text>\n </ion-label>\n </ion-col>\n <ion-col size=\"12\" size-sm=\"4\">\n <ion-label class=\"ion-text-wrap ion-text-sm-center\" color=\"medium\">\n <h4>\n <small>{{ peer.softwareName }}&nbsp;</small>\n <br class=\"hidden-xxs hidden-xs\" />\n <!-- Compatible -->\n @if (!peerMinVersion || isCompatible(peer)) {\n <small>v{{ peer.softwareVersion }}</small>\n } @else {\n <!-- Incompatible -->\n <ion-text\n color=\"danger\"\n [matTooltip]=\"\n 'NETWORK.PEER.SELECT_MODAL.NOT_COMPATIBLE_HELP' | translate: { version: peerMinVersion }\n \"\n >\n <small class=\"ion-color-danger\">\n <mat-icon>warning</mat-icon>\n v{{ peer.softwareVersion }}\n </small>\n </ion-text>\n }\n </h4>\n </ion-label>\n </ion-col>\n </ion-row>\n </ion-grid>\n } @else {\n <!-- Peer is DOWN -->\n <ion-icon slot=\"start\" name=\"server\" class=\"disabled ion-icon-avatar\"></ion-icon>\n\n <ion-label class=\"ion-text-wrap\">\n <ion-text color=\"medium\">\n <h3>{{ peer.hostAndPort }}{{ peer.path }}</h3>\n </ion-text>\n <ion-text color=\"danger\">\n <h4>\n <small>\n <ion-icon size=\"small\" name=\"close-circle\"></ion-icon>\n </small>\n <span translate>NETWORK.PEER.OFFLINE</span>\n </h4>\n </ion-text>\n </ion-label>\n }\n </ion-item>\n }\n\n <!-- no result -->\n @if ((filteredPeerCount$ | async) === 0) {\n <ion-item>\n <ion-text color=\"danger\" class=\"text-italic\" translate>COMMON.NO_RESULT</ion-text>\n </ion-item>\n }\n </ion-list>\n </mat-tab>\n\n <!-- Select by features -->\n <mat-tab [disabled]=\"!enableSelectPeerByFeature\">\n <ng-template mat-tab-label>\n <ion-label\n [matBadge]=\"filteredFeaturesCount$ | async | badgeNumber\"\n [matBadgeHidden]=\"filteredFeaturesCount$ | async | isNil\"\n [matBadgeColor]=\"(filteredFeaturesCount$ | async) ? 'primary' : 'accent'\"\n matBadgeOverlap=\"false\"\n matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n >\n {{ 'NETWORK.PEER.SELECT_MODAL.TAB_FEATURES' | translate }}\n </ion-label>\n </ng-template>\n <ion-list>\n <ion-list-header>\n <ion-label class=\"ion-text-wrap ion-padding-end\">\n <p [innerHTML]=\"'NETWORK.PEER.SELECT_MODAL.FEATURES_HELP' | translate\"></p>\n </ion-label>\n </ion-list-header>\n\n @for (peer of filteredPeersByFeatures$ | async; track $index) {\n @let peerUrl = peer.hostAndPort + peer.path;\n <!-- Peer is UP -->\n @if (peer.reachable && peer.features | isNotEmptyArray) {\n @let collapsed = collapsedPeers[peerUrl];\n\n <ion-item-divider (click)=\"togglePeerFeatures(peerUrl)\" tappable @fadeInAnimation>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <ion-label>\n <h4>\n <ion-icon name=\"server\" color=\"medium\"></ion-icon>\n {{ peer.hostAndPort }}{{ peer.path }}\n </h4>\n @if (peerMinVersion && !isCompatible(peer)) {\n <ion-text\n color=\"danger\"\n [matTooltip]=\"\n 'NETWORK.PEER.SELECT_MODAL.NOT_COMPATIBLE_HELP' | translate: { version: peerMinVersion }\n \"\n >\n <h4 class=\"ion-color-danger\">\n <small>\n <mat-icon>warning</mat-icon>\n v{{ peer.softwareVersion }}\n </small>\n </h4>\n </ion-text>\n }\n </ion-label>\n </ion-col>\n <ion-col size=\"4\" class=\"ion-text-end\">\n <ion-label class=\"text-italic\">\n <h4>({{ 'COMMON.RESULT_COUNT' | translate: { count: peer.features.length } }})</h4>\n </ion-label>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <mat-icon slot=\"end\">\n @if (collapsed) {\n {{ mobile ? 'arrow_drop_down' : 'keyboard_arrow_down' }}\n } @else {\n {{ mobile ? 'arrow_drop_up' : 'keyboard_arrow_up' }}\n }\n </mat-icon>\n </ion-item-divider>\n\n @if (!collapsed) {\n @for (feature of peer.features; track feature.label) {\n <ion-item (click)=\"selectPeer(peer)\" tappable matRipple detail @fadeInAnimation>\n <!-- icon -->\n @if (feature.logo && feature.logo != 'skip') {\n <ion-avatar slot=\"start\">\n <ion-img [src]=\"feature.logo\" (ionError)=\"clearLogo(feature)\"></ion-img>\n </ion-avatar>\n } @else if (peer.favicon != 'skip') {\n <ion-avatar slot=\"start\">\n <ion-img [src]=\"peer.favicon || peer.url + '/api/favicon'\" (ionError)=\"clearLogo(peer)\"></ion-img>\n <ion-icon\n name=\"contract\"\n class=\"icon-secondary\"\n style=\"top: 12px; left: 44px\"\n color=\"dark\"\n ></ion-icon>\n </ion-avatar>\n } @else {\n <ion-icon slot=\"start\" name=\"contract\" class=\"ion-icon-avatar\" color=\"dark\"></ion-icon>\n }\n\n <ion-label class=\"ion-text-wrap\">\n <ion-text color=\"primary\">\n <h3 [innerHTML]=\"feature | referentialToString | highlight: searchText\"></h3>\n </ion-text>\n <ion-text>\n <p [innerHTML]=\"feature.description | highlight: searchText\"></p>\n </ion-text>\n </ion-label>\n </ion-item>\n }\n }\n }\n }\n\n <!-- no result -->\n @if ((filteredFeaturesCount$ | async) === 0) {\n <ion-item>\n <ion-text color=\"danger\" class=\"text-italic\" translate>COMMON.NO_RESULT</ion-text>\n </ion-item>\n }\n </ion-list>\n </mat-tab>\n </mat-tab-group>\n</ion-content>\n\n@if ((canCancel && !mobile) || showSetManuallyButton) {\n <ion-footer>\n <ion-toolbar>\n <ion-row class=\"ion-no-padding ion-text-nowrap\">\n <ion-col></ion-col>\n\n <!-- buttons -->\n @if (showSetManuallyButton) {\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" (click)=\"clickSetManually($event)\">\n <ion-label translate>NETWORK.PEER.SELECT_MODAL.BTN_SET_MANUALLY</ion-label>\n </ion-button>\n </ion-col>\n }\n\n @if (canCancel) {\n <ion-col size=\"auto\" hidden-xs hidden-sm hidden-mobile>\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n </ion-col>\n }\n </ion-row>\n </ion-toolbar>\n </ion-footer>\n}\n", styles: [".mat-mdc-tab-group{height:100%}.mat-mdc-tab-group .mat-tab-body-wrapper{height:calc(100% - var(--mat-tab-header-height))}ion-item-divider .ion-icon-avatar,ion-item .ion-icon-avatar{-webkit-margin-end:16px;margin-inline-end:16px;font-size:40px;width:40px;height:40px}ion-item-divider .ion-icon-avatar.disabled,ion-item .ion-icon-avatar.disabled{color:rgba(var(--ion-color-medium-rgb),.7)}ion-item-divider h4 ion-icon,ion-item-divider h4 mat-icon,ion-item h4 ion-icon,ion-item h4 mat-icon{height:14px;width:14px;font-size:14px;line-height:14px}ion-item-divider h4 small ion-icon,ion-item-divider h4 small mat-icon,ion-item h4 small ion-icon,ion-item h4 small mat-icon{height:12px;width:12px;font-size:12px;line-height:12px}ion-item-divider.selected,ion-item.selected{--ion-color-base: var(--ion-color-secondary100-contrast) !important;--ion-item-background: var(--ion-color-secondary100)}\n"], dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i1.IonAvatar, selector: "ion-avatar" }, { kind: "component", type: i1.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: i1.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i1.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: i1.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i1.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i1.IonGrid, selector: "ion-grid", inputs: ["fixed"] }, { kind: "component", type: i1.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i1.IonImg, selector: "ion-img", inputs: ["alt", "src"] }, { kind: "component", type: i1.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: i1.IonItemDivider, selector: "ion-item-divider", inputs: ["color", "mode", "sticky"] }, { kind: "component", type: i1.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i1.IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: i1.IonListHeader, selector: "ion-list-header", inputs: ["color", "lines", "mode"] }, { kind: "component", type: i1.IonRow, selector: "ion-row" }, { kind: "component", type: i1.IonSearchbar, selector: "ion-searchbar", inputs: ["animated", "autocapitalize", "autocomplete", "autocorrect", "cancelButtonIcon", "cancelButtonText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "maxlength", "minlength", "mode", "name", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value"] }, { kind: "component", type: i1.IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: i1.IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: i1.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: i1.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "directive", type: i1.TextValueAccessor, selector: "ion-input:not([type=number]),ion-textarea,ion-searchbar,ion-range" }, { kind: "directive", type: i2.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i7.MatTabLabel, selector: "[mat-tab-label], [matTabLabel]" }, { kind: "component", type: i7.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass"], exportAs: ["matTab"] }, { kind: "component", type: i7.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "directive", type: i8.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "directive", type: i9.MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "pipe", type: i11.HighlightPipe, name: "highlight" }, { kind: "pipe", type: i12.NotEmptyArrayPipe, name: "isNotEmptyArray" }, { kind: "pipe", type: i13.IsNilPipe, name: "isNil" }, { kind: "pipe", type: i14.BadgeNumberPipe, name: "badgeNumber" }, { kind: "pipe", type: i15.ReferentialToStringPipe, name: "referentialToString" }], animations: [fadeInAnimation], changeDetection: i0.ChangeDetectionStrategy.OnPush });
177
303
  }
178
304
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.11", ngImport: i0, type: SelectPeerModal, decorators: [{
179
305
  type: Component,
180
- args: [{ selector: 'select-peer-modal', changeDetection: ChangeDetectionStrategy.OnPush, animations: [fadeInAnimation], template: "<ion-header>\n <ion-toolbar color=\"light\">\n <ion-buttons slot=\"start\">\n <ion-button (click)=\"cancel()\" *ngIf=\"canCancel\" visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title>\n {{ 'NETWORK.PEER.SELECT_MODAL.TITLE' | translate }}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <!-- loader -->\n <ion-spinner *ngIf=\"loading; else endButtons\"></ion-spinner>\n\n <ng-template #endButtons>\n <!-- refresh button -->\n <ion-button\n *ngIf=\"onRefresh.observed\"\n [matTooltip]=\"'COMMON.BTN_REFRESH' | translate\"\n (click)=\"refresh($event)\"\n >\n <mat-icon slot=\"icon-only\">refresh</mat-icon>\n </ion-button>\n </ng-template>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n <ion-list>\n <ion-list-header>\n <ion-label class=\"ion-text-wrap\">\n <p translate>NETWORK.PEER.SELECT_MODAL.HELP</p>\n </ion-label>\n </ion-list-header>\n\n <ion-item\n *rxFor=\"let peer of $peers\"\n (click)=\"selectPeer(peer)\"\n [class.selected]=\"selectedPeer && selectedPeer === peer.url\"\n tappable\n matRipple\n detail\n @fadeInAnimation\n >\n <!-- Peer is UP -->\n @if (peer.reachable) {\n <!-- icon -->\n <ion-avatar slot=\"start\">\n <ion-img [src]=\"peer.favicon || peer.url + '/api/favicon'\"></ion-img>\n </ion-avatar>\n\n <ion-grid>\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding\">\n <ion-label class=\"ion-text-wrap\">\n <ion-text>\n <h3>{{ peer.hostAndPort }}{{ peer.path }}</h3>\n </ion-text>\n <ion-text color=\"primary\">\n <h4>{{ peer.label }}</h4>\n </ion-text>\n </ion-label>\n </ion-col>\n <ion-col class=\"ion-no-padding\">\n <ion-label class=\"ion-text-wrap ion-text-center\" color=\"medium\">\n <h3>{{ peer.softwareName }}</h3>\n <h4 *ngIf=\"!peerMinVersion || isCompatible(peer); else invalidVersion\">\n <small>v{{ peer.softwareVersion }}</small>\n </h4>\n <ng-template #invalidVersion>\n <ion-text\n color=\"danger\"\n [matTooltip]=\"\n 'NETWORK.PEER.SELECT_MODAL.NOT_COMPATIBLE_HELP' | translate: { version: peerMinVersion }\n \"\n >\n <h4 class=\"ion-color-danger\">\n <small>\n <mat-icon>warning</mat-icon>\n v{{ peer.softwareVersion }}\n </small>\n </h4>\n </ion-text>\n </ng-template>\n </ion-label>\n </ion-col>\n </ion-row>\n </ion-grid>\n } @else {\n <!-- Peer is DOWN -->\n <ion-icon slot=\"start\" name=\"desktop\" class=\"disabled ion-icon-avatar\"></ion-icon>\n\n <ion-label class=\"ion-text-wrap\">\n <ion-text color=\"medium\">\n <h3>{{ peer.hostAndPort }}{{ peer.path }}</h3>\n </ion-text>\n <ion-text color=\"danger\">\n <h4>\n <small><ion-icon size=\"small\" name=\"close-circle\"></ion-icon></small>\n <span translate>NETWORK.PEER.OFFLINE</span>\n </h4>\n </ion-text>\n </ion-label>\n }\n </ion-item>\n </ion-list>\n</ion-content>\n\n@if ((canCancel && !mobile) || showSetManuallyButton) {\n <ion-footer>\n <ion-toolbar>\n <ion-row class=\"ion-no-padding ion-text-nowrap\">\n <ion-col></ion-col>\n\n <!-- buttons -->\n @if (showSetManuallyButton) {\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"clickSetManually($event)\">\n <ion-label translate>NETWORK.PEER.SELECT_MODAL.BTN_SET_MANUALLY</ion-label>\n </ion-button>\n </ion-col>\n }\n\n @if (canCancel) {\n <ion-col size=\"auto\" hidden-xs hidden-sm hidden-mobile>\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n </ion-col>\n }\n </ion-row>\n </ion-toolbar>\n </ion-footer>\n}\n", styles: ["ion-item .ion-icon-avatar{font-size:40px;width:40px;height:40px}ion-item .ion-icon-avatar.disabled{color:rgba(var(--ion-color-medium-rgb),.7)}ion-item h4 ion-icon,ion-item h4 mat-icon{height:14px;width:14px;font-size:14px;line-height:14px}ion-item h4 small ion-icon,ion-item h4 small mat-icon{height:12px;width:12px;font-size:12px;line-height:12px}ion-item.selected{--ion-color-base: var(--ion-color-secondary100-contrast) !important;--ion-item-background: var(--ion-color-secondary100)}\n"] }]
181
- }], ctorParameters: () => [{ type: i1.ModalController }, { type: i1.PopoverController }, { type: i2.TranslateService }, { type: i3.HttpClient }, { type: i0.ChangeDetectorRef }, { type: i9.Environment, decorators: [{
306
+ args: [{ selector: 'select-peer-modal', changeDetection: ChangeDetectionStrategy.OnPush, animations: [fadeInAnimation], template: "<ion-header>\n <ion-toolbar color=\"light\" style=\"z-index: 900\">\n <ion-buttons slot=\"start\">\n @if (canCancel) {\n <ion-button (click)=\"cancel()\" visible-mobile visible-sm visible-xs>\n <ion-icon name=\"arrow-back\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n </ion-buttons>\n\n <ion-title>\n {{ title | translate }}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <!-- loader -->\n @if (loading) {\n <ion-spinner></ion-spinner>\n } @else {\n <!-- refresh button -->\n <ion-button\n (click)=\"refresh($event)\"\n *ngIf=\"onRefresh.observed\"\n [matTooltip]=\"'COMMON.BTN_REFRESH' | translate\"\n >\n <mat-icon slot=\"icon-only\">refresh</mat-icon>\n </ion-button>\n }\n <!-- search button -->\n @if (!showSearchBar) {\n <ion-button (click)=\"toggleSearchBar()\">\n <ion-icon slot=\"icon-only\" name=\"search\"></ion-icon>\n </ion-button>\n }\n </ion-buttons>\n </ion-toolbar>\n\n <!-- search bar -->\n <ion-toolbar *ngIf=\"showSearchBar\">\n <ion-searchbar\n #searchbar\n animated\n type=\"search\"\n [class.cdk-visually-hidden]=\"!showSearchBar\"\n show-clear-button=\"always\"\n [placeholder]=\"'COMMON.BTN_SEARCH' | translate\"\n [cancelButtonText]=\"'COMMON.BTN_CANCEL' | translate\"\n [(ngModel)]=\"searchText\"\n (ionCancel)=\"toggleSearchBar()\"\n ></ion-searchbar>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n <mat-tab-group\n #tabGroup\n [(selectedIndex)]=\"selectedTabIndex\"\n class=\"mat-mdc-tab-disabled-hidden\"\n [class.mat-mdc-tab-group-header-hidden]=\"!enableSelectPeerByFeature\"\n [dynamicHeight]=\"false\"\n [mat-stretch-tabs]=\"mobile\"\n [animationDuration]=\"mobile ? tabGroupAnimationDuration : '0s'\"\n >\n <mat-tab>\n <ng-template mat-tab-label>\n <ion-label\n [matBadge]=\"filteredPeerCount$ | async | badgeNumber\"\n [matBadgeHidden]=\"filteredPeerCount$ | async | isNil\"\n [matBadgeColor]=\"(filteredPeerCount$ | async) ? 'primary' : 'accent'\"\n matBadgeOverlap=\"false\"\n matBadgeColor=\"primary\"\n matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n >\n {{ 'NETWORK.PEER.SELECT_MODAL.TAB_NETWORK' | translate }}\n </ion-label>\n </ng-template>\n <ion-list>\n <ion-list-header>\n <ion-label class=\"ion-text-wrap ion-padding-end\">\n <p [innerHTML]=\"'NETWORK.PEER.SELECT_MODAL.NETWORK_HELP' | translate\"></p>\n </ion-label>\n </ion-list-header>\n\n @for (peer of filteredPeers$ | async; track $index) {\n <ion-item\n (click)=\"selectPeer(peer)\"\n @fadeInAnimation\n [class.selected]=\"selectedPeer && selectedPeer === peer.url\"\n detail\n matRipple\n tappable\n >\n <!-- Peer is UP -->\n @if (peer.reachable) {\n <!-- icon -->\n @if (peer.favicon != 'skip') {\n <ion-avatar slot=\"start\">\n <ion-img [src]=\"peer.favicon || peer.url + '/api/favicon'\" (ionError)=\"clearLogo(peer)\"></ion-img>\n <ion-icon name=\"server\" class=\"icon-secondary\" style=\"top: 12px; left: 44px\" color=\"dark\"></ion-icon>\n </ion-avatar>\n } @else {\n <ion-icon slot=\"start\" name=\"server\" class=\"ion-icon-avatar\" color=\"dark\"></ion-icon>\n }\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <ion-label class=\"ion-text-wrap\">\n <ion-text>\n @let url = peer.hostAndPort + peer.path;\n <h3 [innerHTML]=\"url | highlight: searchText\"></h3>\n </ion-text>\n <ion-text color=\"primary\">\n <h4 [innerHTML]=\"peer.label | highlight: searchText\"></h4>\n </ion-text>\n </ion-label>\n </ion-col>\n <ion-col size=\"12\" size-sm=\"4\">\n <ion-label class=\"ion-text-wrap ion-text-sm-center\" color=\"medium\">\n <h4>\n <small>{{ peer.softwareName }}&nbsp;</small>\n <br class=\"hidden-xxs hidden-xs\" />\n <!-- Compatible -->\n @if (!peerMinVersion || isCompatible(peer)) {\n <small>v{{ peer.softwareVersion }}</small>\n } @else {\n <!-- Incompatible -->\n <ion-text\n color=\"danger\"\n [matTooltip]=\"\n 'NETWORK.PEER.SELECT_MODAL.NOT_COMPATIBLE_HELP' | translate: { version: peerMinVersion }\n \"\n >\n <small class=\"ion-color-danger\">\n <mat-icon>warning</mat-icon>\n v{{ peer.softwareVersion }}\n </small>\n </ion-text>\n }\n </h4>\n </ion-label>\n </ion-col>\n </ion-row>\n </ion-grid>\n } @else {\n <!-- Peer is DOWN -->\n <ion-icon slot=\"start\" name=\"server\" class=\"disabled ion-icon-avatar\"></ion-icon>\n\n <ion-label class=\"ion-text-wrap\">\n <ion-text color=\"medium\">\n <h3>{{ peer.hostAndPort }}{{ peer.path }}</h3>\n </ion-text>\n <ion-text color=\"danger\">\n <h4>\n <small>\n <ion-icon size=\"small\" name=\"close-circle\"></ion-icon>\n </small>\n <span translate>NETWORK.PEER.OFFLINE</span>\n </h4>\n </ion-text>\n </ion-label>\n }\n </ion-item>\n }\n\n <!-- no result -->\n @if ((filteredPeerCount$ | async) === 0) {\n <ion-item>\n <ion-text color=\"danger\" class=\"text-italic\" translate>COMMON.NO_RESULT</ion-text>\n </ion-item>\n }\n </ion-list>\n </mat-tab>\n\n <!-- Select by features -->\n <mat-tab [disabled]=\"!enableSelectPeerByFeature\">\n <ng-template mat-tab-label>\n <ion-label\n [matBadge]=\"filteredFeaturesCount$ | async | badgeNumber\"\n [matBadgeHidden]=\"filteredFeaturesCount$ | async | isNil\"\n [matBadgeColor]=\"(filteredFeaturesCount$ | async) ? 'primary' : 'accent'\"\n matBadgeOverlap=\"false\"\n matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n >\n {{ 'NETWORK.PEER.SELECT_MODAL.TAB_FEATURES' | translate }}\n </ion-label>\n </ng-template>\n <ion-list>\n <ion-list-header>\n <ion-label class=\"ion-text-wrap ion-padding-end\">\n <p [innerHTML]=\"'NETWORK.PEER.SELECT_MODAL.FEATURES_HELP' | translate\"></p>\n </ion-label>\n </ion-list-header>\n\n @for (peer of filteredPeersByFeatures$ | async; track $index) {\n @let peerUrl = peer.hostAndPort + peer.path;\n <!-- Peer is UP -->\n @if (peer.reachable && peer.features | isNotEmptyArray) {\n @let collapsed = collapsedPeers[peerUrl];\n\n <ion-item-divider (click)=\"togglePeerFeatures(peerUrl)\" tappable @fadeInAnimation>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <ion-label>\n <h4>\n <ion-icon name=\"server\" color=\"medium\"></ion-icon>\n {{ peer.hostAndPort }}{{ peer.path }}\n </h4>\n @if (peerMinVersion && !isCompatible(peer)) {\n <ion-text\n color=\"danger\"\n [matTooltip]=\"\n 'NETWORK.PEER.SELECT_MODAL.NOT_COMPATIBLE_HELP' | translate: { version: peerMinVersion }\n \"\n >\n <h4 class=\"ion-color-danger\">\n <small>\n <mat-icon>warning</mat-icon>\n v{{ peer.softwareVersion }}\n </small>\n </h4>\n </ion-text>\n }\n </ion-label>\n </ion-col>\n <ion-col size=\"4\" class=\"ion-text-end\">\n <ion-label class=\"text-italic\">\n <h4>({{ 'COMMON.RESULT_COUNT' | translate: { count: peer.features.length } }})</h4>\n </ion-label>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <mat-icon slot=\"end\">\n @if (collapsed) {\n {{ mobile ? 'arrow_drop_down' : 'keyboard_arrow_down' }}\n } @else {\n {{ mobile ? 'arrow_drop_up' : 'keyboard_arrow_up' }}\n }\n </mat-icon>\n </ion-item-divider>\n\n @if (!collapsed) {\n @for (feature of peer.features; track feature.label) {\n <ion-item (click)=\"selectPeer(peer)\" tappable matRipple detail @fadeInAnimation>\n <!-- icon -->\n @if (feature.logo && feature.logo != 'skip') {\n <ion-avatar slot=\"start\">\n <ion-img [src]=\"feature.logo\" (ionError)=\"clearLogo(feature)\"></ion-img>\n </ion-avatar>\n } @else if (peer.favicon != 'skip') {\n <ion-avatar slot=\"start\">\n <ion-img [src]=\"peer.favicon || peer.url + '/api/favicon'\" (ionError)=\"clearLogo(peer)\"></ion-img>\n <ion-icon\n name=\"contract\"\n class=\"icon-secondary\"\n style=\"top: 12px; left: 44px\"\n color=\"dark\"\n ></ion-icon>\n </ion-avatar>\n } @else {\n <ion-icon slot=\"start\" name=\"contract\" class=\"ion-icon-avatar\" color=\"dark\"></ion-icon>\n }\n\n <ion-label class=\"ion-text-wrap\">\n <ion-text color=\"primary\">\n <h3 [innerHTML]=\"feature | referentialToString | highlight: searchText\"></h3>\n </ion-text>\n <ion-text>\n <p [innerHTML]=\"feature.description | highlight: searchText\"></p>\n </ion-text>\n </ion-label>\n </ion-item>\n }\n }\n }\n }\n\n <!-- no result -->\n @if ((filteredFeaturesCount$ | async) === 0) {\n <ion-item>\n <ion-text color=\"danger\" class=\"text-italic\" translate>COMMON.NO_RESULT</ion-text>\n </ion-item>\n }\n </ion-list>\n </mat-tab>\n </mat-tab-group>\n</ion-content>\n\n@if ((canCancel && !mobile) || showSetManuallyButton) {\n <ion-footer>\n <ion-toolbar>\n <ion-row class=\"ion-no-padding ion-text-nowrap\">\n <ion-col></ion-col>\n\n <!-- buttons -->\n @if (showSetManuallyButton) {\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" (click)=\"clickSetManually($event)\">\n <ion-label translate>NETWORK.PEER.SELECT_MODAL.BTN_SET_MANUALLY</ion-label>\n </ion-button>\n </ion-col>\n }\n\n @if (canCancel) {\n <ion-col size=\"auto\" hidden-xs hidden-sm hidden-mobile>\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n </ion-col>\n }\n </ion-row>\n </ion-toolbar>\n </ion-footer>\n}\n", styles: [".mat-mdc-tab-group{height:100%}.mat-mdc-tab-group .mat-tab-body-wrapper{height:calc(100% - var(--mat-tab-header-height))}ion-item-divider .ion-icon-avatar,ion-item .ion-icon-avatar{-webkit-margin-end:16px;margin-inline-end:16px;font-size:40px;width:40px;height:40px}ion-item-divider .ion-icon-avatar.disabled,ion-item .ion-icon-avatar.disabled{color:rgba(var(--ion-color-medium-rgb),.7)}ion-item-divider h4 ion-icon,ion-item-divider h4 mat-icon,ion-item h4 ion-icon,ion-item h4 mat-icon{height:14px;width:14px;font-size:14px;line-height:14px}ion-item-divider h4 small ion-icon,ion-item-divider h4 small mat-icon,ion-item h4 small ion-icon,ion-item h4 small mat-icon{height:12px;width:12px;font-size:12px;line-height:12px}ion-item-divider.selected,ion-item.selected{--ion-color-base: var(--ion-color-secondary100-contrast) !important;--ion-item-background: var(--ion-color-secondary100)}\n"] }]
307
+ }], ctorParameters: () => [{ type: i1.ModalController }, { type: i1.PopoverController }, { type: i2.TranslateService }, { type: i3.HttpClient }, { type: i0.ChangeDetectorRef }, { type: i16.Environment, decorators: [{
182
308
  type: Inject,
183
309
  args: [ENVIRONMENT]
184
310
  }] }, { type: undefined, decorators: [{
@@ -186,7 +312,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.11", ngImpo
186
312
  }, {
187
313
  type: Inject,
188
314
  args: [APP_LOGGING_SERVICE]
189
- }] }], propDecorators: { selectedPeer: [{
315
+ }] }], propDecorators: { selectedTabIndex: [{
316
+ type: Input,
317
+ args: [{ transform: numberAttribute }]
318
+ }], selectedPeer: [{
319
+ type: Input
320
+ }], title: [{
190
321
  type: Input
191
322
  }], canCancel: [{
192
323
  type: Input,
@@ -197,7 +328,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.11", ngImpo
197
328
  }], showSetManuallyButton: [{
198
329
  type: Input,
199
330
  args: [{ transform: booleanAttribute }]
331
+ }], showSearchBar: [{
332
+ type: Input,
333
+ args: [{ transform: booleanAttribute }]
334
+ }], tabGroupAnimationDuration: [{
335
+ type: Input
200
336
  }], onRefresh: [{
201
337
  type: Input
338
+ }], defaultPeers: [{
339
+ type: Input
340
+ }], searchbar: [{
341
+ type: ViewChild,
342
+ args: ['searchbar', { static: true }]
202
343
  }] } });
203
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VsZWN0LXBlZXIubW9kYWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBwL2NvcmUvcGVlci9zZWxlY3QtcGVlci5tb2RhbC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcHAvY29yZS9wZWVyL3NlbGVjdC1wZWVyLm1vZGFsLmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLGdCQUFnQixFQUNoQix1QkFBdUIsRUFFdkIsU0FBUyxFQUNULFlBQVksRUFDWixNQUFNLEVBQ04sS0FBSyxFQUVMLFFBQVEsR0FDVCxNQUFNLGVBQWUsQ0FBQztBQUV2QixPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDcEQsT0FBTyxFQUFjLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDekQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDJDQUEyQyxDQUFDO0FBRTVFLE9BQU8sRUFBRSxZQUFZLEVBQVksTUFBTSwyQkFBMkIsQ0FBQztBQUNuRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDN0QsT0FBTyxFQUFlLFdBQVcsRUFBRSxNQUFNLHlDQUF5QyxDQUFDO0FBQ25GLE9BQU8sRUFBRSxXQUFXLEVBQXNCLE1BQU0sNkNBQTZDLENBQUM7QUFFOUYsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ2xELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM1QyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDOUQsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sNENBQTRDLENBQUM7Ozs7Ozs7Ozs7O0FBa0JqRixNQUFNLE9BQU8sZUFBZTtJQWtCaEI7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUN1QjtJQUNvQjtJQXZCN0MsYUFBYSxHQUFHLElBQUksWUFB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ZTtTQUMxQixDQUFDLENBQUM7UUFFSCxNQUFNLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUN0QixNQUFNLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxHQUFHLE1BQU0sS0FBSyxDQUFDLFlBQVksRUFBRSxDQUFDO1FBRWxELElBQUksSUFBSSxFQUFFLENBQUM7WUFDVCxPQUFPLENBQUMsSUFBSSxDQUFDLGtCQUFrQixFQUFFLElBQUksQ0FBQyxDQUFDO1lBQ3ZDLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztJQUNILENBQUM7SUFFUyxZQUFZO1FBQ3BCLElBQUksQ0FBQyxFQUFFLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDekIsQ0FBQzt3R0FwS1UsZUFBZSw2S0F1QmhCLFdBQVcsYUFDQyxtQkFBbUI7NEZBeEI5QixlQUFlLCtHQVdOLGdCQUFnQix1RUFDaEIsZ0JBQWdCLDZFQUNoQixnQkFBZ0IscURDdkR0QywwaEpBeUlBLG9uSURqR2MsQ0FBQyxlQUFlLENBQUM7OzRGQUVsQixlQUFlO2tCQVAzQixTQUFTOytCQUNFLG1CQUFtQixtQkFHWix1QkFBdUIsQ0FBQyxNQUFNLGNBQ25DLENBQUMsZUFBZSxDQUFDOzswQkF5QjFCLE1BQU07MkJBQUMsV0FBVzs7MEJBQ2xCLFFBQVE7OzBCQUFJLE1BQU07MkJBQUMsbUJBQW1CO3lDQWRoQyxZQUFZO3NCQUFwQixLQUFLO2dCQUNrQyxTQUFTO3NCQUFoRCxLQUFLO3VCQUFDLEVBQUUsU0FBUyxFQUFFLGdCQUFnQixFQUFFO2dCQUNFLG1CQUFtQjtzQkFBMUQsS0FBSzt1QkFBQyxFQUFFLFNBQVMsRUFBRSxnQkFBZ0IsRUFBRTtnQkFDRSxxQkFBcUI7c0JBQTVELEtBQUs7dUJBQUMsRUFBRSxTQUFTLEVBQUUsZ0JBQWdCLEVBQUU7Z0JBRTdCLFNBQVM7c0JBQWpCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBib29sZWFuQXR0cmlidXRlLFxuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gIENvbXBvbmVudCxcbiAgRXZlbnRFbWl0dGVyLFxuICBJbmplY3QsXG4gIElucHV0LFxuICBPbkRlc3Ryb3ksXG4gIE9wdGlvbmFsLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IE1vZGFsQ29udHJvbGxlciwgUG9wb3ZlckNvbnRyb2xsZXIgfSBmcm9tICdAaW9uaWMvYW5ndWxhcic7XG5pbXBvcnQgeyBQZWVyIH0gZnJvbSAnLi4vc2VydmljZXMvbW9kZWwvcGVlci5tb2RlbCc7XG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBTdWJqZWN0LCBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGZhZGVJbkFuaW1hdGlvbiB9IGZyb20gJy4uLy4uL3NoYXJlZC9tYXRlcmlhbC9tYXRlcmlhbC5hbmltYXRpb25zJztcbmltcG9ydCB7IEh0dHBDbGllbnQgfSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCc7XG5pbXBvcnQgeyBOZXR3b3JrVXRpbHMsIE5vZGVJbmZvIH0gZnJvbSAnLi4vc2VydmljZXMvbmV0d29yay51dGlscyc7XG5pbXBvcnQgeyBWZXJzaW9uVXRpbHMgfSBmcm9tICcuLi8uLi9zaGFyZWQvdmVyc2lvbi92ZXJzaW9ucyc7XG5pbXBvcnQgeyBFbnZpcm9ubWVudCwgRU5WSVJPTk1FTlQgfSBmcm9tICcuLi8uLi8uLi9lbnZpcm9ubWVudHMvZW52aXJvbm1lbnQuY2xhc3MnO1xuaW1wb3J0IHsgVGV4dFBvcG92ZXIsIFRleHRQb3BvdmVyT3B0aW9ucyB9IGZyb20gJy4uL2Zvcm0vdGV4dC1wb3BvdmVyL3RleHQtcG9wb3Zlci5jb21wb25lbnQnO1xuaW1wb3J0IHsgVHJhbnNsYXRlU2VydmljZSB9IGZyb20gJ0BuZ3gtdHJhbnNsYXRlL2NvcmUnO1xuaW1wb3J0IHsgaXNNb2JpbGUgfSBmcm9tICcuLi8uLi9zaGFyZWQvcGxhdGZvcm1zJztcbmltcG9ydCB7IFZhbGlkYXRvcnMgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBQRUVSX1VSTF9SRUdFWFAgfSBmcm9tICcuLi9zZXJ2aWNlcy9uZXR3b3JrLnNlcnZpY2UnO1xuaW1wb3J0IHsgQVBQX0xPR0dJTkdfU0VSVklDRSB9IGZyb20gJy4uLy4uL3NoYXJlZC9sb2dnaW5nL2xvZ2dpbmctc2VydmljZS5jbGFzcyc7XG5pbXBvcnQgeyBJTG9nZ2VyLCBJTG9nZ2luZ1NlcnZpY2UgfSBmcm9tICcuLi8uLi9zaGFyZWQvbG9nZ2luZy9sb2dnZXIubW9kZWwnO1xuXG5leHBvcnQgaW50ZXJmYWNlIElTZWxlY3RQZWVyTW9kYWxPcHRpb25zIHtcbiAgY2FuQ2FuY2VsOiBib29sZWFuO1xuICBhbGxvd1NlbGVjdERvd25QZWVyOiBib29sZWFuO1xuICBvblJlZnJlc2g6IEV2ZW50RW1pdHRlcjxFdmVudD47XG4gIHNob3dTZXRNYW51YWxseUJ1dHRvbjogYm9vbGVhbjtcbiAgc2VsZWN0ZWRQZWVyPzogc3RyaW5nO1xufVxuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdzZWxlY3QtcGVlci1tb2RhbCcsXG4gIHRlbXBsYXRlVXJsOiAnc2VsZWN0LXBlZXIubW9kYWwuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL3NlbGVjdC1wZWVyLm1vZGFsLnNjc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gIGFuaW1hdGlvbnM6IFtmYWRlSW5BbmltYXRpb25dLFxufSlcbmV4cG9ydCBjbGFzcyBTZWxlY3RQZWVyTW9kYWwgaW1wbGVtZW50cyBPbkRlc3Ryb3ksIElTZWxlY3RQZWVyTW9kYWxPcHRpb25zIHtcbiAgcHJpdmF0ZSBfc3Vic2NyaXB0aW9uID0gbmV3IFN1YnNjcmlwdGlvbigpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9sb2dnZXI6IElMb2dnZXI7XG5cbiAgcHJvdGVjdGVkIGxvYWRpbmcgPSB0cnVlO1xuICBwcm90ZWN0ZWQgbW9iaWxlOiBib29sZWFuO1xuICBwcm90ZWN0ZWQgJHBlZXJzID0gbmV3IFN1YmplY3Q8UGVlcltdPigpO1xuICBwcm90ZWN0ZWQgcGVlck1pblZlcnNpb246IHN0cmluZztcbiAgcHJvdGVjdGVkIHBlZXJEZWZhdWx0UHJlZml4OiBzdHJpbmc7XG5cbiAgQElucHV0KCkgc2VsZWN0ZWRQZWVyOiBzdHJpbmc7XG4gIEBJbnB1dCh7IHRyYW5zZm9ybTogYm9vbGVhbkF0dHJpYnV0ZSB9KSBjYW5DYW5jZWwgPSB0cnVlO1xuICBASW5wdXQoeyB0cmFuc2Zvcm06IGJvb2xlYW5BdHRyaWJ1dGUgfSkgYWxsb3dTZWxlY3REb3duUGVlciA9IHRydWU7XG4gIEBJbnB1dCh7IHRyYW5zZm9ybTogYm9vbGVhbkF0dHJpYnV0ZSB9KSBzaG93U2V0TWFudWFsbHlCdXR0b24gPSB0cnVlO1xuXG4gIEBJbnB1dCgpIG9uUmVmcmVzaCA9IG5ldyBFdmVudEVtaXR0ZXI8RXZlbnQ+KCk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBtb2RhbEN0cmw6IE1vZGFsQ29udHJvbGxlcixcbiAgICBwcml2YXRlIHBvcG92ZXJDb250cm9sbGVyOiBQb3BvdmVyQ29udHJvbGxlcixcbiAgICBwcml2YXRlIHRyYW5zbGF0ZTogVHJhbnNsYXRlU2VydmljZSxcbiAgICBwcml2YXRlIGh0dHA6IEh0dHBDbGllbnQsXG4gICAgcHJpdmF0ZSBjZDogQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgQEluamVjdChFTlZJUk9OTUVOVCkgcHJvdGVjdGVkIGVudmlyb25tZW50OiBFbnZpcm9ubWVudCxcbiAgICBAT3B0aW9uYWwoKSBASW5qZWN0KEFQUF9MT0dHSU5HX1NFUlZJQ0UpIHByb3RlY3RlZCBsb2dnaW5nU2VydmljZT86IElMb2dnaW5nU2VydmljZVxuICApIHtcbiAgICB0aGlzLm1vYmlsZSA9IGlzTW9iaWxlKHdpbmRvdyk7XG4gICAgdGhpcy5fbG9nZ2VyID0gbG9nZ2luZ1NlcnZpY2U/LmdldExvZ2dlcignbmV0d29yay1tb2RhbCcpO1xuICAgIHRoaXMucGVlck1pblZlcnNpb24gPSBlbnZpcm9ubWVudC5wZWVyTWluVmVyc2lvbjtcbiAgICB0aGlzLnBlZXJEZWZhdWx0UHJlZml4ID0gZW52aXJvbm1lbnQucGVlckRlZmF1bHRQcmVmaXggfHwgJ2h0dHBzOi8vJztcbiAgfVxuXG4gIHNldCBwZWVycyhwZWVyczogT2JzZXJ2YWJsZTxQZWVyW10+KSB7XG4gICAgdGhpcy5fc3Vic2NyaXB0aW9uLmFkZChwZWVycy5zdWJzY3JpYmUoKHJlcykgPT4gdGhpcy5yZWZyZXNoUGVlcnMocmVzKSkpO1xuICB9XG5cbiAgY2FuY2VsKCkge1xuICAgIHRoaXMubW9kYWxDdHJsLmRpc21pc3MoKTtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuX3N1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICB9XG5cbiAgc2VsZWN0UGVlcihwZWVyOiBQZWVyKSB7XG4gICAgaWYgKHRoaXMuYWxsb3dTZWxlY3REb3duUGVlciB8fCAocGVlci5yZWFjaGFibGUgJiYgdGhpcy5pc0NvbXBhdGlibGUocGVlcikpKSB7XG4gICAgICBjb25zb2xlLmRlYnVnKGBbc2VsZWN0LXBlZXItbW9kYWxdIFNlbGVjdGVkIHBlZXI6IHt1cmw6ICcke3BlZXIudXJsfSd9YCk7XG4gICAgICB0aGlzLnNlbGVjdGVkUGVlciA9IHBlZXIudXJsO1xuICAgICAgdGhpcy5tb2RhbEN0cmwuZGlzbWlzcyhwZWVyKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogIENoZWNrIHRoZSBtaW4gcG9kIHZlcnNpb24sIGRlZmluZWQgYnkgdGhlIGFwcFxuICAgKlxuICAgKiBAcGFyYW0gcGVlclxuICAgKi9cbiAgaXNDb21wYXRpYmxlKHBlZXI6IFBlZXIpOiBib29sZWFuIHtcbiAgICByZXR1cm4gIXRoaXMucGVlck1pblZlcnNpb24gfHwgKHBlZXIgJiYgcGVlci5zb2Z0d2FyZVZlcnNpb24gJiYgVmVyc2lvblV0aWxzLmlzQ29tcGF0aWJsZSh0aGlzLnBlZXJNaW5WZXJzaW9uLCBwZWVyLnNvZnR3YXJlVmVyc2lvbikpO1xuICB9XG5cbiAgcmVmcmVzaChldmVudDogRXZlbnQpIHtcbiAgICB0aGlzLmxvYWRpbmcgPSB0cnVlO1xuICAgIHRoaXMub25SZWZyZXNoLmVtaXQoZXZlbnQpO1xuICB9XG5cbiAgYXN5bmMgY2xpY2tTZXRNYW51YWxseShldmVudD86IEV2ZW50KSB7XG4gICAgY29uc3QgcGVlclVybCA9IGF3YWl0IHRoaXMub3BlblBlZXJVcmxQb3BvdmVyKGV2ZW50KTtcbiAgICBpZiAocGVlclVybCkge1xuICAgICAgY29uc3QgcGVlciA9IFBlZXIucGFyc2VVcmwocGVlclVybCk7XG4gICAgICBhd2FpdCB0aGlzLnJlZnJlc2hQZWVyKHBlZXIpO1xuICAgICAgdGhpcy5zZWxlY3RQZWVyKHBlZXIpO1xuICAgIH1cbiAgfVxuXG4gIC8qIC0tIHByb3RlY3RlZCBtZXRob2RzIC0tICovXG5cbiAgYXN5bmMgcmVmcmVzaFBlZXJzKHBlZXJzOiBQZWVyW10pIHtcbiAgICBwZWVycyA9IHBlZXJzIHx8IFtdO1xuXG4gICAgY29uc3QgZGF0YTogUGVlcltdID0gW107XG4gICAgY29uc3Qgam9icyA9IFByb21pc2UuYWxsKFxuICAgICAgcGVlcnMubWFwKGFzeW5jIChwZWVyKSA9PiB7XG4gICAgICAgIGF3YWl0IHRoaXMucmVmcmVzaFBlZXIocGVlcik7XG5cbiAgICAgICAgaWYgKHRoaXMuX3N1YnNjcmlwdGlvbi5jbG9zZWQpIHJldHVybjsgLy8gY29tcG9uZW50IGRlc3Ryb3llZFxuXG4gICAgICAgIGRhdGEucHVzaChwZWVyKTtcblxuICAgICAgICAvLyBTb3J0IChieSByZWFjaGFibGUsIHRoZW4gaG9zdClcbiAgICAgICAgZGF0YS5zb3J0KChhLCBiKSA9PiB7XG4gICAgICAgICAgaWYgKGEucmVhY2hhYmxlICYmICFiLnJlYWNoYWJsZSkgcmV0dXJuIC0xO1xuICAgICAgICAgIGlmICghYS5yZWFjaGFibGUgJiYgYi5yZWFjaGFibGUpIHJldHVybiAxO1xuICAgICAgICAgIGlmIChhLmhvc3RBbmRQb3J0IDwgYi5ob3N0QW5kUG9ydCkgcmV0dXJuIC0xO1xuICAgICAgICAgIGlmIChhLmhvc3RBbmRQb3J0ID4gYi5ob3N0QW5kUG9ydCkgcmV0dXJuIDE7XG4gICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuJHBlZXJzLm5leHQoZGF0YSk7XG4gICAgICAgIHJldHVybiBwZWVyO1xuICAgICAgfSlcbiAgICApO1xuXG4gICAgdGhpcy5fc3Vic2NyaXB0aW9uLmFkZCh0aGlzLiRwZWVycy5zdWJzY3JpYmUoKCkgPT4gdGhpcy5jZC5tYXJrRm9yQ2hlY2soKSkpO1xuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGpvYnM7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBpZiAoIXRoaXMuX3N1YnNjcmlwdGlvbi5jbG9zZWQpIGNvbnNvbGUuZXJyb3IoZXJyKTtcbiAgICB9XG4gICAgdGhpcy5sb2FkaW5nID0gZmFsc2U7XG4gICAgdGhpcy5jZC5tYXJrRm9yQ2hlY2soKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyByZWZyZXNoUGVlcihwZWVyOiBQZWVyKTogUHJvbWlzZTxQZWVyPiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHN1bW1hcnk6IE5vZGVJbmZvID0gYXdhaXQgTmV0d29ya1V0aWxzLmdldE5vZGVJbmZvKHRoaXMuaHR0cCwgcGVlci51cmwpO1xuICAgICAgcGVlci5zdGF0dXMgPSAnVVAnO1xuICAgICAgcGVlci5zb2Z0d2FyZU5hbWUgPSBzdW1tYXJ5LnNvZnR3YXJlTmFtZTtcbiAgICAgIHBlZXIuc29mdHdhcmVWZXJzaW9uID0gc3VtbWFyeS5zb2Z0d2FyZVZlcnNpb247XG4gICAgICBwZWVyLmxhYmVsID0gc3VtbWFyeS5ub2RlTGFiZWw7XG4gICAgICBwZWVyLm5hbWUgPSBzdW1tYXJ5Lm5vZGVOYW1lO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgLy8gSWYgbW9kYWwgd2FzIG5vdCBjbG9zZWQgKGUuZy4gcmVzcG9uc2UgYXJyaXZlZCB0b28gbGF0ZSA9PiBpZ25vcmUpXG4gICAgICBpZiAoIXRoaXMuX3N1YnNjcmlwdGlvbi5jbG9zZWQpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihgW3NlbGVjdC1wZWVyXSBFcnJvciB3aGlsZSBjYWxsaW5nICcke3BlZXIudXJsfS9hcGkvbm9kZS9pbmZvJzogJHtlcnI/Lm1lc3NhZ2UgfHwgZXJyfWAsIGVycik7XG4gICAgICAgIHRoaXMuX2xvZ2dlcj8uZXJyb3IoJ3JlZnJlc2hQZWVyJywgYEVycm9yIHdoaWxlIGNhbGxpbmcgJyR7cGVlci51cmx9L2FwaS9ub2RlL2luZm8nOiAke2Vycj8ubWVzc2FnZSB8fCBKU09OLnN0cmluZ2lmeShlcnIpfWApO1xuICAgICAgfVxuICAgICAgcGVlci5zdGF0dXMgPSAnRE9XTic7XG4gICAgfVxuICAgIHJldHVybiBwZWVyO1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIG9wZW5QZWVyVXJsUG9wb3ZlcihldmVudDogRXZlbnQsIG9wdHM/OiBQYXJ0aWFsPFRleHRQb3BvdmVyT3B0aW9ucz4pIHtcbiAgICBjb25zdCBtb2RhbCA9IGF3YWl0IHRoaXMucG9wb3ZlckNvbnRyb2xsZXIuY3JlYXRlKHtcbiAgICAgIGNvbXBvbmVudDogVGV4dFBvcG92ZXIsXG4gICAgICBjb21wb25lbnRQcm9wczogPFRleHRQb3BvdmVyT3B0aW9ucz57XG4gICAgICAgIHBsYWNlaG9sZGVyOiB0aGlzLnRyYW5zbGF0ZS5pbnN0YW50KCdTRVRUSU5HUy5QRUVSX1VSTCcpLFxuICAgICAgICBtdWx0aWxpbmU6IGZhbHNlLFxuICAgICAgICBhdXRvZm9jdXM6ICF0aGlzLm1vYmlsZSxcbiAgICAgICAgYXV0b2NvbXBsZXRlOiBmYWxzZSxcbiAgICAgICAgdmFsaWRhdG9yOiBWYWxpZGF0b3JzLnBhdHRlcm4oUEVFUl9VUkxfUkVHRVhQKSxcbiAgICAgICAgbWF4TGVuZ3RoOiBudWxsLFxuICAgICAgICB0ZXh0OiB0aGlzLnNlbGVjdGVkUGVlciB8fCB0aGlzLnBlZXJEZWZhdWx0UHJlZml4LFxuICAgICAgICAuLi5vcHRzLFxuICAgICAgfSxcbiAgICAgIGJhY2tkcm9wRGlzbWlzczogZmFsc2UsXG4gICAgICBrZXlib2FyZENsb3NlOiBmYWxzZSxcbiAgICAgIGV2ZW50OiBudWxsLCAvLyBJTVBPUlRBTlQ6IG51bGwgZXZlbnQgd2lsbCBjZW50ZXIgdGhlIHBvcG92ZXIsIGFuZCB0aGlzIHdpbGwgZml4IGtleWJvYXJkIG92ZXJsYXAgb24gbW9iaWxlXG4gICAgICB0cmFuc2x1Y2VudDogdHJ1ZSxcbiAgICAgIGNzc0NsYXNzOiAncG9wb3Zlci1sYXJnZScsXG4gICAgfSk7XG5cbiAgICBhd2FpdCBtb2RhbC5wcmVzZW50KCk7XG4gICAgY29uc3QgeyBkYXRhLCByb2xlIH0gPSBhd2FpdCBtb2RhbC5vbkRpZERpc21pc3MoKTtcblxuICAgIGlmIChkYXRhKSB7XG4gICAgICBjb25zb2xlLmluZm8oJ1BvcG92ZXIgcmVzdWx0OiAnLCBkYXRhKTtcbiAgICAgIHJldHVybiBkYXRhO1xuICAgIH1cbiAgfVxuXG4gIHByb3RlY3RlZCBtYXJrRm9yQ2hlY2soKSB7XG4gICAgdGhpcy5jZC5tYXJrRm9yQ2hlY2soKTtcbiAgfVxufVxuIiwiPGlvbi1oZWFkZXI+XG4gIDxpb24tdG9vbGJhciBjb2xvcj1cImxpZ2h0XCI+XG4gICAgPGlvbi1idXR0b25zIHNsb3Q9XCJzdGFydFwiPlxuICAgICAgPGlvbi1idXR0b24gKGNsaWNrKT1cImNhbmNlbCgpXCIgKm5nSWY9XCJjYW5DYW5jZWxcIiB2aXNpYmxlLXhzIHZpc2libGUtc20gdmlzaWJsZS1tb2JpbGU+XG4gICAgICAgIDxpb24taWNvbiBzbG90PVwiaWNvbi1vbmx5XCIgbmFtZT1cImFycm93LWJhY2tcIj48L2lvbi1pY29uPlxuICAgICAgPC9pb24tYnV0dG9uPlxuICAgIDwvaW9uLWJ1dHRvbnM+XG5cbiAgICA8aW9uLXRpdGxlPlxuICAgICAge3sgJ05FVFdPUksuUEVFUi5TRUxFQ1RfTU9EQUwuVElUTEUnIHwgdHJhbnNsYXRlIH19XG4gICAgPC9pb24tdGl0bGU+XG5cbiAgICA8aW9uLWJ1dHRvbnMgc2xvdD1cImVuZFwiPlxuICAgICAgPCEtLSBsb2FkZXIgLS0+XG4gICAgICA8aW9uLXNwaW5uZXIgKm5nSWY9XCJsb2FkaW5nOyBlbHNlIGVuZEJ1dHRvbnNcIj48L2lvbi1zcGlubmVyPlxuXG4gICAgICA8bmctdGVtcGxhdGUgI2VuZEJ1dHRvbnM+XG4gICAgICAgIDwhLS0gcmVmcmVzaCBidXR0b24gLS0+XG4gICAgICAgIDxpb24tYnV0dG9uXG4gICAgICAgICAgKm5nSWY9XCJvblJlZnJlc2gub2JzZXJ2ZWRcIlxuICAgICAgICAgIFttYXRUb29sdGlwXT1cIidDT01NT04uQlROX1JFRlJFU0gnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAoY2xpY2spPVwicmVmcmVzaCgkZXZlbnQpXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxtYXQtaWNvbiBzbG90PVwiaWNvbi1vbmx5XCI+cmVmcmVzaDwvbWF0LWljb24+XG4gICAgICAgIDwvaW9uLWJ1dHRvbj5cbiAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgPC9pb24tYnV0dG9ucz5cbiAgPC9pb24tdG9vbGJhcj5cbjwvaW9uLWhlYWRlcj5cblxuPGlvbi1jb250ZW50PlxuICA8aW9uLWxpc3Q+XG4gICAgPGlvbi1saXN0LWhlYWRlcj5cbiAgICAgIDxpb24tbGFiZWwgY2xhc3M9XCJpb24tdGV4dC13cmFwXCI+XG4gICAgICAgIDxwIHRyYW5zbGF0ZT5ORVRXT1JLLlBFRVIuU0VMRUNUX01PREFMLkhFTFA8L3A+XG4gICAgICA8L2lvbi1sYWJlbD5cbiAgICA8L2lvbi1saXN0LWhlYWRlcj5cblxuICAgIDxpb24taXRlbVxuICAgICAgKnJ4Rm9yPVwibGV0IHBlZXIgb2YgJHBlZXJzXCJcbiAgICAgIChjbGljayk9XCJzZWxlY3RQZWVyKHBlZXIpXCJcbiAgICAgIFtjbGFzcy5zZWxlY3RlZF09XCJzZWxlY3RlZFBlZXIgJiYgc2VsZWN0ZWRQZWVyID09PSBwZWVyLnVybFwiXG4gICAgICB0YXBwYWJsZVxuICAgICAgbWF0UmlwcGxlXG4gICAgICBkZXRhaWxcbiAgICAgIEBmYWRlSW5BbmltYXRpb25cbiAgICA+XG4gICAgICA8IS0tIFBlZXIgaXMgVVAgLS0+XG4gICAgICBAaWYgKHBlZXIucmVhY2hhYmxlKSB7XG4gICAgICAgIDwhLS0gaWNvbiAtLT5cbiAgICAgICAgPGlvbi1hdmF0YXIgc2xvdD1cInN0YXJ0XCI+XG4gICAgICAgICAgPGlvbi1pbWcgW3NyY109XCJwZWVyLmZhdmljb24gfHwgcGVlci51cmwgKyAnL2FwaS9mYXZpY29uJ1wiPjwvaW9uLWltZz5cbiAgICAgICAgPC9pb24tYXZhdGFyPlxuXG4gICAgICAgIDxpb24tZ3JpZD5cbiAgICAgICAgICA8aW9uLXJvdyBjbGFzcz1cImlvbi1uby1wYWRkaW5nXCI+XG4gICAgICAgICAgICA8aW9uLWNvbCBjbGFzcz1cImlvbi1uby1wYWRkaW5nXCI+XG4gICAgICAgICAgICAgIDxpb24tbGFiZWwgY2xhc3M9XCJpb24tdGV4dC13cmFwXCI+XG4gICAgICAgICAgICAgICAgPGlvbi10ZXh0PlxuICAgICAgICAgICAgICAgICAgPGgzPnt7IHBlZXIuaG9zdEFuZFBvcnQgfX17eyBwZWVyLnBhdGggfX08L2gzPlxuICAgICAgICAgICAgICAgIDwvaW9uLXRleHQ+XG4gICAgICAgICAgICAgICAgPGlvbi10ZXh0IGNvbG9yPVwicHJpbWFyeVwiPlxuICAgICAgICAgICAgICAgICAgPGg0Pnt7IHBlZXIubGFiZWwgfX08L2g0PlxuICAgICAgICAgICAgICAgIDwvaW9uLXRleHQ+XG4gICAgICAgICAgICAgIDwvaW9uLWxhYmVsPlxuICAgICAgICAgICAgPC9pb24tY29sPlxuICAgICAgICAgICAgPGlvbi1jb2wgY2xhc3M9XCJpb24tbm8tcGFkZGluZ1wiPlxuICAgICAgICAgICAgICA8aW9uLWxhYmVsIGNsYXNzPVwiaW9uLXRleHQtd3JhcCBpb24tdGV4dC1jZW50ZXJcIiBjb2xvcj1cIm1lZGl1bVwiPlxuICAgICAgICAgICAgICAgIDxoMz57eyBwZWVyLnNvZnR3YXJlTmFtZSB9fTwvaDM+XG4gICAgICAgICAgICAgICAgPGg0ICpuZ0lmPVwiIXBlZXJNaW5WZXJzaW9uIHx8IGlzQ29tcGF0aWJsZShwZWVyKTsgZWxzZSBpbnZhbGlkVmVyc2lvblwiPlxuICAgICAgICAgICAgICAgICAgPHNtYWxsPnZ7eyBwZWVyLnNvZnR3YXJlVmVyc2lvbiB9fTwvc21hbGw+XG4gICAgICAgICAgICAgICAgPC9oND5cbiAgICAgICAgICAgICAgICA8bmctdGVtcGxhdGUgI2ludmFsaWRWZXJzaW9uPlxuICAgICAgICAgICAgICAgICAgPGlvbi10ZXh0XG4gICAgICAgICAgICAgICAgICAgIGNvbG9yPVwiZGFuZ2VyXCJcbiAgICAgICAgICAgICAgICAgICAgW21hdFRvb2x0aXBdPVwiXG4gICAgICAgICAgICAgICAgICAgICAgJ05FVFdPUksuUEVFUi5TRUxFQ1RfTU9EQUwuTk9UX0NPTVBBVElCTEVfSEVMUCcgfCB0cmFuc2xhdGU6IHsgdmVyc2lvbjogcGVlck1pblZlcnNpb24gfVxuICAgICAgICAgICAgICAgICAgICBcIlxuICAgICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgICA8aDQgY2xhc3M9XCJpb24tY29sb3ItZGFuZ2VyXCI+XG4gICAgICAgICAgICAgICAgICAgICAgPHNtYWxsPlxuICAgICAgICAgICAgICAgICAgICAgICAgPG1hdC1pY29uPndhcm5pbmc8L21hdC1pY29uPlxuICAgICAgICAgICAgICAgICAgICAgICAgdnt7IHBlZXIuc29mdHdhcmVWZXJzaW9uIH19XG4gICAgICAgICAgICAgICAgICAgICAgPC9zbWFsbD5cbiAgICAgICAgICAgICAgICAgICAgPC9oND5cbiAgICAgICAgICAgICAgICAgIDwvaW9uLXRleHQ+XG4gICAgICAgICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICAgICAgPC9pb24tbGFiZWw+XG4gICAgICAgICAgICA8L2lvbi1jb2w+XG4gICAgICAgICAgPC9pb24tcm93PlxuICAgICAgICA8L2lvbi1ncmlkPlxuICAgICAgfSBAZWxzZSB7XG4gICAgICAgIDwhLS0gUGVlciBpcyBET1dOIC0tPlxuICAgICAgICA8aW9uLWljb24gc2xvdD1cInN0YXJ0XCIgbmFtZT1cImRlc2t0b3BcIiBjbGFzcz1cImRpc2FibGVkIGlvbi1pY29uLWF2YXRhclwiPjwvaW9uLWljb24+XG5cbiAgICAgICAgPGlvbi1sYWJlbCBjbGFzcz1cImlvbi10ZXh0LXdyYXBcIj5cbiAgICAgICAgICA8aW9uLXRleHQgY29sb3I9XCJtZWRpdW1cIj5cbiAgICAgICAgICAgIDxoMz57eyBwZWVyLmhvc3RBbmRQb3J0IH19e3sgcGVlci5wYXRoIH19PC9oMz5cbiAgICAgICAgICA8L2lvbi10ZXh0PlxuICAgICAgICAgIDxpb24tdGV4dCBjb2xvcj1cImRhbmdlclwiPlxuICAgICAgICAgICAgPGg0PlxuICAgICAgICAgICAgICA8c21hbGw+PGlvbi1pY29uIHNpemU9XCJzbWFsbFwiIG5hbWU9XCJjbG9zZS1jaXJjbGVcIj48L2lvbi1pY29uPjwvc21hbGw+XG4gICAgICAgICAgICAgIDxzcGFuIHRyYW5zbGF0ZT5ORVRXT1JLLlBFRVIuT0ZGTElORTwvc3Bhbj5cbiAgICAgICAgICAgIDwvaDQ+XG4gICAgICAgICAgPC9pb24tdGV4dD5cbiAgICAgICAgPC9pb24tbGFiZWw+XG4gICAgICB9XG4gICAgPC9pb24taXRlbT5cbiAgPC9pb24tbGlzdD5cbjwvaW9uLWNvbnRlbnQ+XG5cbkBpZiAoKGNhbkNhbmNlbCAmJiAhbW9iaWxlKSB8fCBzaG93U2V0TWFudWFsbHlCdXR0b24pIHtcbiAgPGlvbi1mb290ZXI+XG4gICAgPGlvbi10b29sYmFyPlxuICAgICAgPGlvbi1yb3cgY2xhc3M9XCJpb24tbm8tcGFkZGluZyBpb24tdGV4dC1ub3dyYXBcIj5cbiAgICAgICAgPGlvbi1jb2w+PC9pb24tY29sPlxuXG4gICAgICAgIDwhLS0gYnV0dG9ucyAtLT5cbiAgICAgICAgQGlmIChzaG93U2V0TWFudWFsbHlCdXR0b24pIHtcbiAgICAgICAgICA8aW9uLWNvbCBzaXplPVwiYXV0b1wiPlxuICAgICAgICAgICAgPGlvbi1idXR0b24gZmlsbD1cImNsZWFyXCIgY29sb3I9XCJkYXJrXCIgKGNsaWNrKT1cImNsaWNrU2V0TWFudWFsbHkoJGV2ZW50KVwiPlxuICAgICAgICAgICAgICA8aW9uLWxhYmVsIHRyYW5zbGF0ZT5ORVRXT1JLLlBFRVIuU0VMRUNUX01PREFMLkJUTl9TRVRfTUFOVUFMTFk8L2lvbi1sYWJlbD5cbiAgICAgICAgICAgIDwvaW9uLWJ1dHRvbj5cbiAgICAgICAgICA8L2lvbi1jb2w+XG4gICAgICAgIH1cblxuICAgICAgICBAaWYgKGNhbkNhbmNlbCkge1xuICAgICAgICAgIDxpb24tY29sIHNpemU9XCJhdXRvXCIgaGlkZGVuLXhzIGhpZGRlbi1zbSBoaWRkZW4tbW9iaWxlPlxuICAgICAgICAgICAgPGlvbi1idXR0b24gZmlsbD1cImNsZWFyXCIgY29sb3I9XCJkYXJrXCIgKGNsaWNrKT1cImNhbmNlbCgpXCI+XG4gICAgICAgICAgICAgIDxpb24tbGFiZWwgdHJhbnNsYXRlPkNPTU1PTi5CVE5fQ0FOQ0VMPC9pb24tbGFiZWw+XG4gICAgICAgICAgICA8L2lvbi1idXR0b24+XG4gICAgICAgICAgPC9pb24tY29sPlxuICAgICAgICB9XG4gICAgICA8L2lvbi1yb3c+XG4gICAgPC9pb24tdG9vbGJhcj5cbiAgPC9pb24tZm9vdGVyPlxufVxuIl19
344
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VsZWN0LXBlZXIubW9kYWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBwL2NvcmUvcGVlci9zZWxlY3QtcGVlci5tb2RhbC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9hcHAvY29yZS9wZWVyL3NlbGVjdC1wZWVyLm1vZGFsLmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLGdCQUFnQixFQUNoQix1QkFBdUIsRUFFdkIsU0FBUyxFQUNULFlBQVksRUFDWixNQUFNLEVBQ04sS0FBSyxFQUNMLGVBQWUsRUFFZixRQUFRLEVBQ1IsU0FBUyxHQUNWLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwyQ0FBMkMsQ0FBQztBQUU1RSxPQUFPLEVBQUUsWUFBWSxFQUFZLE1BQU0sMkJBQTJCLENBQUM7QUFDbkUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQzdELE9BQU8sRUFBZSxXQUFXLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQztBQUNuRixPQUFPLEVBQUUsV0FBVyxFQUFzQixNQUFNLDZDQUE2QyxDQUFDO0FBRTlGLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDNUMsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQzlELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBRWpGLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNyQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7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QTFELEtBQUs7dUJBQUMsRUFBRSxTQUFTLEVBQUUsZ0JBQWdCLEVBQUU7Z0JBQ0UscUJBQXFCO3NCQUE1RCxLQUFLO3VCQUFDLEVBQUUsU0FBUyxFQUFFLGdCQUFnQixFQUFFO2dCQUNFLGFBQWE7c0JBQXBELEtBQUs7dUJBQUMsRUFBRSxTQUFTLEVBQUUsZ0JBQWdCLEVBQUU7Z0JBQzdCLHlCQUF5QjtzQkFBakMsS0FBSztnQkFFRyxTQUFTO3NCQUFqQixLQUFLO2dCQUVPLFlBQVk7c0JBQXhCLEtBQUs7Z0JBSW9DLFNBQVM7c0JBQWxELFNBQVM7dUJBQUMsV0FBVyxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIGJvb2xlYW5BdHRyaWJ1dGUsXG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgQ29tcG9uZW50LFxuICBFdmVudEVtaXR0ZXIsXG4gIEluamVjdCxcbiAgSW5wdXQsXG4gIG51bWJlckF0dHJpYnV0ZSxcbiAgT25EZXN0cm95LFxuICBPcHRpb25hbCxcbiAgVmlld0NoaWxkLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IElvblNlYXJjaGJhciwgTW9kYWxDb250cm9sbGVyLCBQb3BvdmVyQ29udHJvbGxlciB9IGZyb20gJ0Bpb25pYy9hbmd1bGFyJztcbmltcG9ydCB7IFBlZXIgfSBmcm9tICcuLi9zZXJ2aWNlcy9tb2RlbC9wZWVyLm1vZGVsJztcbmltcG9ydCB7IFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZmFkZUluQW5pbWF0aW9uIH0gZnJvbSAnLi4vLi4vc2hhcmVkL21hdGVyaWFsL21hdGVyaWFsLmFuaW1hdGlvbnMnO1xuaW1wb3J0IHsgSHR0cENsaWVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IE5ldHdvcmtVdGlscywgTm9kZUluZm8gfSBmcm9tICcuLi9zZXJ2aWNlcy9uZXR3b3JrLnV0aWxzJztcbmltcG9ydCB7IFZlcnNpb25VdGlscyB9IGZyb20gJy4uLy4uL3NoYXJlZC92ZXJzaW9uL3ZlcnNpb25zJztcbmltcG9ydCB7IEVudmlyb25tZW50LCBFTlZJUk9OTUVOVCB9IGZyb20gJy4uLy4uLy4uL2Vudmlyb25tZW50cy9lbnZpcm9ubWVudC5jbGFzcyc7XG5pbXBvcnQgeyBUZXh0UG9wb3ZlciwgVGV4dFBvcG92ZXJPcHRpb25zIH0gZnJvbSAnLi4vZm9ybS90ZXh0LXBvcG92ZXIvdGV4dC1wb3BvdmVyLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBUcmFuc2xhdGVTZXJ2aWNlIH0gZnJvbSAnQG5neC10cmFuc2xhdGUvY29yZSc7XG5pbXBvcnQgeyBpc01vYmlsZSB9IGZyb20gJy4uLy4uL3NoYXJlZC9wbGF0Zm9ybXMnO1xuaW1wb3J0IHsgVmFsaWRhdG9ycyB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IFBFRVJfVVJMX1JFR0VYUCB9IGZyb20gJy4uL3NlcnZpY2VzL25ldHdvcmsuc2VydmljZSc7XG5pbXBvcnQgeyBBUFBfTE9HR0lOR19TRVJWSUNFIH0gZnJvbSAnLi4vLi4vc2hhcmVkL2xvZ2dpbmcvbG9nZ2luZy1zZXJ2aWNlLmNsYXNzJztcbmltcG9ydCB7IElMb2dnZXIsIElMb2dnaW5nU2VydmljZSB9IGZyb20gJy4uLy4uL3NoYXJlZC9sb2dnaW5nL2xvZ2dlci5tb2RlbCc7XG5pbXBvcnQgeyBtYXAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBFbnRpdHlVdGlscyB9IGZyb20gJy4uL3NlcnZpY2VzL21vZGVsL2VudGl0eS5tb2RlbCc7XG5pbXBvcnQgeyBSeFN0YXRlIH0gZnJvbSAnQHJ4LWFuZ3VsYXIvc3RhdGUnO1xuaW1wb3J0IHsgc3VnZ2VzdEZyb21BcnJheSB9IGZyb20gJy4uLy4uL3NoYXJlZC9zZXJ2aWNlcyc7XG5pbXBvcnQgeyBpc05pbE9yQmxhbmssIGlzTm90RW1wdHlBcnJheSwgaXNOb3ROaWwgfSBmcm9tICcuLi8uLi9zaGFyZWQvZnVuY3Rpb25zJztcbmltcG9ydCB7IE5vZGVGZWF0dXJlIH0gZnJvbSAnLi4vc2VydmljZXMvbW9kZWwvbm9kZS1mZWF0dXJlLm1vZGVsJztcblxuZXhwb3J0IGludGVyZmFjZSBJU2VsZWN0UGVlck1vZGFsT3B0aW9ucyB7XG4gIGNhbkNhbmNlbDogYm9vbGVhbjtcbiAgYWxsb3dTZWxlY3REb3duUGVlcjogYm9vbGVhbjtcbiAgb25SZWZyZXNoOiBFdmVudEVtaXR0ZXI8RXZlbnQ+O1xuICBzaG93U2V0TWFudWFsbHlCdXR0b246IGJvb2xlYW47XG4gIHNlbGVjdGVkUGVlcj86IHN0cmluZztcbiAgdGl0bGU/OiBzdHJpbmc7XG4gIGRlZmF1bHRQZWVyczogUGVlcltdO1xuICBzaG93U2VhcmNoQmFyPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJU2VsZWN0UGVlck1vZGFsU3RhdGUge1xuICBkZWZhdWx0UGVlcnM6IFBlZXJbXTtcbiAgcGVlcnM6IFBlZXJbXTtcbiAgZmlsdGVyZWRQZWVyczogUGVlcltdO1xuICBmaWx0ZXJlZFBlZXJzQnlGZWF0dXJlczogUGVlcltdO1xuICBmaWx0ZXJlZFBlZXJDb3VudDogbnVtYmVyO1xuICBmaWx0ZXJlZEZlYXR1cmVzQ291bnQ6IG51bWJlcjtcbiAgc2VhcmNoVGV4dDogc3RyaW5nO1xuICBzZWxlY3RlZFRhYkluZGV4OiBudW1iZXI7XG59XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3NlbGVjdC1wZWVyLW1vZGFsJyxcbiAgdGVtcGxhdGVVcmw6ICdzZWxlY3QtcGVlci5tb2RhbC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vc2VsZWN0LXBlZXIubW9kYWwuc2NzcyddLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgYW5pbWF0aW9uczogW2ZhZGVJbkFuaW1hdGlvbl0sXG59KVxuZXhwb3J0IGNsYXNzIFNlbGVjdFBlZXJNb2RhbCBleHRlbmRzIFJ4U3RhdGU8SVNlbGVjdFBlZXJNb2RhbFN0YXRlPiBpbXBsZW1lbnRzIE9uRGVzdHJveSwgSVNlbGVjdFBlZXJNb2RhbE9wdGlvbnMge1xuICBwcml2YXRlIF9zdWJzY3JpcHRpb24gPSBuZXcgU3Vic2NyaXB0aW9uKCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX2xvZ2dlcjogSUxvZ2dlcjtcblxuICBwcm90ZWN0ZWQgZGVmYXVsdFBlZXJzJCA9IHRoaXMuc2VsZWN0KCdkZWZhdWx0UGVlcnMnKTtcbiAgcHJvdGVjdGVkIHBlZXJzJCA9IHRoaXMuc2VsZWN0KCdwZWVycycpO1xuICBwcm90ZWN0ZWQgZmlsdGVyZWRQZWVycyQgPSB0aGlzLnNlbGVjdCgnZmlsdGVyZWRQZWVycycpO1xuICBwcm90ZWN0ZWQgZmlsdGVyZWRQZWVyc0J5RmVhdHVyZXMkID0gdGhpcy5zZWxlY3QoJ2ZpbHRlcmVkUGVlcnNCeUZlYXR1cmVzJyk7XG4gIHByb3RlY3RlZCBmaWx0ZXJlZFBlZXJDb3VudCQgPSB0aGlzLnNlbGVjdCgnZmlsdGVyZWRQZWVyQ291bnQnKTtcbiAgcHJvdGVjdGVkIGZpbHRlcmVkRmVhdHVyZXNDb3VudCQgPSB0aGlzLnNlbGVjdCgnZmlsdGVyZWRGZWF0dXJlc0NvdW50Jyk7XG5cbiAgcHJvdGVjdGVkIGxvYWRpbmcgPSB0cnVlO1xuICBwcm90ZWN0ZWQgbW9iaWxlOiBib29sZWFuO1xuICBwcm90ZWN0ZWQgcGVlck1pblZlcnNpb246IHN0cmluZztcbiAgcHJvdGVjdGVkIHBlZXJEZWZhdWx0UHJlZml4OiBzdHJpbmc7XG4gIHByb3RlY3RlZCBlbmFibGVTZWxlY3RQZWVyQnlGZWF0dXJlOiBib29sZWFuO1xuICBwcm90ZWN0ZWQgY29sbGFwc2VkUGVlcnM6IHsgW2tleTogc3RyaW5nXTogYm9vbGVhbiB9ID0ge307XG5cbiAgc2V0IHBlZXJzKHZhbHVlOiBQZWVyW10pIHtcbiAgICB0aGlzLnNldCgncGVlcnMnLCAoKSA9PiB2YWx1ZSk7XG4gIH1cbiAgZ2V0IHBlZXJzKCk6IFBlZXJbXSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0KCdwZWVycycpO1xuICB9XG4gIHNldCBzZWFyY2hUZXh0KHZhbHVlOiBzdHJpbmcpIHtcbiAgICB0aGlzLnNldCgnc2VhcmNoVGV4dCcsICgpID0+IHZhbHVlKTtcbiAgfVxuICBnZXQgc2VhcmNoVGV4dCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmdldCgnc2VhcmNoVGV4dCcpO1xuICB9XG4gIHNldCBmaWx0ZXJlZFBlZXJzKHZhbHVlOiBQZWVyW10pIHtcbiAgICB0aGlzLnNldCgnZmlsdGVyZWRQZWVycycsICgpID0+IHZhbHVlKTtcbiAgfVxuICBnZXQgZmlsdGVyZWRQZWVycygpOiBQZWVyW10ge1xuICAgIHJldHVybiB0aGlzLmdldCgnZmlsdGVyZWRQZWVycycpO1xuICB9XG5cbiAgQElucHV0KHsgdHJhbnNmb3JtOiBudW1iZXJBdHRyaWJ1dGUgfSkgc2V0IHNlbGVjdGVkVGFiSW5kZXgodmFsdWU6IG51bWJlcikge1xuICAgIHRoaXMuc2V0KCdzZWxlY3RlZFRhYkluZGV4JywgKCkgPT4gdmFsdWUpO1xuICB9XG4gIGdldCBzZWxlY3RlZFRhYkluZGV4KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0KCdzZWxlY3RlZFRhYkluZGV4Jyk7XG4gIH1cblxuICBASW5wdXQoKSBzZWxlY3RlZFBlZXI6IHN0cmluZztcbiAgQElucHV0KCkgdGl0bGUgPSAnTkVUV09SSy5QRUVSLlNFTEVDVF9NT0RBTC5USVRMRSc7XG4gIEBJbnB1dCh7IHRyYW5zZm9ybTogYm9vbGVhbkF0dHJpYnV0ZSB9KSBjYW5DYW5jZWwgPSB0cnVlO1xuICBASW5wdXQoeyB0cmFuc2Zvcm06IGJvb2xlYW5BdHRyaWJ1dGUgfSkgYWxsb3dTZWxlY3REb3duUGVlciA9IHRydWU7XG4gIEBJbnB1dCh7IHRyYW5zZm9ybTogYm9vbGVhbkF0dHJpYnV0ZSB9KSBzaG93U2V0TWFudWFsbHlCdXR0b24gPSB0cnVlO1xuICBASW5wdXQoeyB0cmFuc2Zvcm06IGJvb2xlYW5BdHRyaWJ1dGUgfSkgc2hvd1NlYXJjaEJhcjogYm9vbGVhbjtcbiAgQElucHV0KCkgdGFiR3JvdXBBbmltYXRpb25EdXJhdGlvbjogJzIwMG1zJztcblxuICBASW5wdXQoKSBvblJlZnJlc2ggPSBuZXcgRXZlbnRFbWl0dGVyPEV2ZW50PigpO1xuXG4gIEBJbnB1dCgpIHNldCBkZWZhdWx0UGVlcnModmFsdWU6IFBlZXJbXSkge1xuICAgIHRoaXMuc2V0KCdkZWZhdWx0UGVlcnMnLCAoKSA9PiB2YWx1ZSk7XG4gIH1cblxuICBAVmlld0NoaWxkKCdzZWFyY2hiYXInLCB7IHN0YXRpYzogdHJ1ZSB9KSBzZWFyY2hiYXI6IElvblNlYXJjaGJhcjtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIG1vZGFsQ3RybDogTW9kYWxDb250cm9sbGVyLFxuICAgIHByaXZhdGUgcG9wb3ZlckNvbnRyb2xsZXI6IFBvcG92ZXJDb250cm9sbGVyLFxuICAgIHByaXZhdGUgdHJhbnNsYXRlOiBUcmFuc2xhdGVTZXJ2aWNlLFxuICAgIHByaXZhdGUgaHR0cDogSHR0cENsaWVudCxcbiAgICBwcml2YXRlIGNkOiBDaGFuZ2VEZXRlY3RvclJlZixcbiAgICBASW5qZWN0KEVOVklST05NRU5UKSBwcm90ZWN0ZWQgZW52aXJvbm1lbnQ6IEVudmlyb25tZW50LFxuICAgIEBPcHRpb25hbCgpIEBJbmplY3QoQVBQX0xPR0dJTkdfU0VSVklDRSkgcHJvdGVjdGVkIGxvZ2dpbmdTZXJ2aWNlPzogSUxvZ2dpbmdTZXJ2aWNlXG4gICkge1xuICAgIHN1cGVyKCk7XG4gICAgdGhpcy5zZXQoeyBzZWFyY2hUZXh0OiBudWxsLCBzZWxlY3RlZFRhYkluZGV4OiAwIH0pO1xuICAgIHRoaXMubW9iaWxlID0gaXNNb2JpbGUod2luZG93KTtcbiAgICB0aGlzLl9sb2dnZXIgPSBsb2dnaW5nU2VydmljZT8uZ2V0TG9nZ2VyKCduZXR3b3JrLW1vZGFsJyk7XG4gICAgdGhpcy5wZWVyTWluVmVyc2lvbiA9IGVudmlyb25tZW50LnBlZXJNaW5WZXJzaW9uO1xuICAgIHRoaXMucGVlckRlZmF1bHRQcmVmaXggPSBlbnZpcm9ubWVudC5wZWVyRGVmYXVsdFByZWZpeCB8fCAnaHR0cHM6Ly8nO1xuICAgIHRoaXMuZW5hYmxlU2VsZWN0UGVlckJ5RmVhdHVyZSA9IGVudmlyb25tZW50LmVuYWJsZVNlbGVjdFBlZXJCeUZlYXR1cmUgfHwgZmFsc2U7XG4gICAgdGhpcy5zaG93U2VhcmNoQmFyID0gdGhpcy5lbmFibGVTZWxlY3RQZWVyQnlGZWF0dXJlOyAvLyBTaG93IHNlYXJjaCBiYXIgYnkgZGVmYXVsdCwgaWYgdHdvIHRhYnNcblxuICAgIC8vIFJlZnJlc2hpbmcgcGVlcnNcbiAgICB0aGlzLmhvbGQodGhpcy5kZWZhdWx0UGVlcnMkLCAocmVzKSA9PiB0aGlzLnJlZnJlc2hQZWVycyhyZXMpKTtcblxuICAgIC8vIFNlYXJjaCBvbiBob3N0XG4gICAgdGhpcy5jb25uZWN0KFxuICAgICAgJ2ZpbHRlcmVkUGVlcnMnLFxuICAgICAgdGhpcy5zZWxlY3QoWydwZWVycycsICdzZWFyY2hUZXh0J10sIChyZXMpID0+IHJlcykucGlwZShcbiAgICAgICAgbWFwKCh7IHBlZXJzLCBzZWFyY2hUZXh0IH0pID0+IHtcbiAgICAgICAgICBpZiAoaXNOaWxPckJsYW5rKHNlYXJjaFRleHQpKSByZXR1cm4gcGVlcnM7IC8vIEFsbFxuXG4gICAgICAgICAgY29uc29sZS5kZWJ1ZygnW3NlbGVjdC1wZWVyLW1vZGFsXSBTZWFyY2hpbmcgb24gaG9zdHM6ICcgKyBzZWFyY2hUZXh0KTtcbiAgICAgICAgICBjb25zdCB7IGRhdGEgfSA9IHN1Z2dlc3RGcm9tQXJyYXkocGVlcnMsIHNlYXJjaFRleHQsIHtcbiAgICAgICAgICAgIGFueVNlYXJjaDogdHJ1ZSxcbiAgICAgICAgICAgIHNlYXJjaEF0dHJpYnV0ZXM6IFsnbGFiZWwnLCAnaG9zdEFuZFBvcnQnXSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm4gZGF0YTtcbiAgICAgICAgfSlcbiAgICAgIClcbiAgICApO1xuICAgIHRoaXMuY29ubmVjdCgnZmlsdGVyZWRQZWVyQ291bnQnLCB0aGlzLmZpbHRlcmVkUGVlcnMkLnBpcGUobWFwKChwZWVycykgPT4gcGVlcnM/Lmxlbmd0aCA/PyAwKSkpO1xuXG4gICAgLy8gU2VhcmNoIG9uIGZlYXR1cmVzXG4gICAgaWYgKHRoaXMuZW5hYmxlU2VsZWN0UGVlckJ5RmVhdHVyZSkge1xuICAgICAgdGhpcy5jb25uZWN0KFxuICAgICAgICAnZmlsdGVyZWRQZWVyc0J5RmVhdHVyZXMnLFxuICAgICAgICB0aGlzLnNlbGVjdChbJ3BlZXJzJywgJ3NlYXJjaFRleHQnXSwgKHJlcykgPT4gcmVzKS5waXBlKFxuICAgICAgICAgIG1hcCgoeyBwZWVycywgc2VhcmNoVGV4dCB9KSA9PiB7XG4gICAgICAgICAgICBpZiAoaXNOaWxPckJsYW5rKHNlYXJjaFRleHQpKSB7XG4gICAgICAgICAgICAgIHJldHVybiAocGVlcnMgfHwgW10pLmZpbHRlcigocCkgPT4gaXNOb3RFbXB0eUFycmF5KHA/LmZlYXR1cmVzKSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnNvbGUuZGVidWcoJ1tzZWxlY3QtcGVlci1tb2RhbF0gU2VhcmNoaW5nIG9uIGZlYXR1cmVzOiAnICsgc2VhcmNoVGV4dCk7XG4gICAgICAgICAgICByZXR1cm4gcGVlcnNcbiAgICAgICAgICAgICAgLm1hcCgocGVlcikgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IHsgZGF0YTogZmVhdHVyZXMgfSA9IHN1Z2dlc3RGcm9tQXJyYXkocGVlci5mZWF0dXJlcyB8fCBbXSwgc2VhcmNoVGV4dCwge1xuICAgICAgICAgICAgICAgICAgYW55U2VhcmNoOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgc2VhcmNoQXR0cmlidXRlczogWydsYWJlbCcsICduYW1lJywgJ2Rlc2NyaXB0aW9uJ10sXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgaWYgKGlzTm90RW1wdHlBcnJheShmZWF0dXJlcykpIHtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGZpbHRlcmVkUGVlciA9IHBlZXIuY2xvbmUoKTtcbiAgICAgICAgICAgICAgICAgIGZpbHRlcmVkUGVlci5mZWF0dXJlcyA9IGZlYXR1cmVzO1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIGZpbHRlcmVkUGVlcjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgIC5maWx0ZXIoaXNOb3ROaWwpO1xuICAgICAgICAgIH0pXG4gICAgICAgIClcbiAgICAgICk7XG4gICAgICB0aGlzLmNvbm5lY3QoJ2ZpbHRlcmVkRmVhdHVyZXNDb3VudCcsIHRoaXMuZmlsdGVyZWRQZWVyc0J5RmVhdHVyZXMkLnBpcGUobWFwKFBlZXIuY291bnRBbGxGZWF0dXJlcykpKTtcbiAgICB9XG4gIH1cblxuICBjYW5jZWwoKSB7XG4gICAgdGhpcy5tb2RhbEN0cmwuZGlzbWlzcygpO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5fc3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gIH1cblxuICBzZWxlY3RQZWVyKHBlZXI6IFBlZXIpIHtcbiAgICBpZiAodGhpcy5hbGxvd1NlbGVjdERvd25QZWVyIHx8IChwZWVyLnJlYWNoYWJsZSAmJiB0aGlzLmlzQ29tcGF0aWJsZShwZWVyKSkpIHtcbiAgICAgIGNvbnNvbGUuZGVidWcoYFtzZWxlY3QtcGVlci1tb2RhbF0gU2VsZWN0ZWQgcGVlcjoge3VybDogJyR7cGVlci51cmx9J31gKTtcbiAgICAgIHRoaXMuc2VsZWN0ZWRQZWVyID0gcGVlci51cmw7XG4gICAgICB0aGlzLm1vZGFsQ3RybC5kaXNtaXNzKHBlZXIpO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIHRvZ2dsZVNlYXJjaEJhcigpIHtcbiAgICB0aGlzLnNob3dTZWFyY2hCYXIgPSAhdGhpcy5zaG93U2VhcmNoQmFyO1xuICAgIGlmICh0aGlzLnNob3dTZWFyY2hCYXIgJiYgdGhpcy5zZWFyY2hiYXIpIHtcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICB0aGlzLnNlYXJjaGJhci5zZXRGb2N1cygpO1xuICAgICAgICB0aGlzLm1hcmtGb3JDaGVjaygpO1xuICAgICAgfSwgMzAwKTtcbiAgICB9XG4gIH1cblxuICB0b2dnbGVQZWVyRmVhdHVyZXMocGVlclVybDogc3RyaW5nKSB7XG4gICAgaWYgKCFwZWVyVXJsKSByZXR1cm47XG4gICAgdGhpcy5jb2xsYXBzZWRQZWVyc1twZWVyVXJsXSA9IGlzTm90TmlsKHRoaXMuY29sbGFwc2VkUGVlcnNbcGVlclVybF0pID8gIXRoaXMuY29sbGFwc2VkUGVlcnNbcGVlclVybF0gOiB0cnVlO1xuICAgIHRoaXMubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICAvKipcbiAgICogIENoZWNrIHRoZSBtaW4gcG9kIHZlcnNpb24sIGRlZmluZWQgYnkgdGhlIGFwcFxuICAgKlxuICAgKiBAcGFyYW0gcGVlclxuICAgKi9cbiAgaXNDb21wYXRpYmxlKHBlZXI6IFBlZXIpOiBib29sZWFuIHtcbiAgICByZXR1cm4gIXRoaXMucGVlck1pblZlcnNpb24gfHwgKHBlZXIgJiYgcGVlci5zb2Z0d2FyZVZlcnNpb24gJiYgVmVyc2lvblV0aWxzLmlzQ29tcGF0aWJsZSh0aGlzLnBlZXJNaW5WZXJzaW9uLCBwZWVyLnNvZnR3YXJlVmVyc2lvbikpO1xuICB9XG5cbiAgcmVmcmVzaChldmVudDogRXZlbnQpIHtcbiAgICB0aGlzLmxvYWRpbmcgPSB0cnVlO1xuICAgIHRoaXMub25SZWZyZXNoLmVtaXQoZXZlbnQpO1xuICB9XG5cbiAgYXN5bmMgY2xpY2tTZXRNYW51YWxseShldmVudD86IEV2ZW50KSB7XG4gICAgY29uc3QgcGVlclVybCA9IGF3YWl0IHRoaXMub3BlblBlZXJVcmxQb3BvdmVyKGV2ZW50KTtcbiAgICBpZiAocGVlclVybCkge1xuICAgICAgY29uc3QgcGVlciA9IFBlZXIucGFyc2VVcmwocGVlclVybCk7XG4gICAgICBhd2FpdCB0aGlzLnJlZnJlc2hQZWVyKHBlZXIpO1xuICAgICAgdGhpcy5zZWxlY3RQZWVyKHBlZXIpO1xuICAgIH1cbiAgfVxuXG4gIC8qIC0tIHByb3RlY3RlZCBtZXRob2RzIC0tICovXG4gIHByb3RlY3RlZCBjbGVhckxvZ28ocGVlcjogUGVlciB8IE5vZGVGZWF0dXJlKSB7XG4gICAgaWYgKHBlZXIgaW5zdGFuY2VvZiBQZWVyKSB7XG4gICAgICBwZWVyLmZhdmljb24gPSAnc2tpcCc7XG4gICAgfSBlbHNlIHtcbiAgICAgIHBlZXIubG9nbyA9ICdza2lwJztcbiAgICB9XG4gIH1cbiAgYXN5bmMgcmVmcmVzaFBlZXJzKHBlZXJzOiBQZWVyW10pIHtcbiAgICBwZWVycyA9IHBlZXJzIHx8IFtdO1xuXG4gICAgY29uc3QgZGF0YTogUGVlcltdID0gW107XG4gICAgY29uc3Qgam9icyA9IFByb21pc2UuYWxsKFxuICAgICAgcGVlcnMubWFwKGFzeW5jIChwZWVyKSA9PiB7XG4gICAgICAgIGF3YWl0IHRoaXMucmVmcmVzaFBlZXIocGVlcik7XG5cbiAgICAgICAgaWYgKHRoaXMuX3N1YnNjcmlwdGlvbi5jbG9zZWQpIHJldHVybjsgLy8gY29tcG9uZW50IGRlc3Ryb3llZFxuXG4gICAgICAgIGRhdGEucHVzaChwZWVyKTtcblxuICAgICAgICAvLyBTb3J0IChieSByZWFjaGFibGUsIHRoZW4gaG9zdClcbiAgICAgICAgZGF0YS5zb3J0KChhLCBiKSA9PiB7XG4gICAgICAgICAgaWYgKGEucmVhY2hhYmxlICYmICFiLnJlYWNoYWJsZSkgcmV0dXJuIC0xO1xuICAgICAgICAgIGlmICghYS5yZWFjaGFibGUgJiYgYi5yZWFjaGFibGUpIHJldHVybiAxO1xuICAgICAgICAgIGlmIChhLmhvc3RBbmRQb3J0IDwgYi5ob3N0QW5kUG9ydCkgcmV0dXJuIC0xO1xuICAgICAgICAgIGlmIChhLmhvc3RBbmRQb3J0ID4gYi5ob3N0QW5kUG9ydCkgcmV0dXJuIDE7XG4gICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMucGVlcnMgPSBkYXRhLnNsaWNlKCk7IC8vIENvcHkgdG8gZm9yY2UgdXBkYXRlXG5cbiAgICAgICAgcmV0dXJuIHBlZXI7XG4gICAgICB9KVxuICAgICk7XG5cbiAgICB0cnkge1xuICAgICAgYXdhaXQgam9icztcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGlmICghdGhpcy5fc3Vic2NyaXB0aW9uLmNsb3NlZCkgY29uc29sZS5lcnJvcihlcnIpO1xuICAgIH1cbiAgICB0aGlzLmxvYWRpbmcgPSBmYWxzZTtcbiAgICB0aGlzLmNkLm1hcmtGb3JDaGVjaygpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIHJlZnJlc2hQZWVyKHBlZXI6IFBlZXIpOiBQcm9taXNlPFBlZXI+IHtcbiAgICB0cnkge1xuICAgICAgLy8gREVCVUdcbiAgICAgIC8vYXdhaXQgc2xlZXAoTWF0aC5yYW5kb20oKSAqIDEwMCk7XG5cbiAgICAgIGNvbnN0IHN1bW1hcnk6IE5vZGVJbmZvID0gYXdhaXQgTmV0d29ya1V0aWxzLmdldE5vZGVJbmZvKHRoaXMuaHR0cCwgcGVlci51cmwpO1xuICAgICAgcGVlci5zdGF0dXMgPSAnVVAnO1xuICAgICAgcGVlci5zb2Z0d2FyZU5hbWUgPSBzdW1tYXJ5LnNvZnR3YXJlTmFtZTtcbiAgICAgIHBlZXIuc29mdHdhcmVWZXJzaW9uID0gc3VtbWFyeS5zb2Z0d2FyZVZlcnNpb247XG4gICAgICBwZWVyLmxhYmVsID0gc3VtbWFyeS5ub2RlTGFiZWw7XG4gICAgICBwZWVyLm5hbWUgPSBzdW1tYXJ5Lm5vZGVOYW1lO1xuICAgICAgcGVlci5mZWF0dXJlcyA9IHN1bW1hcnkuZmVhdHVyZXM/Lm1hcChOb2RlRmVhdHVyZS5mcm9tT2JqZWN0KSB8fCBbXTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIC8vIElmIG1vZGFsIHdhcyBub3QgY2xvc2VkIChlLmcuIHJlc3BvbnNlIGFycml2ZWQgdG9vIGxhdGUgPT4gaWdub3JlKVxuICAgICAgaWYgKCF0aGlzLl9zdWJzY3JpcHRpb24uY2xvc2VkKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoYFtzZWxlY3QtcGVlcl0gRXJyb3Igd2hpbGUgY2FsbGluZyAnJHtwZWVyLnVybH0vYXBpL25vZGUvaW5mbyc6ICR7ZXJyPy5tZXNzYWdlIHx8IGVycn1gLCBlcnIpO1xuICAgICAgICB0aGlzLl9sb2dnZXI/LmVycm9yKCdyZWZyZXNoUGVlcicsIGBFcnJvciB3aGlsZSBjYWxsaW5nICcke3BlZXIudXJsfS9hcGkvbm9kZS9pbmZvJzogJHtlcnI/Lm1lc3NhZ2UgfHwgSlNPTi5zdHJpbmdpZnkoZXJyKX1gKTtcbiAgICAgIH1cbiAgICAgIHBlZXIuc3RhdHVzID0gJ0RPV04nO1xuICAgIH1cbiAgICByZXR1cm4gcGVlcjtcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBvcGVuUGVlclVybFBvcG92ZXIoZXZlbnQ6IEV2ZW50LCBvcHRzPzogUGFydGlhbDxUZXh0UG9wb3Zlck9wdGlvbnM+KSB7XG4gICAgY29uc3QgbW9kYWwgPSBhd2FpdCB0aGlzLnBvcG92ZXJDb250cm9sbGVyLmNyZWF0ZSh7XG4gICAgICBjb21wb25lbnQ6IFRleHRQb3BvdmVyLFxuICAgICAgY29tcG9uZW50UHJvcHM6IDxUZXh0UG9wb3Zlck9wdGlvbnM+e1xuICAgICAgICBwbGFjZWhvbGRlcjogdGhpcy50cmFuc2xhdGUuaW5zdGFudCgnU0VUVElOR1MuUEVFUl9VUkwnKSxcbiAgICAgICAgbXVsdGlsaW5lOiBmYWxzZSxcbiAgICAgICAgYXV0b2ZvY3VzOiAhdGhpcy5tb2JpbGUsXG4gICAgICAgIGF1dG9jb21wbGV0ZTogZmFsc2UsXG4gICAgICAgIHZhbGlkYXRvcjogVmFsaWRhdG9ycy5wYXR0ZXJuKFBFRVJfVVJMX1JFR0VYUCksXG4gICAgICAgIG1heExlbmd0aDogbnVsbCxcbiAgICAgICAgdGV4dDogdGhpcy5zZWxlY3RlZFBlZXIgfHwgdGhpcy5wZWVyRGVmYXVsdFByZWZpeCxcbiAgICAgICAgLi4ub3B0cyxcbiAgICAgIH0sXG4gICAgICBiYWNrZHJvcERpc21pc3M6IGZhbHNlLFxuICAgICAga2V5Ym9hcmRDbG9zZTogZmFsc2UsXG4gICAgICBldmVudDogbnVsbCwgLy8gSU1QT1JUQU5UOiBudWxsIGV2ZW50IHdpbGwgY2VudGVyIHRoZSBwb3BvdmVyLCBhbmQgdGhpcyB3aWxsIGZpeCBrZXlib2FyZCBvdmVybGFwIG9uIG1vYmlsZVxuICAgICAgdHJhbnNsdWNlbnQ6IHRydWUsXG4gICAgICBjc3NDbGFzczogJ3BvcG92ZXItbGFyZ2UnLFxuICAgIH0pO1xuXG4gICAgYXdhaXQgbW9kYWwucHJlc2VudCgpO1xuICAgIGNvbnN0IHsgZGF0YSwgcm9sZSB9ID0gYXdhaXQgbW9kYWwub25EaWREaXNtaXNzKCk7XG5cbiAgICBpZiAoZGF0YSkge1xuICAgICAgY29uc29sZS5pbmZvKCdQb3BvdmVyIHJlc3VsdDogJywgZGF0YSk7XG4gICAgICByZXR1cm4gZGF0YTtcbiAgICB9XG4gIH1cblxuICBwcm90ZWN0ZWQgdXBkYXRlRmlsdGVyZWRQZWVyKGV2ZW50OiBhbnkpIHtcbiAgICBpZiAoZXZlbnQpIHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICB9XG4gICAgY29uc3QgdmFsdWUgPSBldmVudC50YXJnZXQudmFsdWU7XG5cbiAgICBjb25zdCB0ZXN0ID0gdGhpcy5maWx0ZXJlZFBlZXJzJC5waXBlKFxuICAgICAgbWFwKChwZWVycykgPT4gcGVlcnMuZmlsdGVyKEVudGl0eVV0aWxzLnNlYXJjaFRleHRGaWx0ZXIoWydmZWF0dXJlcy5sYWJlbCcsICdmZWF0dXJlcy5uYW1lJywgJ2ZlYXR1cmVzLmRlc2NyaXB0aW9uJ10sIHZhbHVlKSkpXG4gICAgKTtcblxuICAgIGNvbnNvbGUubG9nKHRlc3QpO1xuICAgIC8vIChldmVudC50YXJnZXQudmFsdWUpO1xuICAgIHRoaXMubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgbWFya0ZvckNoZWNrKCkge1xuICAgIHRoaXMuY2QubWFya0ZvckNoZWNrKCk7XG4gIH1cbn1cbiIsIjxpb24taGVhZGVyPlxuICA8aW9uLXRvb2xiYXIgY29sb3I9XCJsaWdodFwiIHN0eWxlPVwiei1pbmRleDogOTAwXCI+XG4gICAgPGlvbi1idXR0b25zIHNsb3Q9XCJzdGFydFwiPlxuICAgICAgQGlmIChjYW5DYW5jZWwpIHtcbiAgICAgICAgPGlvbi1idXR0b24gKGNsaWNrKT1cImNhbmNlbCgpXCIgdmlzaWJsZS1tb2JpbGUgdmlzaWJsZS1zbSB2aXNpYmxlLXhzPlxuICAgICAgICAgIDxpb24taWNvbiBuYW1lPVwiYXJyb3ctYmFja1wiIHNsb3Q9XCJpY29uLW9ubHlcIj48L2lvbi1pY29uPlxuICAgICAgICA8L2lvbi1idXR0b24+XG4gICAgICB9XG4gICAgPC9pb24tYnV0dG9ucz5cblxuICAgIDxpb24tdGl0bGU+XG4gICAgICB7eyB0aXRsZSB8IHRyYW5zbGF0ZSB9fVxuICAgIDwvaW9uLXRpdGxlPlxuXG4gICAgPGlvbi1idXR0b25zIHNsb3Q9XCJlbmRcIj5cbiAgICAgIDwhLS0gbG9hZGVyIC0tPlxuICAgICAgQGlmIChsb2FkaW5nKSB7XG4gICAgICAgIDxpb24tc3Bpbm5lcj48L2lvbi1zcGlubmVyPlxuICAgICAgfSBAZWxzZSB7XG4gICAgICAgIDwhLS0gcmVmcmVzaCBidXR0b24gLS0+XG4gICAgICAgIDxpb24tYnV0dG9uXG4gICAgICAgICAgKGNsaWNrKT1cInJlZnJlc2goJGV2ZW50KVwiXG4gICAgICAgICAgKm5nSWY9XCJvblJlZnJlc2gub2JzZXJ2ZWRcIlxuICAgICAgICAgIFttYXRUb29sdGlwXT1cIidDT01NT04uQlROX1JFRlJFU0gnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxtYXQtaWNvbiBzbG90PVwiaWNvbi1vbmx5XCI+cmVmcmVzaDwvbWF0LWljb24+XG4gICAgICAgIDwvaW9uLWJ1dHRvbj5cbiAgICAgIH1cbiAgICAgIDwhLS0gc2VhcmNoIGJ1dHRvbiAtLT5cbiAgICAgIEBpZiAoIXNob3dTZWFyY2hCYXIpIHtcbiAgICAgICAgPGlvbi1idXR0b24gKGNsaWNrKT1cInRvZ2dsZVNlYXJjaEJhcigpXCI+XG4gICAgICAgICAgPGlvbi1pY29uIHNsb3Q9XCJpY29uLW9ubHlcIiBuYW1lPVwic2VhcmNoXCI+PC9pb24taWNvbj5cbiAgICAgICAgPC9pb24tYnV0dG9uPlxuICAgICAgfVxuICAgIDwvaW9uLWJ1dHRvbnM+XG4gIDwvaW9uLXRvb2xiYXI+XG5cbiAgPCEtLSBzZWFyY2ggYmFyIC0tPlxuICA8aW9uLXRvb2xiYXIgKm5nSWY9XCJzaG93U2VhcmNoQmFyXCI+XG4gICAgPGlvbi1zZWFyY2hiYXJcbiAgICAgICNzZWFyY2hiYXJcbiAgICAgIGFuaW1hdGVkXG4gICAgICB0eXBlPVwic2VhcmNoXCJcbiAgICAgIFtjbGFzcy5jZGstdmlzdWFsbHktaGlkZGVuXT1cIiFzaG93U2VhcmNoQmFyXCJcbiAgICAgIHNob3ctY2xlYXItYnV0dG9uPVwiYWx3YXlzXCJcbiAgICAgIFtwbGFjZWhvbGRlcl09XCInQ09NTU9OLkJUTl9TRUFSQ0gnIHwgdHJhbnNsYXRlXCJcbiAgICAgIFtjYW5jZWxCdXR0b25UZXh0XT1cIidDT01NT04uQlROX0NBTkNFTCcgfCB0cmFuc2xhdGVcIlxuICAgICAgWyhuZ01vZGVsKV09XCJzZWFyY2hUZXh0XCJcbiAgICAgIChpb25DYW5jZWwpPVwidG9nZ2xlU2VhcmNoQmFyKClcIlxuICAgID48L2lvbi1zZWFyY2hiYXI+XG4gIDwvaW9uLXRvb2xiYXI+XG48L2lvbi1oZWFkZXI+XG5cbjxpb24tY29udGVudD5cbiAgPG1hdC10YWItZ3JvdXBcbiAgICAjdGFiR3JvdXBcbiAgICBbKHNlbGVjdGVkSW5kZXgpXT1cInNlbGVjdGVkVGFiSW5kZXhcIlxuICAgIGNsYXNzPVwibWF0LW1kYy10YWItZGlzYWJsZWQtaGlkZGVuXCJcbiAgICBbY2xhc3MubWF0LW1kYy10YWItZ3JvdXAtaGVhZGVyLWhpZGRlbl09XCIhZW5hYmxlU2VsZWN0UGVlckJ5RmVhdHVyZVwiXG4gICAgW2R5bmFtaWNIZWlnaHRdPVwiZmFsc2VcIlxuICAgIFttYXQtc3RyZXRjaC10YWJzXT1cIm1vYmlsZVwiXG4gICAgW2FuaW1hdGlvbkR1cmF0aW9uXT1cIm1vYmlsZSA/IHRhYkdyb3VwQW5pbWF0aW9uRHVyYXRpb24gOiAnMHMnXCJcbiAgPlxuICAgIDxtYXQtdGFiPlxuICAgICAgPG5nLXRlbXBsYXRlIG1hdC10YWItbGFiZWw+XG4gICAgICAgIDxpb24tbGFiZWxcbiAgICAgICAgICBbbWF0QmFkZ2VdPVwiZmlsdGVyZWRQZWVyQ291bnQkIHwgYXN5bmMgfCBiYWRnZU51bWJlclwiXG4gICAgICAgICAgW21hdEJhZGdlSGlkZGVuXT1cImZpbHRlcmVkUGVlckNvdW50JCB8IGFzeW5jIHwgaXNOaWxcIlxuICAgICAgICAgIFttYXRCYWRnZUNvbG9yXT1cIihmaWx0ZXJlZFBlZXJDb3VudCQgfCBhc3luYykgPyAncHJpbWFyeScgOiAnYWNjZW50J1wiXG4gICAgICAgICAgbWF0QmFkZ2VPdmVybGFwPVwiZmFsc2VcIlxuICAgICAgICAgIG1hdEJhZGdlQ29sb3I9XCJwcmltYXJ5XCJcbiAgICAgICAgICBtYXRCYWRnZVNpemU9XCJzbWFsbFwiXG4gICAgICAgICAgbWF0QmFkZ2VQb3NpdGlvbj1cImFib3ZlIGFmdGVyXCJcbiAgICAgICAgPlxuICAgICAgICAgIHt7ICdORVRXT1JLLlBFRVIuU0VMRUNUX01PREFMLlRBQl9ORVRXT1JLJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICA8L2lvbi1sYWJlbD5cbiAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICA8aW9uLWxpc3Q+XG4gICAgICAgIDxpb24tbGlzdC1oZWFkZXI+XG4gICAgICAgICAgPGlvbi1sYWJlbCBjbGFzcz1cImlvbi10ZXh0LXdyYXAgaW9uLXBhZGRpbmctZW5kXCI+XG4gICAgICAgICAgICA8cCBbaW5uZXJIVE1MXT1cIidORVRXT1JLLlBFRVIuU0VMRUNUX01PREFMLk5FVFdPUktfSEVMUCcgfCB0cmFuc2xhdGVcIj48L3A+XG4gICAgICAgICAgPC9pb24tbGFiZWw+XG4gICAgICAgIDwvaW9uLWxpc3QtaGVhZGVyPlxuXG4gICAgICAgIEBmb3IgKHBlZXIgb2YgZmlsdGVyZWRQZWVycyQgfCBhc3luYzsgdHJhY2sgJGluZGV4KSB7XG4gICAgICAgICAgPGlvbi1pdGVtXG4gICAgICAgICAgICAoY2xpY2spPVwic2VsZWN0UGVlcihwZWVyKVwiXG4gICAgICAgICAgICBAZmFkZUluQW5pbWF0aW9uXG4gICAgICAgICAgICBbY2xhc3Muc2VsZWN0ZWRdPVwic2VsZWN0ZWRQZWVyICYmIHNlbGVjdGVkUGVlciA9PT0gcGVlci51cmxcIlxuICAgICAgICAgICAgZGV0YWlsXG4gICAgICAgICAgICBtYXRSaXBwbGVcbiAgICAgICAgICAgIHRhcHBhYmxlXG4gICAgICAgICAgPlxuICAgICAgICAgICAgPCEtLSBQZWVyIGlzIFVQIC0tPlxuICAgICAgICAgICAgQGlmIChwZWVyLnJlYWNoYWJsZSkge1xuICAgICAgICAgICAgICA8IS0tIGljb24gLS0+XG4gICAgICAgICAgICAgIEBpZiAocGVlci5mYXZpY29uICE9ICdza2lwJykge1xuICAgICAgICAgICAgICAgIDxpb24tYXZhdGFyIHNsb3Q9XCJzdGFydFwiPlxuICAgICAgICAgICAgICAgICAgPGlvbi1pbWcgW3NyY109XCJwZWVyLmZhdmljb24gfHwgcGVlci51cmwgKyAnL2FwaS9mYXZpY29uJ1wiIChpb25FcnJvcik9XCJjbGVhckxvZ28ocGVlcilcIj48L2lvbi1pbWc+XG4gICAgICAgICAgICAgICAgICA8aW9uLWljb24gbmFtZT1cInNlcnZlclwiIGNsYXNzPVwiaWNvbi1zZWNvbmRhcnlcIiBzdHlsZT1cInRvcDogMTJweDsgbGVmdDogNDRweFwiIGNvbG9yPVwiZGFya1wiPjwvaW9uLWljb24+XG4gICAgICAgICAgICAgICAgPC9pb24tYXZhdGFyPlxuICAgICAgICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICAgICAgICA8aW9uLWljb24gc2xvdD1cInN0YXJ0XCIgbmFtZT1cInNlcnZlclwiIGNsYXNzPVwiaW9uLWljb24tYXZhdGFyXCIgY29sb3I9XCJkYXJrXCI+PC9pb24taWNvbj5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICA8aW9uLWdyaWQgY2xhc3M9XCJpb24tbm8tcGFkZGluZ1wiPlxuICAgICAgICAgICAgICAgIDxpb24tcm93PlxuICAgICAgICAgICAgICAgICAgPGlvbi1jb2w+XG4gICAgICAgICAgICAgICAgICAgIDxpb24tbGFiZWwgY2xhc3M9XCJpb24tdGV4dC13cmFwXCI+XG4gICAgICAgICAgICAgICAgICAgICAgPGlvbi10ZXh0PlxuICAgICAgICAgICAgICAgICAgICAgICAgQGxldCB1cmwgPSBwZWVyLmhvc3RBbmRQb3J0ICsgcGVlci5wYXRoO1xuICAgICAgICAgICAgICAgICAgICAgICAgPGgzIFtpbm5lckhUTUxdPVwidXJsIHwgaGlnaGxpZ2h0OiBzZWFyY2hUZXh0XCI+PC9oMz5cbiAgICAgICAgICAgICAgICAgICAgICA8L2lvbi10ZXh0PlxuICAgICAgICAgICAgICAgICAgICAgIDxpb24tdGV4dCBjb2xvcj1cInByaW1hcnlcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxoNCBbaW5uZXJIVE1MXT1cInBlZXIubGFiZWwgfCBoaWdobGlnaHQ6IHNlYXJjaFRleHRcIj48L2g0PlxuICAgICAgICAgICAgICAgICAgICAgIDwvaW9uLXRleHQ+XG4gICAgICAgICAgICAgICAgICAgIDwvaW9uLWxhYmVsPlxuICAgICAgICAgICAgICAgICAgPC9pb24tY29sPlxuICAgICAgICAgICAgICAgICAgPGlvbi1jb2wgc2l6ZT1cIjEyXCIgc2l6ZS1zbT1cIjRcIj5cbiAgICAgICAgICAgICAgICAgICAgPGlvbi1sYWJlbCBjbGFzcz1cImlvbi10ZXh0LXdyYXAgaW9uLXRleHQtc20tY2VudGVyXCIgY29sb3I9XCJtZWRpdW1cIj5cbiAgICAgICAgICAgICAgICAgICAgICA8aDQ+XG4gICAgICAgICAgICAgICAgICAgICAgICA8c21hbGw+e3sgcGVlci5zb2Z0d2FyZU5hbWUgfX0mbmJzcDs8L3NtYWxsPlxuICAgICAgICAgICAgICAgICAgICAgICAgPGJyIGNsYXNzPVwiaGlkZGVuLXh4cyBoaWRkZW4teHNcIiAvPlxuICAgICAgICAgICAgICAgICAgICAgICAgPCEtLSBDb21wYXRpYmxlIC0tPlxuICAgICAgICAgICAgICAgICAgICAgICAgQGlmICghcGVlck1pblZlcnNpb24gfHwgaXNDb21wYXRpYmxlKHBlZXIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIDxzbWFsbD52e3sgcGVlci5zb2Z0d2FyZVZlcnNpb24gfX08L3NtYWxsPlxuICAgICAgICAgICAgICAgICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIDwhLS0gSW5jb21wYXRpYmxlIC0tPlxuICAgICAgICAgICAgICAgICAgICAgICAgICA8aW9uLXRleHRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj1cImRhbmdlclwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgW21hdFRvb2x0aXBdPVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTkVUV09SSy5QRUVSLlNFTEVDVF9NT0RBTC5OT1RfQ09NUEFUSUJMRV9IRUxQJyB8IHRyYW5zbGF0ZTogeyB2ZXJzaW9uOiBwZWVyTWluVmVyc2lvbiB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxzbWFsbCBjbGFzcz1cImlvbi1jb2xvci1kYW5nZXJcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxtYXQtaWNvbj53YXJuaW5nPC9tYXQtaWNvbj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZ7eyBwZWVyLnNvZnR3YXJlVmVyc2lvbiB9fVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvc21hbGw+XG4gICAgICAgICAgICAgICAgICAgICAgICAgIDwvaW9uLXRleHQ+XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgPC9oND5cbiAgICAgICAgICAgICAgICAgICAgPC9pb24tbGFiZWw+XG4gICAgICAgICAgICAgICAgICA8L2lvbi1jb2w+XG4gICAgICAgICAgICAgICAgPC9pb24tcm93PlxuICAgICAgICAgICAgICA8L2lvbi1ncmlkPlxuICAgICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICAgIDwhLS0gUGVlciBpcyBET1dOIC0tPlxuICAgICAgICAgICAgICA8aW9uLWljb24gc2xvdD1cInN0YXJ0XCIgbmFtZT1cInNlcnZlclwiIGNsYXNzPVwiZGlzYWJsZWQgaW9uLWljb24tYXZhdGFyXCI+PC9pb24taWNvbj5cblxuICAgICAgICAgICAgICA8aW9uLWxhYmVsIGNsYXNzPVwiaW9uLXRleHQtd3JhcFwiPlxuICAgICAgICAgICAgICAgIDxpb24tdGV4dCBjb2xvcj1cIm1lZGl1bVwiPlxuICAgICAgICAgICAgICAgICAgPGgzPnt7IHBlZXIuaG9zdEFuZFBvcnQgfX17eyBwZWVyLnBhdGggfX08L2gzPlxuICAgICAgICAgICAgICAgIDwvaW9uLXRleHQ+XG4gICAgICAgICAgICAgICAgPGlvbi10ZXh0IGNvbG9yPVwiZGFuZ2VyXCI+XG4gICAgICAgICAgICAgICAgICA8aDQ+XG4gICAgICAgICAgICAgICAgICAgIDxzbWFsbD5cbiAgICAgICAgICAgICAgICAgICAgICA8aW9uLWljb24gc2l6ZT1cInNtYWxsXCIgbmFtZT1cImNsb3NlLWNpcmNsZVwiPjwvaW9uLWljb24+XG4gICAgICAgICAgICAgICAgICAgIDwvc21hbGw+XG4gICAgICAgICAgICAgICAgICAgIDxzcGFuIHRyYW5zbGF0ZT5ORVRXT1JLLlBFRVIuT0ZGTElORTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgIDwvaDQ+XG4gICAgICAgICAgICAgICAgPC9pb24tdGV4dD5cbiAgICAgICAgICAgICAgPC9pb24tbGFiZWw+XG4gICAgICAgICAgICB9XG4gICAgICAgICAgPC9pb24taXRlbT5cbiAgICAgICAgfVxuXG4gICAgICAgIDwhLS0gbm8gcmVzdWx0IC0tPlxuICAgICAgICBAaWYgKChmaWx0ZXJlZFBlZXJDb3VudCQgfCBhc3luYykgPT09IDApIHtcbiAgICAgICAgICA8aW9uLWl0ZW0+XG4gICAgICAgICAgICA8aW9uLXRleHQgY29sb3I9XCJkYW5nZXJcIiBjbGFzcz1cInRleHQtaXRhbGljXCIgdHJhbnNsYXRlPkNPTU1PTi5OT19SRVNVTFQ8L2lvbi10ZXh0PlxuICAgICAgICAgIDwvaW9uLWl0ZW0+XG4gICAgICAgIH1cbiAgICAgIDwvaW9uLWxpc3Q+XG4gICAgPC9tYXQtdGFiPlxuXG4gICAgPCEtLSBTZWxlY3QgYnkgZmVhdHVyZXMgLS0+XG4gICAgPG1hdC10YWIgW2Rpc2FibGVkXT1cIiFlbmFibGVTZWxlY3RQZWVyQnlGZWF0dXJlXCI+XG4gICAgICA8bmctdGVtcGxhdGUgbWF0LXRhYi1sYWJlbD5cbiAgICAgICAgPGlvbi1sYWJlbFxuICAgICAgICAgIFttYXRCYWRnZV09XCJmaWx0ZXJlZEZlYXR1cmVzQ291bnQkIHwgYXN5bmMgfCBiYWRnZU51bWJlclwiXG4gICAgICAgICAgW21hdEJhZGdlSGlkZGVuXT1cImZpbHRlcmVkRmVhdHVyZXNDb3VudCQgfCBhc3luYyB8IGlzTmlsXCJcbiAgICAgICAgICBbbWF0QmFkZ2VDb2xvcl09XCIoZmlsdGVyZWRGZWF0dXJlc0NvdW50JCB8IGFzeW5jKSA/ICdwcmltYXJ5JyA6ICdhY2NlbnQnXCJcbiAgICAgICAgICBtYXRCYWRnZU92ZXJsYXA9XCJmYWxzZVwiXG4gICAgICAgICAgbWF0QmFkZ2VTaXplPVwic21hbGxcIlxuICAgICAgICAgIG1hdEJhZGdlUG9zaXRpb249XCJhYm92ZSBhZnRlclwiXG4gICAgICAgID5cbiAgICAgICAgICB7eyAnTkVUV09SSy5QRUVSLlNFTEVDVF9NT0RBTC5UQUJfRkVBVFVSRVMnIHwgdHJhbnNsYXRlIH19XG4gICAgICAgIDwvaW9uLWxhYmVsPlxuICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgIDxpb24tbGlzdD5cbiAgICAgICAgPGlvbi1saXN0LWhlYWRlcj5cbiAgICAgICAgICA8aW9uLWxhYmVsIGNsYXNzPVwiaW9uLXRleHQtd3JhcCBpb24tcGFkZGluZy1lbmRcIj5cbiAgICAgICAgICAgIDxwIFtpbm5lckhUTUxdPVwiJ05FVFdPUksuUEVFUi5TRUxFQ1RfTU9EQUwuRkVBVFVSRVNfSEVMUCcgfCB0cmFuc2xhdGVcIj48L3A+XG4gICAgICAgICAgPC9pb24tbGFiZWw+XG4gICAgICAgIDwvaW9uLWxpc3QtaGVhZGVyPlxuXG4gICAgICAgIEBmb3IgKHBlZXIgb2YgZmlsdGVyZWRQZWVyc0J5RmVhdHVyZXMkIHwgYXN5bmM7IHRyYWNrICRpbmRleCkge1xuICAgICAgICAgIEBsZXQgcGVlclVybCA9IHBlZXIuaG9zdEFuZFBvcnQgKyBwZWVyLnBhdGg7XG4gICAgICAgICAgPCEtLSBQZWVyIGlzIFVQIC0tPlxuICAgICAgICAgIEBpZiAocGVlci5yZWFjaGFibGUgJiYgcGVlci5mZWF0dXJlcyB8IGlzTm90RW1wdHlBcnJheSkge1xuICAgICAgICAgICAgQGxldCBjb2xsYXBzZWQgPSBjb2xsYXBzZWRQZWVyc1twZWVyVXJsXTtcblxuICAgICAgICAgICAgPGlvbi1pdGVtLWRpdmlkZXIgKGNsaWNrKT1cInRvZ2dsZVBlZXJGZWF0dXJlcyhwZWVyVXJsKVwiIHRhcHBhYmxlIEBmYWRlSW5BbmltYXRpb24+XG4gICAgICAgICAgICAgIDxpb24tZ3JpZCBjbGFzcz1cImlvbi1uby1wYWRkaW5nXCI+XG4gICAgICAgICAgICAgICAgPGlvbi1yb3c+XG4gICAgICAgICAgICAgICAgICA8aW9uLWNvbD5cbiAgICAgICAgICAgICAgICAgICAgPGlvbi1sYWJlbD5cbiAgICAgICAgICAgICAgICAgICAgICA8aDQ+XG4gICAgICAgICAgICAgICAgICAgICAgICA8aW9uLWljb24gbmFtZT1cInNlcnZlclwiIGNvbG9yPVwibWVkaXVtXCI+PC9pb24taWNvbj5cbiAgICAgICAgICAgICAgICAgICAgICAgIHt7IHBlZXIuaG9zdEFuZFBvcnQgfX17eyBwZWVyLnBhdGggfX1cbiAgICAgICAgICAgICAgICAgICAgICA8L2g0PlxuICAgICAgICAgICAgICAgICAgICAgIEBpZiAocGVlck1pblZlcnNpb24gJiYgIWlzQ29tcGF0aWJsZShwZWVyKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgPGlvbi10ZXh0XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPVwiZGFuZ2VyXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgW21hdFRvb2x0aXBdPVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ05FVFdPUksuUEVFUi5TRUxFQ1RfTU9EQUwuTk9UX0NPTVBBVElCTEVfSEVMUCcgfCB0cmFuc2xhdGU6IHsgdmVyc2lvbjogcGVlck1pblZlcnNpb24gfVxuICAgICAgICAgICAgICAgICAgICAgICAgICBcIlxuICAgICAgICAgICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgICAgICAgICA8aDQgY2xhc3M9XCJpb24tY29sb3ItZGFuZ2VyXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNtYWxsPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPG1hdC1pY29uPndhcm5pbmc8L21hdC1pY29uPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdnt7IHBlZXIuc29mdHdhcmVWZXJzaW9uIH19XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zbWFsbD5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgPC9oND5cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvaW9uLXRleHQ+XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICA8L2lvbi1sYWJlbD5cbiAgICAgICAgICAgICAgICAgIDwvaW9uLWNvbD5cbiAgICAgICAgICAgICAgICAgIDxpb24tY29sIHNpemU9XCI0XCIgY2xhc3M9XCJpb24tdGV4dC1lbmRcIj5cbiAgICAgICAgICAgICAgICAgICAgPGlvbi1sYWJlbCBjbGFzcz1cInRleHQtaXRhbGljXCI+XG4gICAgICAgICAgICAgICAgICAgICAgPGg0Pih7eyAnQ09NTU9OLlJFU1VMVF9DT1VOVCcgfCB0cmFuc2xhdGU6IHsgY291bnQ6IHBlZXIuZmVhdHVyZXMubGVuZ3RoIH0gfX0pPC9oND5cbiAgICAgICAgICAgICAgICAgICAgPC9pb24tbGFiZWw+XG4gICAgICAgICAgICAgICAgICA8L2lvbi1jb2w+XG4gICAgICAgICAgICAgICAgPC9pb24tcm93PlxuICAgICAgICAgICAgICA8L2lvbi1ncmlkPlxuXG4gICAgICAgICAgICAgIDxtYXQtaWNvbiBzbG90PVwiZW5kXCI+XG4gICAgICAgICAgICAgICAgQGlmIChjb2xsYXBzZWQpIHtcbiAgICAgICAgICAgICAgICAgIHt7IG1vYmlsZSA/ICdhcnJvd19kcm9wX2Rvd24nIDogJ2tleWJvYXJkX2Fycm93X2Rvd24nIH19XG4gICAgICAgICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICAgICAgICB7eyBtb2JpbGUgPyAnYXJyb3dfZHJvcF91cCcgOiAna2V5Ym9hcmRfYXJyb3dfdXAnIH19XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICA8L21hdC1pY29uPlxuICAgICAgICAgICAgPC9pb24taXRlbS1kaXZpZGVyPlxuXG4gICAgICAgICAgICBAaWYgKCFjb2xsYXBzZWQpIHtcbiAgICAgICAgICAgICAgQGZvciAoZmVhdHVyZSBvZiBwZWVyLmZlYXR1cmVzOyB0cmFjayBmZWF0dXJlLmxhYmVsKSB7XG4gICAgICAgICAgICAgICAgPGlvbi1pdGVtIChjbGljayk9XCJzZWxlY3RQZWVyKHBlZXIpXCIgdGFwcGFibGUgbWF0UmlwcGxlIGRldGFpbCBAZmFkZUluQW5pbWF0aW9uPlxuICAgICAgICAgICAgICAgICAgPCEtLSBpY29uIC0tPlxuICAgICAgICAgICAgICAgICAgQGlmIChmZWF0dXJlLmxvZ28gJiYgZmVhdHVyZS5sb2dvICE9ICdza2lwJykge1xuICAgICAgICAgICAgICAgICAgICA8aW9uLWF2YXRhciBzbG90PVwic3RhcnRcIj5cbiAgICAgICAgICAgICAgICAgICAgICA8aW9uLWltZyBbc3JjXT1cImZlYXR1cmUubG9nb1wiIChpb25FcnJvcik9XCJjbGVhckxvZ28oZmVhdHVyZSlcIj48L2lvbi1pbWc+XG4gICAgICAgICAgICAgICAgICAgIDwvaW9uLWF2YXRhcj5cbiAgICAgICAgICAgICAgICAgIH0gQGVsc2UgaWYgKHBlZXIuZmF2aWNvbiAhPSAnc2tpcCcpIHtcbiAgICAgICAgICAgICAgICAgICAgPGlvbi1hdmF0YXIgc2xvdD1cInN0YXJ0XCI+XG4gICAgICAgICAgICAgICAgICAgICAgPGlvbi1pbWcgW3NyY109XCJwZWVyLmZhdmljb24gfHwgcGVlci51cmwgKyAnL2FwaS9mYXZpY29uJ1wiIChpb25FcnJvcik9XCJjbGVhckxvZ28ocGVlcilcIj48L2lvbi1pbWc+XG4gICAgICAgICAgICAgICAgICAgICAgPGlvbi1pY29uXG4gICAgICAgICAgICAgICAgICAgICAgICBuYW1lPVwiY29udHJhY3RcIlxuICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJpY29uLXNlY29uZGFyeVwiXG4gICAgICAgICAgICAgICAgICAgICAgICBzdHlsZT1cInRvcDogMTJweDsgbGVmdDogNDRweFwiXG4gICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj1cImRhcmtcIlxuICAgICAgICAgICAgICAgICAgICAgID48L2lvbi1pY29uPlxuICAgICAgICAgICAgICAgICAgICA8L2lvbi1hdmF0YXI+XG4gICAgICAgICAgICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgPGlvbi1pY29uIHNsb3Q9XCJzdGFydFwiIG5hbWU9XCJjb250cmFjdFwiIGNsYXNzPVwiaW9uLWljb24tYXZhdGFyXCIgY29sb3I9XCJkYXJrXCI+PC9pb24taWNvbj5cbiAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgPGlvbi1sYWJlbCBjbGFzcz1cImlvbi10ZXh0LXdyYXBcIj5cbiAgICAgICAgICAgICAgICAgICAgPGlvbi10ZXh0IGNvbG9yPVwicHJpbWFyeVwiPlxuICAgICAgICAgICAgICAgICAgICAgIDxoMyBbaW5uZXJIVE1MXT1cImZlYXR1cmUgfCByZWZlcmVudGlhbFRvU3RyaW5nIHwgaGlnaGxpZ2h0OiBzZWFyY2hUZXh0XCI+PC9oMz5cbiAgICAgICAgICAgICAgICAgICAgPC9pb24tdGV4dD5cbiAgICAgICAgICAgICAgICAgICAgPGlvbi10ZXh0PlxuICAgICAgICAgICAgICAgICAgICAgIDxwIFtpbm5lckhUTUxdPVwiZmVhdHVyZS5kZXNjcmlwdGlvbiB8IGhpZ2hsaWdodDogc2VhcmNoVGV4dFwiPjwvcD5cbiAgICAgICAgICAgICAgICAgICAgPC9pb24tdGV4dD5cbiAgICAgICAgICAgICAgICAgIDwvaW9uLWxhYmVsPlxuICAgICAgICAgICAgICAgIDwvaW9uLWl0ZW0+XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICA8IS0tIG5vIHJlc3VsdCAtLT5cbiAgICAgICAgQGlmICgoZmlsdGVyZWRGZWF0dXJlc0NvdW50JCB8IGFzeW5jKSA9PT0gMCkge1xuICAgICAgICAgIDxpb24taXRlbT5cbiAgICAgICAgICAgIDxpb24tdGV4dCBjb2xvcj1cImRhbmdlclwiIGNsYXNzPVwidGV4dC1pdGFsaWNcIiB0cmFuc2xhdGU+Q09NTU9OLk5PX1JFU1VMVDwvaW9uLXRleHQ+XG4gICAgICAgICAgPC9pb24taXRlbT5cbiAgICAgICAgfVxuICAgICAgPC9pb24tbGlzdD5cbiAgICA8L21hdC10YWI+XG4gIDwvbWF0LXRhYi1ncm91cD5cbjwvaW9uLWNvbnRlbnQ+XG5cbkBpZiAoKGNhbkNhbmNlbCAmJiAhbW9iaWxlKSB8fCBzaG93U2V0TWFudWFsbHlCdXR0b24pIHtcbiAgPGlvbi1mb290ZXI+XG4gICAgPGlvbi10b29sYmFyPlxuICAgICAgPGlvbi1yb3cgY2xhc3M9XCJpb24tbm8tcGFkZGluZyBpb24tdGV4dC1ub3dyYXBcIj5cbiAgICAgICAgPGlvbi1jb2w+PC9pb24tY29sPlxuXG4gICAgICAgIDwhLS0gYnV0dG9ucyAtLT5cbiAgICAgICAgQGlmIChzaG93U2V0TWFudWFsbHlCdXR0b24pIHtcbiAgICAgICAgICA8aW9uLWNvbCBzaXplPVwiYXV0b1wiPlxuICAgICAgICAgICAgPGlvbi1idXR0b24gZmlsbD1cImNsZWFyXCIgKGNsaWNrKT1cImNsaWNrU2V0TWFudWFsbHkoJGV2ZW50KVwiPlxuICAgICAgICAgICAgICA8aW9uLWxhYmVsIHRyYW5zbGF0ZT5ORVRXT1JLLlBFRVIuU0VMRUNUX01PREFMLkJUTl9TRVRfTUFOVUFMTFk8L2lvbi1sYWJlbD5cbiAgICAgICAgICAgIDwvaW9uLWJ1dHRvbj5cbiAgICAgICAgICA8L2lvbi1jb2w+XG4gICAgICAgIH1cblxuICAgICAgICBAaWYgKGNhbkNhbmNlbCkge1xuICAgICAgICAgIDxpb24tY29sIHNpemU9XCJhdXRvXCIgaGlkZGVuLXhzIGhpZGRlbi1zbSBoaWRkZW4tbW9iaWxlPlxuICAgICAgICAgICAgPGlvbi1idXR0b24gZmlsbD1cImNsZWFyXCIgY29sb3I9XCJkYXJrXCIgKGNsaWNrKT1cImNhbmNlbCgpXCI+XG4gICAgICAgICAgICAgIDxpb24tbGFiZWwgdHJhbnNsYXRlPkNPTU1PTi5CVE5fQ0FOQ0VMPC9pb24tbGFiZWw+XG4gICAgICAgICAgICA8L2lvbi1idXR0b24+XG4gICAgICAgICAgPC9pb24tY29sPlxuICAgICAgICB9XG4gICAgICA8L2lvbi1yb3c+XG4gICAgPC9pb24tdG9vbGJhcj5cbiAgPC9pb24tZm9vdGVyPlxufVxuIl19