@qbs-origin/origin-form 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/esm2022/lib/action-step-handler.mjs +163 -0
- package/esm2022/lib/auth-client.service.mjs +69 -0
- package/esm2022/lib/enums/label.keys.mjs +721 -0
- package/esm2022/lib/form-css.helper.mjs +367 -0
- package/esm2022/lib/formly/baseFormlyControlComponent.mjs +52 -0
- package/esm2022/lib/formly/baseFormlyStepComponent.mjs +59 -0
- package/esm2022/lib/formly/custom-section-separator.component.mjs +32 -0
- package/esm2022/lib/formly/form-section-separator.component.mjs +36 -0
- package/esm2022/lib/formly/formly-action.mjs +56 -0
- package/esm2022/lib/formly/formly-checkbox/formly-checkbox.component.mjs +52 -0
- package/esm2022/lib/formly/formly-dictionary-dropdown-tree/formly-dictionary-dropdown-tree.component.mjs +261 -0
- package/esm2022/lib/formly/formly-download-documents/formly-download-documents.component.mjs +126 -0
- package/esm2022/lib/formly/formly-enrol-card/formly-enrol-card.component.mjs +120 -0
- package/esm2022/lib/formly/formly-field-stepper/formly-field-stepper.component.mjs +762 -0
- package/esm2022/lib/formly/formly-generate-documents/formly-generate-documents.component.mjs +57 -0
- package/esm2022/lib/formly/formly-identification.component.mjs +84 -0
- package/esm2022/lib/formly/formly-open-banking/formly-open-banking.component.mjs +590 -0
- package/esm2022/lib/formly/formly-paragraph/formly-paragraph.component.mjs +35 -0
- package/esm2022/lib/formly/formly-radio/formly-radio-component.mjs +49 -0
- package/esm2022/lib/formly/formly-row-fille.mjs +12 -0
- package/esm2022/lib/formly/formly-scan-id/formly-scan-id.component.mjs +284 -0
- package/esm2022/lib/formly/formly-sign/formly-sign.component.mjs +173 -0
- package/esm2022/lib/formly/formly-upload-documents/formly-upload-documents.component.mjs +198 -0
- package/esm2022/lib/formly/formly-validate-contact-info/formly-validate-contact-info.component.mjs +124 -0
- package/esm2022/lib/formly/formly-view-documents/formly-view-documents.component.mjs +245 -0
- package/esm2022/lib/formly/formly-view-offers/formly-view-offers.component.mjs +160 -0
- package/esm2022/lib/model-population.helper.mjs +265 -0
- package/esm2022/lib/models/application-type.model.mjs +12 -0
- package/esm2022/lib/models/application.model.mjs +30 -0
- package/esm2022/lib/models/auth/users.model.mjs +2 -0
- package/esm2022/lib/models/dictionary.model.mjs +20 -0
- package/esm2022/lib/models/flux.model.mjs +105 -0
- package/esm2022/lib/models/forms.model.mjs +572 -0
- package/esm2022/lib/models/label-info.model.mjs +2 -0
- package/esm2022/lib/models/label.model.mjs +2 -0
- package/esm2022/lib/models/language.model.mjs +3 -0
- package/esm2022/lib/models/list.model.mjs +2 -0
- package/esm2022/lib/models/partner.model.mjs +3 -0
- package/esm2022/lib/models/treeview.model.mjs +15 -0
- package/esm2022/lib/origin-form-auth.service.mjs +40 -0
- package/esm2022/lib/origin-form-config.model.mjs +2 -0
- package/esm2022/lib/origin-form-token.interceptor.mjs +35 -0
- package/esm2022/lib/origin-form.component.mjs +2391 -0
- package/esm2022/lib/origin-form.module.mjs +479 -0
- package/esm2022/lib/origin-form.service.mjs +14 -0
- package/esm2022/lib/others/check-list.database.mjs +55 -0
- package/esm2022/lib/others/config-service.mjs +42 -0
- package/esm2022/lib/others/dictionary-label-info.mjs +3 -0
- package/esm2022/lib/others/environment-type.mjs +21 -0
- package/esm2022/lib/others/external-link.directive.mjs +49 -0
- package/esm2022/lib/others/flux-helper.mjs +1397 -0
- package/esm2022/lib/others/picker.component.mjs +119 -0
- package/esm2022/lib/others/translation.pipe.mjs +21 -0
- package/esm2022/lib/others/translations-helper.mjs +258 -0
- package/esm2022/lib/others/utils.mjs +272 -0
- package/esm2022/lib/services/applicationData.service.mjs +145 -0
- package/esm2022/lib/services/auth-http.service.mjs +80 -0
- package/esm2022/lib/services/dialog.service.mjs +56 -0
- package/esm2022/lib/services/dictionary.service.mjs +198 -0
- package/esm2022/lib/services/forms.service.mjs +47 -0
- package/esm2022/lib/services/labels.service.mjs +29 -0
- package/esm2022/lib/services/language.service.mjs +24 -0
- package/esm2022/lib/services/open-banking.service.mjs +194 -0
- package/esm2022/lib/services/origin-form-signalr-handler.service.mjs +107 -0
- package/esm2022/lib/services/origin-form-signalr.service.mjs +105 -0
- package/esm2022/lib/services/otp.service.mjs +28 -0
- package/esm2022/lib/services/proxy.service.mjs +79 -0
- package/esm2022/lib/services/scroll-to-error.service.mjs +369 -0
- package/esm2022/lib/services/translation.service.mjs +27 -0
- package/esm2022/lib/shared-components/confirmation.component.mjs +34 -0
- package/esm2022/lib/shared-components/dictionaries-tree.component.mjs +301 -0
- package/esm2022/lib/shared-components/grid.component.mjs +241 -0
- package/esm2022/lib/shared-components/treeview/treeview.component.mjs +224 -0
- package/esm2022/lib/theme-css.mjs +2254 -0
- package/esm2022/lib/theme-injector.service.mjs +26 -0
- package/esm2022/public-api.mjs +4 -0
- package/esm2022/qbs-origin-origin-form.mjs +5 -0
- package/fesm2022/qbs-origin-origin-form.mjs +15215 -0
- package/fesm2022/qbs-origin-origin-form.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/action-step-handler.d.ts +49 -0
- package/lib/auth-client.service.d.ts +17 -0
- package/lib/enums/label.keys.d.ts +720 -0
- package/lib/form-css.helper.d.ts +28 -0
- package/lib/formly/baseFormlyControlComponent.d.ts +25 -0
- package/lib/formly/baseFormlyStepComponent.d.ts +29 -0
- package/lib/formly/custom-section-separator.component.d.ts +6 -0
- package/lib/formly/form-section-separator.component.d.ts +10 -0
- package/lib/formly/formly-action.d.ts +13 -0
- package/lib/formly/formly-checkbox/formly-checkbox.component.d.ts +15 -0
- package/lib/formly/formly-dictionary-dropdown-tree/formly-dictionary-dropdown-tree.component.d.ts +45 -0
- package/lib/formly/formly-download-documents/formly-download-documents.component.d.ts +22 -0
- package/lib/formly/formly-enrol-card/formly-enrol-card.component.d.ts +114 -0
- package/lib/formly/formly-field-stepper/formly-field-stepper.component.d.ts +79 -0
- package/lib/formly/formly-generate-documents/formly-generate-documents.component.d.ts +17 -0
- package/lib/formly/formly-identification.component.d.ts +19 -0
- package/lib/formly/formly-open-banking/formly-open-banking.component.d.ts +119 -0
- package/lib/formly/formly-paragraph/formly-paragraph.component.d.ts +10 -0
- package/lib/formly/formly-radio/formly-radio-component.d.ts +15 -0
- package/lib/formly/formly-row-fille.d.ts +6 -0
- package/lib/formly/formly-scan-id/formly-scan-id.component.d.ts +41 -0
- package/lib/formly/formly-sign/formly-sign.component.d.ts +36 -0
- package/lib/formly/formly-upload-documents/formly-upload-documents.component.d.ts +25 -0
- package/lib/formly/formly-validate-contact-info/formly-validate-contact-info.component.d.ts +79 -0
- package/lib/formly/formly-view-documents/formly-view-documents.component.d.ts +33 -0
- package/lib/formly/formly-view-offers/formly-view-offers.component.d.ts +23 -0
- package/lib/model-population.helper.d.ts +8 -0
- package/lib/models/application-type.model.d.ts +27 -0
- package/lib/models/application.model.d.ts +107 -0
- package/lib/models/auth/users.model.d.ts +20 -0
- package/lib/models/dictionary.model.d.ts +77 -0
- package/lib/models/flux.model.d.ts +101 -0
- package/lib/models/forms.model.d.ts +504 -0
- package/lib/models/label-info.model.d.ts +10 -0
- package/lib/models/label.model.d.ts +4 -0
- package/lib/models/language.model.d.ts +5 -0
- package/lib/models/list.model.d.ts +8 -0
- package/lib/models/partner.model.d.ts +12 -0
- package/lib/models/treeview.model.d.ts +17 -0
- package/lib/origin-form-auth.service.d.ts +15 -0
- package/lib/origin-form-config.model.d.ts +12 -0
- package/lib/origin-form-token.interceptor.d.ts +12 -0
- package/lib/origin-form.component.d.ts +231 -0
- package/lib/origin-form.module.d.ts +84 -0
- package/lib/origin-form.service.d.ts +6 -0
- package/lib/others/check-list.database.d.ts +16 -0
- package/lib/others/config-service.d.ts +22 -0
- package/lib/others/dictionary-label-info.d.ts +6 -0
- package/lib/others/environment-type.d.ts +8 -0
- package/lib/others/external-link.directive.d.ts +12 -0
- package/lib/others/flux-helper.d.ts +115 -0
- package/lib/others/picker.component.d.ts +36 -0
- package/lib/others/translation.pipe.d.ts +10 -0
- package/lib/others/translations-helper.d.ts +31 -0
- package/lib/others/utils.d.ts +37 -0
- package/lib/services/applicationData.service.d.ts +35 -0
- package/lib/services/auth-http.service.d.ts +21 -0
- package/lib/services/dialog.service.d.ts +20 -0
- package/lib/services/dictionary.service.d.ts +89 -0
- package/lib/services/forms.service.d.ts +17 -0
- package/lib/services/labels.service.d.ts +13 -0
- package/lib/services/language.service.d.ts +14 -0
- package/lib/services/open-banking.service.d.ts +137 -0
- package/lib/services/origin-form-signalr-handler.service.d.ts +29 -0
- package/lib/services/origin-form-signalr.service.d.ts +24 -0
- package/lib/services/otp.service.d.ts +22 -0
- package/lib/services/proxy.service.d.ts +29 -0
- package/lib/services/scroll-to-error.service.d.ts +54 -0
- package/lib/services/translation.service.d.ts +10 -0
- package/lib/shared-components/confirmation.component.d.ts +77 -0
- package/lib/shared-components/dictionaries-tree.component.d.ts +51 -0
- package/lib/shared-components/grid.component.d.ts +138 -0
- package/lib/shared-components/treeview/treeview.component.d.ts +121 -0
- package/lib/theme-css.d.ts +2 -0
- package/lib/theme-injector.service.d.ts +8 -0
- package/package.json +42 -0
- package/public-api.d.ts +3 -0
- package/schematics-compiled/collection.json +10 -0
- package/schematics-compiled/ng-add/index.d.ts +2 -0
- package/schematics-compiled/ng-add/index.js +67 -0
- package/schematics-compiled/ng-add/index.js.map +1 -0
- package/schematics-compiled/ng-add/schema.json +8 -0
- package/src/lib/assets/fonts/Figtree-Bold.ttf +0 -0
- package/src/lib/assets/fonts/Figtree-Light.ttf +0 -0
- package/src/lib/assets/fonts/Figtree-Regular.ttf +0 -0
- package/src/lib/assets/fonts/Sora-ExtraBold.ttf +0 -0
- package/src/lib/assets/fonts/Sora-Light.ttf +0 -0
- package/src/lib/assets/fonts/Sora-Regular.ttf +0 -0
- package/src/lib/assets/fonts/ttrounds-bold-webfont.woff +0 -0
- package/src/lib/assets/fonts/ttrounds-bold-webfont.woff2 +0 -0
- package/src/lib/assets/fonts/ttrounds-regular-webfont.woff +0 -0
- package/src/lib/assets/fonts/ttrounds-regular-webfont.woff2 +0 -0
- package/src/lib/assets/fonts/ttrounds-thin-webfont.woff +0 -0
- package/src/lib/assets/fonts/ttrounds-thin-webfont.woff2 +0 -0
- package/src/lib/assets/images/flag/icon-flag-de.svg +10 -0
- package/src/lib/assets/images/flag/icon-flag-en.svg +1 -0
- package/src/lib/assets/images/flag/icon-flag-es.svg +11 -0
- package/src/lib/assets/images/flag/icon-flag-fr.svg +1 -0
- package/src/lib/assets/images/flag/icon-flag-ro.svg +11 -0
- package/src/lib/assets/images/flag/origin-form/new-id-card.png +0 -0
- package/src/lib/assets/images/flag/origin-form/old-id-card.png +0 -0
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
import { Component, } from '@angular/core';
|
|
2
|
+
import { FormControl } from '@angular/forms';
|
|
3
|
+
import { BehaviorSubject, interval } from 'rxjs';
|
|
4
|
+
import { switchMap, takeWhile, finalize } from 'rxjs/operators';
|
|
5
|
+
import { BaseFormlyStepComponent } from '../baseFormlyStepComponent';
|
|
6
|
+
import * as i0 from "@angular/core";
|
|
7
|
+
import * as i1 from "../../services/open-banking.service";
|
|
8
|
+
import * as i2 from "../../services/dialog.service";
|
|
9
|
+
import * as i3 from "@angular/platform-browser";
|
|
10
|
+
import * as i4 from "@angular/common";
|
|
11
|
+
import * as i5 from "@angular/material/button";
|
|
12
|
+
import * as i6 from "@angular/material/icon";
|
|
13
|
+
import * as i7 from "@angular/material/progress-spinner";
|
|
14
|
+
var OpenBankingState;
|
|
15
|
+
(function (OpenBankingState) {
|
|
16
|
+
OpenBankingState["Initial"] = "initial";
|
|
17
|
+
OpenBankingState["BankSelection"] = "bankSelection";
|
|
18
|
+
OpenBankingState["Consent"] = "consent";
|
|
19
|
+
OpenBankingState["Processing"] = "processing";
|
|
20
|
+
OpenBankingState["Error"] = "error";
|
|
21
|
+
OpenBankingState["Complete"] = "complete";
|
|
22
|
+
})(OpenBankingState || (OpenBankingState = {}));
|
|
23
|
+
export class FormlyOpenBankingComponent extends BaseFormlyStepComponent {
|
|
24
|
+
constructor(openBankingService, dialog, sanitizer, cdr) {
|
|
25
|
+
super(cdr);
|
|
26
|
+
this.openBankingService = openBankingService;
|
|
27
|
+
this.dialog = dialog;
|
|
28
|
+
this.sanitizer = sanitizer;
|
|
29
|
+
this.config = {};
|
|
30
|
+
this.currentState = new BehaviorSubject(OpenBankingState.Initial);
|
|
31
|
+
this.banks = [];
|
|
32
|
+
this.selectedBank = '';
|
|
33
|
+
this.authorizationUrl = null;
|
|
34
|
+
this.consentId = '';
|
|
35
|
+
this._errorMessage = '';
|
|
36
|
+
this._isConsentError = false;
|
|
37
|
+
this._consentErrorStatus = '';
|
|
38
|
+
this.isLoading = false;
|
|
39
|
+
this.isLoadingSubject = new BehaviorSubject(false);
|
|
40
|
+
this.accounts = [];
|
|
41
|
+
this.transactions = [];
|
|
42
|
+
this.selectedAccounts = [];
|
|
43
|
+
this.transactionPages = new Map();
|
|
44
|
+
}
|
|
45
|
+
async ngOnInit() {
|
|
46
|
+
await super.ngOnInit();
|
|
47
|
+
if (this.stepData?.config) {
|
|
48
|
+
this.config = this.stepData.config;
|
|
49
|
+
}
|
|
50
|
+
// If translations are in stepData.translations, merge them into config
|
|
51
|
+
if (this.stepData?.translations) {
|
|
52
|
+
this.mergeTranslationsIntoConfig();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
mergeTranslationsIntoConfig() {
|
|
56
|
+
// Map translation names to config properties
|
|
57
|
+
const translationMap = {
|
|
58
|
+
'initialMessageTranslations': 'initialMessageTranslations',
|
|
59
|
+
'waitingMessageTranslations': 'waitingMessageTranslations',
|
|
60
|
+
'consentErrorMessageTranslations': 'consentErrorMessageTranslations',
|
|
61
|
+
'completionMessageTranslations': 'completionMessageTranslations',
|
|
62
|
+
'retryButtonLabelTranslations': 'retryButtonLabelTranslations',
|
|
63
|
+
'nextButtonTranslations': 'nextButtonTranslations',
|
|
64
|
+
'continueButtonTranslations': 'continueButtonTranslations',
|
|
65
|
+
'selectBankTranslations': 'selectBankTranslations',
|
|
66
|
+
'consentTitleTranslations': 'consentTitleTranslations',
|
|
67
|
+
'consentDescriptionTranslations': 'consentDescriptionTranslations',
|
|
68
|
+
'waitingForAuthorizationTranslations': 'waitingForAuthorizationTranslations',
|
|
69
|
+
'popupWindowMessageTranslations': 'popupWindowMessageTranslations',
|
|
70
|
+
'popupBlockerMessageTranslations': 'popupBlockerMessageTranslations',
|
|
71
|
+
'accountsRetrievedTranslations': 'accountsRetrievedTranslations',
|
|
72
|
+
'transactionsRetrievedTranslations': 'transactionsRetrievedTranslations',
|
|
73
|
+
'accountsFoundTranslations': 'accountsFoundTranslations',
|
|
74
|
+
'transactionsSummaryTranslations': 'transactionsSummaryTranslations'
|
|
75
|
+
};
|
|
76
|
+
this.stepData.translations?.forEach((translation) => {
|
|
77
|
+
const configKey = translationMap[translation.name];
|
|
78
|
+
if (configKey && translation.values && translation.values.length > 0) {
|
|
79
|
+
// Use the translation values from stepData if config doesn't have all languages
|
|
80
|
+
this.config[configKey] = translation.values;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
ngAfterViewInit() {
|
|
85
|
+
// Only set initial state if we haven't already set a state
|
|
86
|
+
if (!this.currentState.value) {
|
|
87
|
+
this.currentState.next(OpenBankingState.Initial);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
onPageSelected() {
|
|
91
|
+
// Only reset to initial if we haven't started the flow yet
|
|
92
|
+
// This prevents reset when language changes
|
|
93
|
+
if (!this.currentState.value) {
|
|
94
|
+
this.currentState.next(OpenBankingState.Initial);
|
|
95
|
+
}
|
|
96
|
+
// Update language if it changed
|
|
97
|
+
this.cdr.detectChanges();
|
|
98
|
+
}
|
|
99
|
+
determineNextStep() {
|
|
100
|
+
// Get account information from form if configured
|
|
101
|
+
const accountNumber = this.getFieldValue(this.config.accountNumberCollected);
|
|
102
|
+
// If we should extract bank from IBAN and have an IBAN
|
|
103
|
+
if (this.config.extractBankFromIBAN && accountNumber && this.isIBAN(accountNumber)) {
|
|
104
|
+
// Load banks first, then match IBAN to bank
|
|
105
|
+
this.loadBanksAndMatchIBAN(accountNumber);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
// If we should show all banks
|
|
109
|
+
if (this.config.showAllBanks) {
|
|
110
|
+
this.loadBanks();
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
// Go directly to consent without bank selection
|
|
114
|
+
this.initiateConsent();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
getFieldValue(fieldId) {
|
|
118
|
+
if (!fieldId)
|
|
119
|
+
return '';
|
|
120
|
+
return this.form.get(fieldId)?.value || '';
|
|
121
|
+
}
|
|
122
|
+
isIBAN(value) {
|
|
123
|
+
// Basic IBAN validation for Romanian IBANs
|
|
124
|
+
return /^RO\d{2}[A-Z]{4}\d{16}$/.test(value.replace(/\s/g, ''));
|
|
125
|
+
}
|
|
126
|
+
extractBankFromIBAN(iban) {
|
|
127
|
+
// Extract bank code from Romanian IBAN (positions 5-8)
|
|
128
|
+
const cleanIban = iban.replace(/\s/g, '');
|
|
129
|
+
if (cleanIban.startsWith('RO') && cleanIban.length >= 8) {
|
|
130
|
+
return cleanIban.substring(4, 8);
|
|
131
|
+
}
|
|
132
|
+
return '';
|
|
133
|
+
}
|
|
134
|
+
loadBanksAndMatchIBAN(iban) {
|
|
135
|
+
this.setLoadingState(true);
|
|
136
|
+
const countryCode = 'RO'; // Default to Romania
|
|
137
|
+
this.openBankingService.getBanks(countryCode).subscribe({
|
|
138
|
+
next: (banks) => {
|
|
139
|
+
this.banks = banks.filter(b => b.isActive);
|
|
140
|
+
// Extract bank code from IBAN
|
|
141
|
+
const ibanBankCode = this.extractBankFromIBAN(iban);
|
|
142
|
+
if (ibanBankCode) {
|
|
143
|
+
// Try to match against bank codes
|
|
144
|
+
const matchedBank = this.banks.find(bank => bank.bankCode.toUpperCase() === ibanBankCode.toUpperCase());
|
|
145
|
+
if (matchedBank) {
|
|
146
|
+
// Bank found - select it and go directly to consent
|
|
147
|
+
this.selectedBank = matchedBank.bankCode;
|
|
148
|
+
this.selectedBankObject = matchedBank;
|
|
149
|
+
this.setLoadingState(false);
|
|
150
|
+
this.initiateConsent();
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// If no match found, show bank selection
|
|
155
|
+
this.currentState.next(OpenBankingState.BankSelection);
|
|
156
|
+
this.setLoadingState(false);
|
|
157
|
+
},
|
|
158
|
+
error: (error) => {
|
|
159
|
+
this.handleError(error);
|
|
160
|
+
this.setLoadingState(false);
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
loadBanks() {
|
|
165
|
+
this.setLoadingState(true);
|
|
166
|
+
const countryCode = 'RO'; // Default to Romania
|
|
167
|
+
this.openBankingService.getBanks(countryCode).subscribe({
|
|
168
|
+
next: (banks) => {
|
|
169
|
+
this.banks = banks.filter(b => b.isActive);
|
|
170
|
+
this.currentState.next(OpenBankingState.BankSelection);
|
|
171
|
+
this.setLoadingState(false);
|
|
172
|
+
},
|
|
173
|
+
error: (error) => {
|
|
174
|
+
this.handleError(error);
|
|
175
|
+
this.setLoadingState(false);
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
selectBank(bank) {
|
|
180
|
+
this.selectedBank = bank.bankCode;
|
|
181
|
+
this.selectedBankObject = bank;
|
|
182
|
+
}
|
|
183
|
+
proceedToNextStep() {
|
|
184
|
+
if (this.currentState.value === OpenBankingState.Initial) {
|
|
185
|
+
// User clicked Next on initial screen - determine what to show next
|
|
186
|
+
this.determineNextStep();
|
|
187
|
+
}
|
|
188
|
+
else if (this.currentState.value === OpenBankingState.BankSelection) {
|
|
189
|
+
if (this.selectedBank) {
|
|
190
|
+
this.initiateConsent();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
initiateConsent() {
|
|
195
|
+
this.setLoadingState(true);
|
|
196
|
+
// Get user information
|
|
197
|
+
const email = this.getFieldValue(this.config.emailCollected) || 'user@example.com';
|
|
198
|
+
// Generate a unique PSU ID for this session
|
|
199
|
+
const psuId = this.appDataId || 'user-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
|
|
200
|
+
const consentRequest = {
|
|
201
|
+
bankCode: this.selectedBank || 'DEFAULT',
|
|
202
|
+
psuEmail: email,
|
|
203
|
+
psuIntermediaryId: psuId,
|
|
204
|
+
periodOfValidity: 90,
|
|
205
|
+
tcAccepted: this.config.tcAcceptedByDefault !== false
|
|
206
|
+
};
|
|
207
|
+
this.openBankingService.initializeConsent(consentRequest).subscribe({
|
|
208
|
+
next: (response) => {
|
|
209
|
+
this.consentId = response.consentId;
|
|
210
|
+
// Check if bank requires redirect
|
|
211
|
+
if (this.selectedBankObject?.requiresRedirect !== false) {
|
|
212
|
+
// Try iframe first, but most banks will block it
|
|
213
|
+
if (this.shouldUseIframe()) {
|
|
214
|
+
this.authorizationUrl = this.sanitizer.bypassSecurityTrustResourceUrl(response.authorizationUrl);
|
|
215
|
+
this.currentState.next(OpenBankingState.Consent);
|
|
216
|
+
// Set a flag to detect if iframe fails
|
|
217
|
+
this.checkIframeLoad(response.authorizationUrl);
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
// Open in new window/tab
|
|
221
|
+
this.openConsentInNewWindow(response.authorizationUrl);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
this.setLoadingState(false);
|
|
225
|
+
// Start polling for consent status
|
|
226
|
+
this.startConsentPolling();
|
|
227
|
+
},
|
|
228
|
+
error: (error) => {
|
|
229
|
+
this.handleError(error);
|
|
230
|
+
this.setLoadingState(false);
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
shouldUseIframe() {
|
|
235
|
+
// Most banks don't allow iframes due to X-Frame-Options
|
|
236
|
+
// So default to false (use popup window instead)
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
openConsentInNewWindow(authorizationUrl) {
|
|
240
|
+
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
241
|
+
let consentWindow;
|
|
242
|
+
if (isMobile) {
|
|
243
|
+
// On mobile, open in same tab (full redirect) or new tab
|
|
244
|
+
// Using _blank will open a new tab and allow user to return
|
|
245
|
+
consentWindow = window.open(authorizationUrl, '_blank');
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
// On desktop, open in a popup window
|
|
249
|
+
const width = 800;
|
|
250
|
+
const height = 600;
|
|
251
|
+
const left = (window.screen.width - width) / 2;
|
|
252
|
+
const top = (window.screen.height - height) / 2;
|
|
253
|
+
consentWindow = window.open(authorizationUrl, 'bankConsent', `width=${width},height=${height},left=${left},top=${top},toolbar=no,menubar=no,scrollbars=yes,resizable=yes`);
|
|
254
|
+
}
|
|
255
|
+
if (consentWindow) {
|
|
256
|
+
// Show a message that consent is in progress
|
|
257
|
+
this.currentState.next(OpenBankingState.Consent);
|
|
258
|
+
// Check if window is closed periodically (works better on desktop)
|
|
259
|
+
if (!isMobile) {
|
|
260
|
+
const checkWindowClosed = setInterval(() => {
|
|
261
|
+
if (consentWindow && consentWindow.closed) {
|
|
262
|
+
clearInterval(checkWindowClosed);
|
|
263
|
+
// Window was closed, the polling will detect the consent status
|
|
264
|
+
}
|
|
265
|
+
}, 1000);
|
|
266
|
+
}
|
|
267
|
+
// On mobile, we rely entirely on polling since window.closed doesn't work reliably
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
// Popup was blocked
|
|
271
|
+
this._isConsentError = false;
|
|
272
|
+
this._errorMessage = 'Please allow popups for this site to complete bank authorization. Then click Retry to try again.';
|
|
273
|
+
this.currentState.next(OpenBankingState.Error);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
checkIframeLoad(authorizationUrl) {
|
|
277
|
+
// If iframe fails to load (X-Frame-Options), fall back to popup
|
|
278
|
+
setTimeout(() => {
|
|
279
|
+
// Check if we're still in consent state (iframe might have failed)
|
|
280
|
+
if (this.currentState.value === OpenBankingState.Consent && this.authorizationUrl) {
|
|
281
|
+
// Clear iframe and open in new window
|
|
282
|
+
console.warn('Iframe might be blocked, opening in new window');
|
|
283
|
+
this.authorizationUrl = null;
|
|
284
|
+
this.openConsentInNewWindow(authorizationUrl);
|
|
285
|
+
}
|
|
286
|
+
}, 2000);
|
|
287
|
+
}
|
|
288
|
+
startConsentPolling() {
|
|
289
|
+
// Poll every 5 seconds for consent status (user needs time to complete bank authorization)
|
|
290
|
+
this.pollSubscription = interval(10000)
|
|
291
|
+
.pipe(switchMap(() => this.openBankingService.getConsentStatus(this.selectedBank || 'DEFAULT', this.consentId)), takeWhile((status) => status.status === 'received', true), finalize(() => this.pollSubscription?.unsubscribe()))
|
|
292
|
+
.subscribe({
|
|
293
|
+
next: (status) => {
|
|
294
|
+
if (status.status === 'valid') {
|
|
295
|
+
this.onConsentApproved();
|
|
296
|
+
}
|
|
297
|
+
else if (status.status === 'rejected' ||
|
|
298
|
+
status.status === 'expired' ||
|
|
299
|
+
status.status === 'terminated' ||
|
|
300
|
+
status.status === 'revokedByPsu') {
|
|
301
|
+
this.onConsentRejected(status);
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
error: (error) => {
|
|
305
|
+
this.handleError(error);
|
|
306
|
+
},
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
onConsentApproved() {
|
|
310
|
+
this.currentState.next(OpenBankingState.Processing);
|
|
311
|
+
this.fetchAccountData();
|
|
312
|
+
}
|
|
313
|
+
onConsentRejected(status) {
|
|
314
|
+
this._isConsentError = true;
|
|
315
|
+
this._consentErrorStatus = status.status;
|
|
316
|
+
this._errorMessage = ''; // Clear to use translated message
|
|
317
|
+
this.currentState.next(OpenBankingState.Error);
|
|
318
|
+
}
|
|
319
|
+
fetchAccountData() {
|
|
320
|
+
this.setLoadingState(true);
|
|
321
|
+
// First, fetch accounts
|
|
322
|
+
this.openBankingService.getAccounts(this.consentId, this.selectedBank || 'DEFAULT').subscribe({
|
|
323
|
+
next: (accounts) => {
|
|
324
|
+
this.accounts = accounts;
|
|
325
|
+
// Select all accounts for transaction fetching
|
|
326
|
+
this.selectedAccounts = accounts.map(a => a.accountId);
|
|
327
|
+
// Fetch transactions for each account
|
|
328
|
+
this.fetchTransactionsForAccounts();
|
|
329
|
+
},
|
|
330
|
+
error: (error) => {
|
|
331
|
+
this.handleError(error);
|
|
332
|
+
this.setLoadingState(false);
|
|
333
|
+
},
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
fetchTransactionsForAccounts() {
|
|
337
|
+
if (this.selectedAccounts.length === 0) {
|
|
338
|
+
this.completeProcess();
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
const transactionRequests = this.selectedAccounts.map(accountId => {
|
|
342
|
+
// Calculate date range based on bank-specific limits
|
|
343
|
+
const bankCode = this.selectedBank || 'DEFAULT';
|
|
344
|
+
const maxDays = this.openBankingService.getMaxTransactionPeriod(bankCode);
|
|
345
|
+
const toDate = new Date();
|
|
346
|
+
const fromDate = new Date();
|
|
347
|
+
// If unlimited (-1) or very long period, use 365 days as practical limit
|
|
348
|
+
// Otherwise use the bank's specific limit
|
|
349
|
+
const daysToFetch = maxDays === -1 ? 365 : Math.min(maxDays, 365);
|
|
350
|
+
fromDate.setDate(fromDate.getDate() - daysToFetch);
|
|
351
|
+
return this.openBankingService.getTransactions({
|
|
352
|
+
consentId: this.consentId,
|
|
353
|
+
bankCode: bankCode,
|
|
354
|
+
accountId: accountId,
|
|
355
|
+
fromDate: fromDate.toISOString(),
|
|
356
|
+
toDate: toDate.toISOString(),
|
|
357
|
+
page: 1,
|
|
358
|
+
pageSize: 50
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
// Execute all transaction requests
|
|
362
|
+
Promise.all(transactionRequests.map(req => req.toPromise()))
|
|
363
|
+
.then(results => {
|
|
364
|
+
// Store transaction pages
|
|
365
|
+
results.forEach((page, index) => {
|
|
366
|
+
if (page) {
|
|
367
|
+
this.transactionPages.set(this.selectedAccounts[index], page);
|
|
368
|
+
// Flatten all transactions into single array
|
|
369
|
+
this.transactions.push(...page.items);
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
this.completeProcess();
|
|
373
|
+
})
|
|
374
|
+
.catch(error => {
|
|
375
|
+
console.error('Error fetching transactions:', error);
|
|
376
|
+
// Even if transactions fail, we can continue with accounts
|
|
377
|
+
this.completeProcess();
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
completeProcess() {
|
|
381
|
+
// Store data in form model
|
|
382
|
+
this.storeAccountData();
|
|
383
|
+
this.currentState.next(OpenBankingState.Complete);
|
|
384
|
+
this.setLoadingState(false);
|
|
385
|
+
// Auto-proceed to next step after a short delay
|
|
386
|
+
setTimeout(() => {
|
|
387
|
+
this.onEvent('success');
|
|
388
|
+
}, 2000);
|
|
389
|
+
}
|
|
390
|
+
storeAccountData() {
|
|
391
|
+
// Store the fetched data in the form model for use in later steps
|
|
392
|
+
const group = this.form;
|
|
393
|
+
// Add accounts and transactions to form
|
|
394
|
+
group.addControl('openBankingAccounts', new FormControl(this.accounts));
|
|
395
|
+
group.addControl('openBankingTransactions', new FormControl(this.transactions));
|
|
396
|
+
group.addControl('openBankingConsentId', new FormControl(this.consentId));
|
|
397
|
+
group.addControl('openBankingBankCode', new FormControl(this.selectedBank));
|
|
398
|
+
// Store account summary
|
|
399
|
+
const accountSummary = {
|
|
400
|
+
totalAccounts: this.accounts.length,
|
|
401
|
+
totalBalance: this.accounts.reduce((sum, acc) => sum + acc.balance, 0),
|
|
402
|
+
currencies: [...new Set(this.accounts.map(a => a.currency))],
|
|
403
|
+
transactionCount: this.transactions.length,
|
|
404
|
+
oldestTransaction: this.transactions.length > 0
|
|
405
|
+
? this.transactions.reduce((oldest, t) => new Date(t.bookingDate || t.transactionDate || '') < new Date(oldest.bookingDate || oldest.transactionDate || '') ? t : oldest).bookingDate
|
|
406
|
+
: null,
|
|
407
|
+
newestTransaction: this.transactions.length > 0
|
|
408
|
+
? this.transactions.reduce((newest, t) => new Date(t.bookingDate || t.transactionDate || '') > new Date(newest.bookingDate || newest.transactionDate || '') ? t : newest).bookingDate
|
|
409
|
+
: null
|
|
410
|
+
};
|
|
411
|
+
group.addControl('openBankingAccountSummary', new FormControl(accountSummary));
|
|
412
|
+
// Populate the step's controls for SaveAppData
|
|
413
|
+
this.populateStepControls();
|
|
414
|
+
}
|
|
415
|
+
populateStepControls() {
|
|
416
|
+
// Find and populate the controls in the step sections
|
|
417
|
+
if (!this.stepData?.sections)
|
|
418
|
+
return;
|
|
419
|
+
// Get email from config mapping or use empty string
|
|
420
|
+
const email = this.getFieldValue(this.config.emailCollected) || '';
|
|
421
|
+
// Get the first account as the primary account
|
|
422
|
+
const primaryAccount = this.accounts.length > 0 ? this.accounts[0] : null;
|
|
423
|
+
// Calculate total balance
|
|
424
|
+
const totalBalance = this.accounts.reduce((sum, acc) => sum + acc.balance, 0);
|
|
425
|
+
// Calculate transaction period in months
|
|
426
|
+
const months = this.getTransactionPeriodMonths();
|
|
427
|
+
// Map of control identifiers to values
|
|
428
|
+
const controlValues = {
|
|
429
|
+
'OpenBankingConsentStatus': true, // Consent was successfully validated
|
|
430
|
+
'OpenBankingEmail': email,
|
|
431
|
+
'OpenBankingAccountNumber': primaryAccount?.iban || '',
|
|
432
|
+
'OpenBankingAccountHolder': primaryAccount?.accountHolderName || '',
|
|
433
|
+
'OpenBankingBankCode': this.selectedBank || '',
|
|
434
|
+
'OpenBankingConsentId': this.consentId,
|
|
435
|
+
'OpenBankingAccountsCount': this.accounts.length,
|
|
436
|
+
'OpenBankingAccountsData': JSON.stringify(this.accounts),
|
|
437
|
+
'OpenBankingTotalBalance': totalBalance,
|
|
438
|
+
'OpenBankingTransactionsCount': this.transactions.length,
|
|
439
|
+
'OpenBankingTransactionsData': JSON.stringify(this.transactions),
|
|
440
|
+
'OpenBankingTransactionsPeriod': months
|
|
441
|
+
};
|
|
442
|
+
// Add all control values to the form
|
|
443
|
+
const group = this.form;
|
|
444
|
+
Object.keys(controlValues).forEach(controlId => {
|
|
445
|
+
if (!group.contains(controlId)) {
|
|
446
|
+
group.addControl(controlId, new FormControl(controlValues[controlId]));
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
group.get(controlId)?.setValue(controlValues[controlId]);
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
// The values are now stored in the form model and will be saved with SaveAppData
|
|
453
|
+
// When the form is submitted, these values will be associated with the step's controls
|
|
454
|
+
}
|
|
455
|
+
retry() {
|
|
456
|
+
this._errorMessage = '';
|
|
457
|
+
this._isConsentError = false;
|
|
458
|
+
this._consentErrorStatus = '';
|
|
459
|
+
this.accounts = [];
|
|
460
|
+
this.transactions = [];
|
|
461
|
+
this.selectedAccounts = [];
|
|
462
|
+
this.transactionPages.clear();
|
|
463
|
+
this.consentId = '';
|
|
464
|
+
this.selectedBank = '';
|
|
465
|
+
this.selectedBankObject = undefined;
|
|
466
|
+
this.banks = [];
|
|
467
|
+
this.authorizationUrl = null;
|
|
468
|
+
// Reset to initial state - user needs to click Next again
|
|
469
|
+
this.currentState.next(OpenBankingState.Initial);
|
|
470
|
+
}
|
|
471
|
+
handleError(error) {
|
|
472
|
+
console.error('OpenBanking error:', error);
|
|
473
|
+
this._isConsentError = false;
|
|
474
|
+
this._consentErrorStatus = '';
|
|
475
|
+
this._errorMessage = error.error?.message || error.message || 'An error occurred. Please try again.';
|
|
476
|
+
this.currentState.next(OpenBankingState.Error);
|
|
477
|
+
}
|
|
478
|
+
getTranslatedMessage(translations, defaultMessage = '') {
|
|
479
|
+
if (!translations || translations.length === 0)
|
|
480
|
+
return defaultMessage;
|
|
481
|
+
const langIso = this.props?.['langIso'] || this.langIso || 'en';
|
|
482
|
+
const translation = translations.find(t => t.languageIso === langIso);
|
|
483
|
+
return translation?.value || translations[0]?.value || defaultMessage;
|
|
484
|
+
}
|
|
485
|
+
get initialMessage() {
|
|
486
|
+
return this.getTranslatedMessage(this.config.initialMessageTranslations, 'To continue, we need to verify your bank account information. Click Next to proceed.');
|
|
487
|
+
}
|
|
488
|
+
get waitingMessage() {
|
|
489
|
+
return this.getTranslatedMessage(this.config.waitingMessageTranslations, 'Please wait while we retrieve your account information...');
|
|
490
|
+
}
|
|
491
|
+
get completionMessage() {
|
|
492
|
+
return this.getTranslatedMessage(this.config.completionMessageTranslations, 'Account information successfully retrieved.');
|
|
493
|
+
}
|
|
494
|
+
get retryButtonLabel() {
|
|
495
|
+
return this.getTranslatedMessage(this.config.retryButtonLabelTranslations, 'Retry');
|
|
496
|
+
}
|
|
497
|
+
get errorMessage() {
|
|
498
|
+
// If it's a consent error, use the translated consent error message
|
|
499
|
+
if (this._isConsentError) {
|
|
500
|
+
const message = this.getTranslatedMessage(this.config.consentErrorMessageTranslations, 'You must provide consent to continue. Please try again.');
|
|
501
|
+
return this._consentErrorStatus ? `${message} (Status: ${this._consentErrorStatus})` : message;
|
|
502
|
+
}
|
|
503
|
+
// Otherwise return the stored error message (from API or default)
|
|
504
|
+
return this._errorMessage || 'An error occurred. Please try again.';
|
|
505
|
+
}
|
|
506
|
+
// Button translations
|
|
507
|
+
get nextButtonLabel() {
|
|
508
|
+
return this.getTranslatedMessage(this.config.nextButtonTranslations, 'Next');
|
|
509
|
+
}
|
|
510
|
+
get continueButtonLabel() {
|
|
511
|
+
return this.getTranslatedMessage(this.config.continueButtonTranslations, 'Continue');
|
|
512
|
+
}
|
|
513
|
+
// UI label translations
|
|
514
|
+
get selectBankTitle() {
|
|
515
|
+
return this.getTranslatedMessage(this.config.selectBankTranslations, 'Select your bank');
|
|
516
|
+
}
|
|
517
|
+
get consentTitle() {
|
|
518
|
+
return this.getTranslatedMessage(this.config.consentTitleTranslations, 'Bank Authorization');
|
|
519
|
+
}
|
|
520
|
+
get consentDescription() {
|
|
521
|
+
return this.getTranslatedMessage(this.config.consentDescriptionTranslations, 'Please complete the authorization process with your bank');
|
|
522
|
+
}
|
|
523
|
+
get waitingForAuthorizationText() {
|
|
524
|
+
return this.getTranslatedMessage(this.config.waitingForAuthorizationTranslations, 'Waiting for authorization...');
|
|
525
|
+
}
|
|
526
|
+
get popupWindowMessage() {
|
|
527
|
+
return this.getTranslatedMessage(this.config.popupWindowMessageTranslations, 'A new window has opened for bank authorization. Please complete the process there.');
|
|
528
|
+
}
|
|
529
|
+
get popupBlockerMessage() {
|
|
530
|
+
return this.getTranslatedMessage(this.config.popupBlockerMessageTranslations, 'If the window didn\'t open, please check your popup blocker settings.');
|
|
531
|
+
}
|
|
532
|
+
get accountsRetrievedLabel() {
|
|
533
|
+
return this.getTranslatedMessage(this.config.accountsRetrievedTranslations, 'Accounts retrieved');
|
|
534
|
+
}
|
|
535
|
+
get transactionsRetrievedLabel() {
|
|
536
|
+
return this.getTranslatedMessage(this.config.transactionsRetrievedTranslations, 'Transactions retrieved');
|
|
537
|
+
}
|
|
538
|
+
get accountsSummaryText() {
|
|
539
|
+
const count = this.accounts.length;
|
|
540
|
+
const template = this.getTranslatedMessage(this.config.accountsFoundTranslations, '{0} account(s) found');
|
|
541
|
+
return template.replace('{0}', count.toString());
|
|
542
|
+
}
|
|
543
|
+
get transactionsSummaryText() {
|
|
544
|
+
const count = this.transactions.length;
|
|
545
|
+
const months = this.getTransactionPeriodMonths();
|
|
546
|
+
const template = this.getTranslatedMessage(this.config.transactionsSummaryTranslations, '{0} transaction(s) retrieved for the last {1} month(s)');
|
|
547
|
+
return template.replace('{0}', count.toString()).replace('{1}', months.toString());
|
|
548
|
+
}
|
|
549
|
+
getTransactionPeriodMonths() {
|
|
550
|
+
if (!this.selectedBank)
|
|
551
|
+
return 3;
|
|
552
|
+
const maxDays = this.openBankingService.getMaxTransactionPeriod(this.selectedBank);
|
|
553
|
+
const daysToFetch = maxDays === -1 ? 365 : Math.min(maxDays, 365);
|
|
554
|
+
return Math.round(daysToFetch / 30);
|
|
555
|
+
}
|
|
556
|
+
get isInitialState() {
|
|
557
|
+
return this.currentState.value === OpenBankingState.Initial;
|
|
558
|
+
}
|
|
559
|
+
get isBankSelectionState() {
|
|
560
|
+
return this.currentState.value === OpenBankingState.BankSelection;
|
|
561
|
+
}
|
|
562
|
+
get isConsentState() {
|
|
563
|
+
return this.currentState.value === OpenBankingState.Consent;
|
|
564
|
+
}
|
|
565
|
+
get isProcessingState() {
|
|
566
|
+
return this.currentState.value === OpenBankingState.Processing;
|
|
567
|
+
}
|
|
568
|
+
get isErrorState() {
|
|
569
|
+
return this.currentState.value === OpenBankingState.Error;
|
|
570
|
+
}
|
|
571
|
+
get isCompleteState() {
|
|
572
|
+
return this.currentState.value === OpenBankingState.Complete;
|
|
573
|
+
}
|
|
574
|
+
setLoadingState(loading) {
|
|
575
|
+
this.isLoading = loading;
|
|
576
|
+
this.isLoadingSubject.next(loading);
|
|
577
|
+
this.cdr.detectChanges();
|
|
578
|
+
}
|
|
579
|
+
ngOnDestroy() {
|
|
580
|
+
this.pollSubscription?.unsubscribe();
|
|
581
|
+
this.isLoadingSubject.complete();
|
|
582
|
+
}
|
|
583
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FormlyOpenBankingComponent, deps: [{ token: i1.OpenBankingService }, { token: i2.DialogService }, { token: i3.DomSanitizer }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
584
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: FormlyOpenBankingComponent, selector: "app-formly-open-banking", usesInheritance: true, ngImport: i0, template: "<div class=\"open-banking-container\">\n <!-- Initial State -->\n <div *ngIf=\"isInitialState\" class=\"state-initial\">\n <div class=\"message-container\">\n <p class=\"message\">{{ initialMessage }}</p>\n <button mat-raised-button color=\"primary\" (click)=\"proceedToNextStep()\" [disabled]=\"isLoadingSubject | async\">\n {{ nextButtonLabel }}\n </button>\n </div>\n </div>\n\n <!-- Bank Selection State -->\n <div *ngIf=\"isBankSelectionState\" class=\"state-bank-selection\">\n <h3 class=\"section-title\">{{ selectBankTitle }}</h3>\n\n <!-- Bank Grid -->\n <div class=\"banks-grid\" *ngIf=\"banks.length > 0\">\n <div\n *ngFor=\"let bank of banks\"\n class=\"bank-card\"\n [class.selected]=\"selectedBank === bank.bankCode\"\n (click)=\"selectBank(bank)\">\n <div class=\"bank-logo\" *ngIf=\"bank.logoUrl\">\n <img [src]=\"bank.logoUrl\" [alt]=\"bank.displayName\">\n </div>\n <div class=\"bank-info\">\n <h4>{{ bank.displayName }}</h4>\n <span class=\"bank-code\">{{ bank.bankCode }}</span>\n </div>\n <mat-icon class=\"check-icon\" *ngIf=\"selectedBank === bank.bankCode\">check_circle</mat-icon>\n </div>\n </div>\n\n <button\n mat-raised-button\n color=\"primary\"\n (click)=\"proceedToNextStep()\"\n [disabled]=\"!selectedBank || (isLoadingSubject | async)\"\n class=\"m-t-16\">\n {{ continueButtonLabel }}\n </button>\n </div>\n\n <!-- Consent State -->\n <div *ngIf=\"isConsentState\" class=\"state-consent\">\n <div class=\"consent-header\">\n <h3>{{ consentTitle }}</h3>\n <p>{{ consentDescription }}</p>\n </div>\n\n <!-- Show iframe only if we have an authorization URL -->\n <div class=\"consent-container\" *ngIf=\"authorizationUrl\">\n <iframe\n [src]=\"authorizationUrl\"\n class=\"consent-iframe\"\n frameborder=\"0\"\n allowfullscreen\n sandbox=\"allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox allow-top-navigation\">\n </iframe>\n </div>\n\n <!-- Show waiting message when consent is in popup or iframe failed -->\n <div class=\"consent-waiting\" *ngIf=\"!authorizationUrl\">\n <mat-spinner diameter=\"40\"></mat-spinner>\n <p>{{ waitingForAuthorizationText }}</p>\n <p class=\"consent-popup-hint\">\n <mat-icon>open_in_new</mat-icon>\n <span>{{ popupWindowMessage }}</span>\n </p>\n <p class=\"consent-popup-note\">\n {{ popupBlockerMessage }}\n </p>\n </div>\n </div>\n\n <!-- Processing State -->\n <div *ngIf=\"isProcessingState\" class=\"state-processing\">\n <div class=\"loading-container\">\n <mat-spinner diameter=\"50\"></mat-spinner>\n <p class=\"loading-message\">{{ waitingMessage }}</p>\n <div class=\"progress-details\">\n <p *ngIf=\"accounts.length > 0\">\n {{ accountsRetrievedLabel }}: {{ accounts.length }}\n </p>\n <p *ngIf=\"transactions.length > 0\">\n {{ transactionsRetrievedLabel }}: {{ transactions.length }}\n </p>\n </div>\n </div>\n </div>\n\n <!-- Error State -->\n <div *ngIf=\"isErrorState\" class=\"state-error\">\n <div class=\"error-container\">\n <mat-icon color=\"warn\" class=\"error-icon\">error_outline</mat-icon>\n <p class=\"error-message\">{{ errorMessage }}</p>\n <button mat-raised-button color=\"primary\" (click)=\"retry()\">\n {{ retryButtonLabel }}\n </button>\n </div>\n </div>\n\n <!-- Complete State -->\n <div *ngIf=\"isCompleteState\" class=\"state-complete\">\n <div class=\"success-container\">\n <mat-icon color=\"primary\" class=\"success-icon\">check_circle</mat-icon>\n <p class=\"success-message\">{{ completionMessage }}</p>\n\n <!-- Display summary of accounts found -->\n <div class=\"accounts-summary\" *ngIf=\"accounts.length > 0\">\n <h4>{{ accountsSummaryText }}</h4>\n <div class=\"accounts-list\">\n <div class=\"account-card\" *ngFor=\"let account of accounts\">\n <div class=\"account-header\">\n <mat-icon class=\"account-icon\">account_balance</mat-icon>\n <div class=\"account-info\">\n <div class=\"account-name\">{{ account.name || 'Account' }}</div>\n <div class=\"account-iban\">{{ account.iban }}</div>\n </div>\n </div>\n <div class=\"account-details\">\n <div class=\"account-balance\">\n <span class=\"balance-amount\">{{ account.balance | currency:account.currency:'symbol':'1.2-2' }}</span>\n </div>\n <div class=\"account-holder\">{{ account.accountHolderName }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"transaction-summary\" *ngIf=\"transactions.length > 0\">\n <p>{{ transactionsSummaryText }}</p>\n </div>\n </div>\n </div>\n </div>\n</div>", styles: [".open-banking-container{padding:20px;min-height:400px}.open-banking-container .section-title{margin-bottom:20px;font-size:1.25rem;font-weight:500;color:#000000de}.open-banking-container .message-container,.open-banking-container .loading-container,.open-banking-container .error-container,.open-banking-container .success-container{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;min-height:200px}.open-banking-container .message,.open-banking-container .loading-message,.open-banking-container .error-message,.open-banking-container .success-message{font-size:1rem;margin:20px 0;max-width:600px;line-height:1.5}.open-banking-container .error-message{color:#f44336}.open-banking-container .success-message{color:#4caf50}.open-banking-container .error-icon,.open-banking-container .success-icon{font-size:48px;width:48px;height:48px}.open-banking-container .state-bank-selection .banks-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:16px;margin-bottom:24px}.open-banking-container .state-bank-selection .bank-card{border:2px solid #e0e0e0;border-radius:8px;padding:16px;cursor:pointer;transition:all .3s ease;position:relative;background:#fff;min-height:120px;display:flex;flex-direction:column;align-items:center;justify-content:center}.open-banking-container .state-bank-selection .bank-card:hover{border-color:#3f51b5;box-shadow:0 4px 8px #0000001a;transform:translateY(-2px)}.open-banking-container .state-bank-selection .bank-card.selected{border-color:#3f51b5;background:#f5f7ff}.open-banking-container .state-bank-selection .bank-card .bank-logo{width:80px;height:40px;margin-bottom:8px;display:flex;align-items:center;justify-content:center}.open-banking-container .state-bank-selection .bank-card .bank-logo img{max-width:100%;max-height:100%;object-fit:contain}.open-banking-container .state-bank-selection .bank-card .bank-info{text-align:center}.open-banking-container .state-bank-selection .bank-card .bank-info h4{margin:0;font-size:.9rem;font-weight:500;color:#333}.open-banking-container .state-bank-selection .bank-card .bank-info .bank-code{font-size:.75rem;color:#666;margin-top:4px;display:block}.open-banking-container .state-bank-selection .bank-card .check-icon{position:absolute;top:8px;right:8px;color:#3f51b5;font-size:20px}.open-banking-container .state-bank-selection .bank-dropdown{margin:20px 0}.open-banking-container .state-bank-selection .bank-selector{width:100%;max-width:400px}.open-banking-container .state-consent .consent-header{text-align:center;margin-bottom:20px}.open-banking-container .state-consent .consent-header h3{font-size:1.25rem;font-weight:500;margin-bottom:8px}.open-banking-container .state-consent .consent-header p{color:#666;font-size:.95rem}.open-banking-container .state-consent .consent-container{width:100%;height:600px;border:1px solid #e0e0e0;border-radius:4px;overflow:hidden;background:#fff}.open-banking-container .state-consent .consent-iframe{width:100%;height:100%}.open-banking-container .state-consent .consent-waiting{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:300px}.open-banking-container .state-consent .consent-waiting p{margin-top:16px;color:#666}.open-banking-container .state-consent .consent-waiting .consent-popup-hint{display:flex;align-items:center;gap:8px;margin-top:24px;font-size:1.1rem;color:#333}.open-banking-container .state-consent .consent-waiting .consent-popup-hint mat-icon{color:#3f51b5}.open-banking-container .state-consent .consent-waiting .consent-popup-note{margin-top:12px;font-size:.9rem;color:#999;font-style:italic}.open-banking-container .progress-details{margin-top:20px}.open-banking-container .progress-details p{font-size:.9rem;color:#666;margin:4px 0}.open-banking-container .accounts-summary{margin-top:30px;width:100%;max-width:800px}.open-banking-container .accounts-summary h4{font-size:1.15rem;font-weight:500;margin-bottom:20px;color:#000000de}.open-banking-container .accounts-summary .accounts-list{display:flex;flex-direction:column;gap:16px}.open-banking-container .accounts-summary .account-card{border:1px solid #e0e0e0;border-radius:8px;padding:16px;background:#fff;box-shadow:0 1px 3px #0000001a;transition:box-shadow .2s ease}.open-banking-container .accounts-summary .account-card:hover{box-shadow:0 2px 6px #00000026}.open-banking-container .accounts-summary .account-header{display:flex;align-items:flex-start;gap:12px;margin-bottom:12px}.open-banking-container .accounts-summary .account-icon{color:#3f51b5;margin-top:2px}.open-banking-container .accounts-summary .account-info{flex:1}.open-banking-container .accounts-summary .account-name{font-weight:500;font-size:1rem;color:#333;margin-bottom:4px}.open-banking-container .accounts-summary .account-iban{font-size:.85rem;color:#666;font-family:Courier New,monospace;letter-spacing:.5px}.open-banking-container .accounts-summary .account-details{display:flex;justify-content:space-between;align-items:center;padding-left:36px}.open-banking-container .accounts-summary .account-balance{display:flex;flex-direction:column}.open-banking-container .accounts-summary .balance-amount{font-size:1.25rem;font-weight:600;color:#4caf50}.open-banking-container .accounts-summary .account-holder{font-size:.9rem;color:#666;text-align:right}.open-banking-container .accounts-summary .transaction-summary{margin-top:16px;padding:12px;background:#e8f5e9;border-radius:4px}.open-banking-container .accounts-summary .transaction-summary p{margin:0;color:#2e7d32;font-size:.95rem}.open-banking-container ::ng-deep .mat-spinner{margin:0 auto}.open-banking-container ::ng-deep .mat-progress-spinner circle,.open-banking-container ::ng-deep .mat-spinner circle{stroke:#3f51b5}@media (max-width: 768px){.open-banking-container{padding:10px}.open-banking-container .state-bank-selection .banks-grid{grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px}.open-banking-container .state-bank-selection .bank-card{min-height:100px;padding:12px}.open-banking-container .state-bank-selection .bank-card .bank-logo{width:60px;height:30px}.open-banking-container .consent-container{height:500px}.open-banking-container .accounts-summary{max-width:100%}}@media (max-width: 480px){.open-banking-container .state-bank-selection .banks-grid{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i5.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i7.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.CurrencyPipe, name: "currency" }] }); }
|
|
585
|
+
}
|
|
586
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FormlyOpenBankingComponent, decorators: [{
|
|
587
|
+
type: Component,
|
|
588
|
+
args: [{ selector: 'app-formly-open-banking', template: "<div class=\"open-banking-container\">\n <!-- Initial State -->\n <div *ngIf=\"isInitialState\" class=\"state-initial\">\n <div class=\"message-container\">\n <p class=\"message\">{{ initialMessage }}</p>\n <button mat-raised-button color=\"primary\" (click)=\"proceedToNextStep()\" [disabled]=\"isLoadingSubject | async\">\n {{ nextButtonLabel }}\n </button>\n </div>\n </div>\n\n <!-- Bank Selection State -->\n <div *ngIf=\"isBankSelectionState\" class=\"state-bank-selection\">\n <h3 class=\"section-title\">{{ selectBankTitle }}</h3>\n\n <!-- Bank Grid -->\n <div class=\"banks-grid\" *ngIf=\"banks.length > 0\">\n <div\n *ngFor=\"let bank of banks\"\n class=\"bank-card\"\n [class.selected]=\"selectedBank === bank.bankCode\"\n (click)=\"selectBank(bank)\">\n <div class=\"bank-logo\" *ngIf=\"bank.logoUrl\">\n <img [src]=\"bank.logoUrl\" [alt]=\"bank.displayName\">\n </div>\n <div class=\"bank-info\">\n <h4>{{ bank.displayName }}</h4>\n <span class=\"bank-code\">{{ bank.bankCode }}</span>\n </div>\n <mat-icon class=\"check-icon\" *ngIf=\"selectedBank === bank.bankCode\">check_circle</mat-icon>\n </div>\n </div>\n\n <button\n mat-raised-button\n color=\"primary\"\n (click)=\"proceedToNextStep()\"\n [disabled]=\"!selectedBank || (isLoadingSubject | async)\"\n class=\"m-t-16\">\n {{ continueButtonLabel }}\n </button>\n </div>\n\n <!-- Consent State -->\n <div *ngIf=\"isConsentState\" class=\"state-consent\">\n <div class=\"consent-header\">\n <h3>{{ consentTitle }}</h3>\n <p>{{ consentDescription }}</p>\n </div>\n\n <!-- Show iframe only if we have an authorization URL -->\n <div class=\"consent-container\" *ngIf=\"authorizationUrl\">\n <iframe\n [src]=\"authorizationUrl\"\n class=\"consent-iframe\"\n frameborder=\"0\"\n allowfullscreen\n sandbox=\"allow-forms allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox allow-top-navigation\">\n </iframe>\n </div>\n\n <!-- Show waiting message when consent is in popup or iframe failed -->\n <div class=\"consent-waiting\" *ngIf=\"!authorizationUrl\">\n <mat-spinner diameter=\"40\"></mat-spinner>\n <p>{{ waitingForAuthorizationText }}</p>\n <p class=\"consent-popup-hint\">\n <mat-icon>open_in_new</mat-icon>\n <span>{{ popupWindowMessage }}</span>\n </p>\n <p class=\"consent-popup-note\">\n {{ popupBlockerMessage }}\n </p>\n </div>\n </div>\n\n <!-- Processing State -->\n <div *ngIf=\"isProcessingState\" class=\"state-processing\">\n <div class=\"loading-container\">\n <mat-spinner diameter=\"50\"></mat-spinner>\n <p class=\"loading-message\">{{ waitingMessage }}</p>\n <div class=\"progress-details\">\n <p *ngIf=\"accounts.length > 0\">\n {{ accountsRetrievedLabel }}: {{ accounts.length }}\n </p>\n <p *ngIf=\"transactions.length > 0\">\n {{ transactionsRetrievedLabel }}: {{ transactions.length }}\n </p>\n </div>\n </div>\n </div>\n\n <!-- Error State -->\n <div *ngIf=\"isErrorState\" class=\"state-error\">\n <div class=\"error-container\">\n <mat-icon color=\"warn\" class=\"error-icon\">error_outline</mat-icon>\n <p class=\"error-message\">{{ errorMessage }}</p>\n <button mat-raised-button color=\"primary\" (click)=\"retry()\">\n {{ retryButtonLabel }}\n </button>\n </div>\n </div>\n\n <!-- Complete State -->\n <div *ngIf=\"isCompleteState\" class=\"state-complete\">\n <div class=\"success-container\">\n <mat-icon color=\"primary\" class=\"success-icon\">check_circle</mat-icon>\n <p class=\"success-message\">{{ completionMessage }}</p>\n\n <!-- Display summary of accounts found -->\n <div class=\"accounts-summary\" *ngIf=\"accounts.length > 0\">\n <h4>{{ accountsSummaryText }}</h4>\n <div class=\"accounts-list\">\n <div class=\"account-card\" *ngFor=\"let account of accounts\">\n <div class=\"account-header\">\n <mat-icon class=\"account-icon\">account_balance</mat-icon>\n <div class=\"account-info\">\n <div class=\"account-name\">{{ account.name || 'Account' }}</div>\n <div class=\"account-iban\">{{ account.iban }}</div>\n </div>\n </div>\n <div class=\"account-details\">\n <div class=\"account-balance\">\n <span class=\"balance-amount\">{{ account.balance | currency:account.currency:'symbol':'1.2-2' }}</span>\n </div>\n <div class=\"account-holder\">{{ account.accountHolderName }}</div>\n </div>\n </div>\n </div>\n\n <div class=\"transaction-summary\" *ngIf=\"transactions.length > 0\">\n <p>{{ transactionsSummaryText }}</p>\n </div>\n </div>\n </div>\n </div>\n</div>", styles: [".open-banking-container{padding:20px;min-height:400px}.open-banking-container .section-title{margin-bottom:20px;font-size:1.25rem;font-weight:500;color:#000000de}.open-banking-container .message-container,.open-banking-container .loading-container,.open-banking-container .error-container,.open-banking-container .success-container{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;min-height:200px}.open-banking-container .message,.open-banking-container .loading-message,.open-banking-container .error-message,.open-banking-container .success-message{font-size:1rem;margin:20px 0;max-width:600px;line-height:1.5}.open-banking-container .error-message{color:#f44336}.open-banking-container .success-message{color:#4caf50}.open-banking-container .error-icon,.open-banking-container .success-icon{font-size:48px;width:48px;height:48px}.open-banking-container .state-bank-selection .banks-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:16px;margin-bottom:24px}.open-banking-container .state-bank-selection .bank-card{border:2px solid #e0e0e0;border-radius:8px;padding:16px;cursor:pointer;transition:all .3s ease;position:relative;background:#fff;min-height:120px;display:flex;flex-direction:column;align-items:center;justify-content:center}.open-banking-container .state-bank-selection .bank-card:hover{border-color:#3f51b5;box-shadow:0 4px 8px #0000001a;transform:translateY(-2px)}.open-banking-container .state-bank-selection .bank-card.selected{border-color:#3f51b5;background:#f5f7ff}.open-banking-container .state-bank-selection .bank-card .bank-logo{width:80px;height:40px;margin-bottom:8px;display:flex;align-items:center;justify-content:center}.open-banking-container .state-bank-selection .bank-card .bank-logo img{max-width:100%;max-height:100%;object-fit:contain}.open-banking-container .state-bank-selection .bank-card .bank-info{text-align:center}.open-banking-container .state-bank-selection .bank-card .bank-info h4{margin:0;font-size:.9rem;font-weight:500;color:#333}.open-banking-container .state-bank-selection .bank-card .bank-info .bank-code{font-size:.75rem;color:#666;margin-top:4px;display:block}.open-banking-container .state-bank-selection .bank-card .check-icon{position:absolute;top:8px;right:8px;color:#3f51b5;font-size:20px}.open-banking-container .state-bank-selection .bank-dropdown{margin:20px 0}.open-banking-container .state-bank-selection .bank-selector{width:100%;max-width:400px}.open-banking-container .state-consent .consent-header{text-align:center;margin-bottom:20px}.open-banking-container .state-consent .consent-header h3{font-size:1.25rem;font-weight:500;margin-bottom:8px}.open-banking-container .state-consent .consent-header p{color:#666;font-size:.95rem}.open-banking-container .state-consent .consent-container{width:100%;height:600px;border:1px solid #e0e0e0;border-radius:4px;overflow:hidden;background:#fff}.open-banking-container .state-consent .consent-iframe{width:100%;height:100%}.open-banking-container .state-consent .consent-waiting{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:300px}.open-banking-container .state-consent .consent-waiting p{margin-top:16px;color:#666}.open-banking-container .state-consent .consent-waiting .consent-popup-hint{display:flex;align-items:center;gap:8px;margin-top:24px;font-size:1.1rem;color:#333}.open-banking-container .state-consent .consent-waiting .consent-popup-hint mat-icon{color:#3f51b5}.open-banking-container .state-consent .consent-waiting .consent-popup-note{margin-top:12px;font-size:.9rem;color:#999;font-style:italic}.open-banking-container .progress-details{margin-top:20px}.open-banking-container .progress-details p{font-size:.9rem;color:#666;margin:4px 0}.open-banking-container .accounts-summary{margin-top:30px;width:100%;max-width:800px}.open-banking-container .accounts-summary h4{font-size:1.15rem;font-weight:500;margin-bottom:20px;color:#000000de}.open-banking-container .accounts-summary .accounts-list{display:flex;flex-direction:column;gap:16px}.open-banking-container .accounts-summary .account-card{border:1px solid #e0e0e0;border-radius:8px;padding:16px;background:#fff;box-shadow:0 1px 3px #0000001a;transition:box-shadow .2s ease}.open-banking-container .accounts-summary .account-card:hover{box-shadow:0 2px 6px #00000026}.open-banking-container .accounts-summary .account-header{display:flex;align-items:flex-start;gap:12px;margin-bottom:12px}.open-banking-container .accounts-summary .account-icon{color:#3f51b5;margin-top:2px}.open-banking-container .accounts-summary .account-info{flex:1}.open-banking-container .accounts-summary .account-name{font-weight:500;font-size:1rem;color:#333;margin-bottom:4px}.open-banking-container .accounts-summary .account-iban{font-size:.85rem;color:#666;font-family:Courier New,monospace;letter-spacing:.5px}.open-banking-container .accounts-summary .account-details{display:flex;justify-content:space-between;align-items:center;padding-left:36px}.open-banking-container .accounts-summary .account-balance{display:flex;flex-direction:column}.open-banking-container .accounts-summary .balance-amount{font-size:1.25rem;font-weight:600;color:#4caf50}.open-banking-container .accounts-summary .account-holder{font-size:.9rem;color:#666;text-align:right}.open-banking-container .accounts-summary .transaction-summary{margin-top:16px;padding:12px;background:#e8f5e9;border-radius:4px}.open-banking-container .accounts-summary .transaction-summary p{margin:0;color:#2e7d32;font-size:.95rem}.open-banking-container ::ng-deep .mat-spinner{margin:0 auto}.open-banking-container ::ng-deep .mat-progress-spinner circle,.open-banking-container ::ng-deep .mat-spinner circle{stroke:#3f51b5}@media (max-width: 768px){.open-banking-container{padding:10px}.open-banking-container .state-bank-selection .banks-grid{grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px}.open-banking-container .state-bank-selection .bank-card{min-height:100px;padding:12px}.open-banking-container .state-bank-selection .bank-card .bank-logo{width:60px;height:30px}.open-banking-container .consent-container{height:500px}.open-banking-container .accounts-summary{max-width:100%}}@media (max-width: 480px){.open-banking-container .state-bank-selection .banks-grid{grid-template-columns:1fr}}\n"] }]
|
|
589
|
+
}], ctorParameters: () => [{ type: i1.OpenBankingService }, { type: i2.DialogService }, { type: i3.DomSanitizer }, { type: i0.ChangeDetectorRef }] });
|
|
590
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybWx5LW9wZW4tYmFua2luZy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9vcmlnaW4tZm9ybS9zcmMvbGliL2Zvcm1seS9mb3JtbHktb3Blbi1iYW5raW5nL2Zvcm1seS1vcGVuLWJhbmtpbmcuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvb3JpZ2luLWZvcm0vc3JjL2xpYi9mb3JtbHkvZm9ybWx5LW9wZW4tYmFua2luZy9mb3JtbHktb3Blbi1iYW5raW5nLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEdBS1YsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFdBQVcsRUFBYSxNQUFNLGdCQUFnQixDQUFDO0FBQ3hELE9BQU8sRUFBRSxlQUFlLEVBQUUsUUFBUSxFQUFnQixNQUFNLE1BQU0sQ0FBQztBQUMvRCxPQUFPLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNoRSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQzs7Ozs7Ozs7O0FBb0NyRSxJQUFLLGdCQU9KO0FBUEQsV0FBSyxnQkFBZ0I7SUFDbkIsdUNBQW1CLENBQUE7SUFDbkIsbURBQStCLENBQUE7SUFDL0IsdUNBQW1CLENBQUE7SUFDbkIsNkNBQXlCLENBQUE7SUFDekIsbUNBQWUsQ0FBQTtJQUNmLHlDQUFxQixDQUFBO0FBQ3ZCLENBQUMsRUFQSSxnQkFBZ0IsS0FBaEIsZ0JBQWdCLFFBT3BCO0FBT0QsTUFBTSxPQUFPLDBCQUNYLFNBQVEsdUJBQXVCO0lBcUIvQixZQUNVLGtCQUFzQyxFQUN0QyxNQUFxQixFQUNyQixTQUF1QixFQUMvQixHQUFzQjtRQUV0QixLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7UUFMSCx1QkFBa0IsR0FBbEIsa0JB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QUNwRSxDQUFDO0lBRUQsSUFBSSxjQUFjO1FBQ2hCLE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQyxLQUFLLEtBQUssZ0JBQWdCLENBQUMsT0FBTyxDQUFDO0lBQzlELENBQUM7SUFFRCxJQUFJLGlCQUFpQjtRQUNuQixPQUFPLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxLQUFLLGdCQUFnQixDQUFDLFVBQVUsQ0FBQztJQUNqRSxDQUFDO0lBRUQsSUFBSSxZQUFZO1FBQ2QsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDLEtBQUssS0FBSyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUM7SUFDNUQsQ0FBQztJQUVELElBQUksZUFBZTtRQUNqQixPQUFPLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxLQUFLLGdCQUFnQixDQUFDLFFBQVEsQ0FBQztJQUMvRCxDQUFDO0lBRU8sZUFBZSxDQUFDLE9BQWdCO1FBQ3RDLElBQUksQ0FBQyxTQUFTLEdBQUcsT0FBTyxDQUFDO1FBQ3pCLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDcEMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUMzQixDQUFDO0lBRUQsV0FBVztRQUNULElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxXQUFXLEVBQUUsQ0FBQztRQUNyQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDbkMsQ0FBQzsrR0Evc0JVLDBCQUEwQjttR0FBMUIsMEJBQTBCLHNGQzVEdkMsdStKQXVJTTs7NEZEM0VPLDBCQUEwQjtrQkFMdEMsU0FBUzsrQkFDRSx5QkFBeUIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDb21wb25lbnQsXG4gIE9uSW5pdCxcbiAgQWZ0ZXJWaWV3SW5pdCxcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gIE9uRGVzdHJveSxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBGb3JtQ29udHJvbCwgRm9ybUdyb3VwIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBpbnRlcnZhbCwgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBzd2l0Y2hNYXAsIHRha2VXaGlsZSwgZmluYWxpemUgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBCYXNlRm9ybWx5U3RlcENvbXBvbmVudCB9IGZyb20gJy4uL2Jhc2VGb3JtbHlTdGVwQ29tcG9uZW50JztcblxuaW1wb3J0IHsgRG9tU2FuaXRpemVyLCBTYWZlUmVzb3VyY2VVcmwgfSBmcm9tICdAYW5ndWxhci9wbGF0Zm9ybS1icm93c2VyJztcbmltcG9ydCB7IEh0dHBFcnJvclJlc3BvbnNlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHsgRGlhbG9nU2VydmljZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL2RpYWxvZy5zZXJ2aWNlJztcbmltcG9ydCB7IEJhbmssIEFjY291bnQsIFRyYW5zYWN0aW9uLCBUcmFuc2FjdGlvblBhZ2UsIE9wZW5CYW5raW5nU2VydmljZSwgQ29uc2VudEluaXRSZXF1ZXN0LCBDb25zZW50U3RhdHVzIH0gZnJvbSAnLi4vLi4vc2VydmljZXMvb3Blbi1iYW5raW5nLnNlcnZpY2UnO1xuXG5pbnRlcmZhY2UgT3BlbkJhbmtpbmdDb25maWcge1xuICBhY2NvdW50TnVtYmVyQ29sbGVjdGVkPzogc3RyaW5nO1xuICBhY2NvdW50SG9sZGVyQ29sbGVjdGVkPzogc3RyaW5nO1xuICBlbWFpbENvbGxlY3RlZD86IHN0cmluZztcbiAgc2hvd0FsbEJhbmtzPzogYm9vbGVhbjtcbiAgZXh0cmFjdEJhbmtGcm9tSUJBTj86IGJvb2xlYW47XG4gIHRjQWNjZXB0ZWRCeURlZmF1bHQ/OiBib29sZWFuO1xuICAvLyBNZXNzYWdlIHRyYW5zbGF0aW9uc1xuICBpbml0aWFsTWVzc2FnZVRyYW5zbGF0aW9ucz86IGFueVtdO1xuICB3YWl0aW5nTWVzc2FnZVRyYW5zbGF0aW9ucz86IGFueVtdO1xuICBjb25zZW50RXJyb3JNZXNzYWdlVHJhbnNsYXRpb25zPzogYW55W107XG4gIGNvbXBsZXRpb25NZXNzYWdlVHJhbnNsYXRpb25zPzogYW55W107XG4gIHJldHJ5QnV0dG9uTGFiZWxUcmFuc2xhdGlvbnM/OiBhbnlbXTtcbiAgLy8gQnV0dG9uIHRyYW5zbGF0aW9uc1xuICBuZXh0QnV0dG9uVHJhbnNsYXRpb25zPzogYW55W107XG4gIGNvbnRpbnVlQnV0dG9uVHJhbnNsYXRpb25zPzogYW55W107XG4gIC8vIFVJIGxhYmVscyB0cmFuc2xhdGlvbnNcbiAgc2VsZWN0QmFua1RyYW5zbGF0aW9ucz86IGFueVtdO1xuICBjb25zZW50VGl0bGVUcmFuc2xhdGlvbnM/OiBhbnlbXTtcbiAgY29uc2VudERlc2NyaXB0aW9uVHJhbnNsYXRpb25zPzogYW55W107XG4gIHdhaXRpbmdGb3JBdXRob3JpemF0aW9uVHJhbnNsYXRpb25zPzogYW55W107XG4gIHBvcHVwV2luZG93TWVzc2FnZVRyYW5zbGF0aW9ucz86IGFueVtdO1xuICBwb3B1cEJsb2NrZXJNZXNzYWdlVHJhbnNsYXRpb25zPzogYW55W107XG4gIGFjY291bnRzUmV0cmlldmVkVHJhbnNsYXRpb25zPzogYW55W107XG4gIHRyYW5zYWN0aW9uc1JldHJpZXZlZFRyYW5zbGF0aW9ucz86IGFueVtdO1xuICBhY2NvdW50c0ZvdW5kVHJhbnNsYXRpb25zPzogYW55W107XG4gIHRyYW5zYWN0aW9uc1N1bW1hcnlUcmFuc2xhdGlvbnM/OiBhbnlbXTtcbn1cblxuZW51bSBPcGVuQmFua2luZ1N0YXRlIHtcbiAgSW5pdGlhbCA9ICdpbml0aWFsJyxcbiAgQmFua1NlbGVjdGlvbiA9ICdiYW5rU2VsZWN0aW9uJyxcbiAgQ29uc2VudCA9ICdjb25zZW50JyxcbiAgUHJvY2Vzc2luZyA9ICdwcm9jZXNzaW5nJyxcbiAgRXJyb3IgPSAnZXJyb3InLFxuICBDb21wbGV0ZSA9ICdjb21wbGV0ZScsXG59XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2FwcC1mb3JtbHktb3Blbi1iYW5raW5nJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2Zvcm1seS1vcGVuLWJhbmtpbmcuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9mb3JtbHktb3Blbi1iYW5raW5nLmNvbXBvbmVudC5zY3NzJ10sXG59KVxuZXhwb3J0IGNsYXNzIEZvcm1seU9wZW5CYW5raW5nQ29tcG9uZW50XG4gIGV4dGVuZHMgQmFzZUZvcm1seVN0ZXBDb21wb25lbnRcbiAgaW1wbGVtZW50cyBPbkluaXQsIEFmdGVyVmlld0luaXQsIE9uRGVzdHJveVxue1xuICBjb25maWc6IE9wZW5CYW5raW5nQ29uZmlnID0ge307XG4gIGN1cnJlbnRTdGF0ZSA9IG5ldyBCZWhhdmlvclN1YmplY3Q8T3BlbkJhbmtpbmdTdGF0ZT4oT3BlbkJhbmtpbmdTdGF0ZS5Jbml0aWFsKTtcbiAgYmFua3M6IEJhbmtbXSA9IFtdO1xuICBzZWxlY3RlZEJhbms6IHN0cmluZyA9ICcnO1xuICBzZWxlY3RlZEJhbmtPYmplY3Q/OiBCYW5rO1xuICBhdXRob3JpemF0aW9uVXJsOiBTYWZlUmVzb3VyY2VVcmwgfCBudWxsID0gbnVsbDtcbiAgY29uc2VudElkOiBzdHJpbmcgPSAnJztcbiAgcHJpdmF0ZSBfZXJyb3JNZXNzYWdlOiBzdHJpbmcgPSAnJztcbiAgcHJpdmF0ZSBfaXNDb25zZW50RXJyb3I6IGJvb2xlYW4gPSBmYWxzZTtcbiAgcHJpdmF0ZSBfY29uc2VudEVycm9yU3RhdHVzOiBzdHJpbmcgPSAnJztcbiAgb3ZlcnJpZGUgaXNMb2FkaW5nOiBib29sZWFuID0gZmFsc2U7XG4gIGlzTG9hZGluZ1N1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgYWNjb3VudHM6IEFjY291bnRbXSA9IFtdO1xuICB0cmFuc2FjdGlvbnM6IFRyYW5zYWN0aW9uW10gPSBbXTtcbiAgcG9sbFN1YnNjcmlwdGlvbj86IFN1YnNjcmlwdGlvbjtcbiAgc2VsZWN0ZWRBY2NvdW50czogc3RyaW5nW10gPSBbXTtcbiAgdHJhbnNhY3Rpb25QYWdlczogTWFwPHN0cmluZywgVHJhbnNhY3Rpb25QYWdlPiA9IG5ldyBNYXAoKTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIG9wZW5CYW5raW5nU2VydmljZTogT3BlbkJhbmtpbmdTZXJ2aWNlLFxuICAgIHByaXZhdGUgZGlhbG9nOiBEaWFsb2dTZXJ2aWNlLFxuICAgIHByaXZhdGUgc2FuaXRpemVyOiBEb21TYW5pdGl6ZXIsXG4gICAgY2RyOiBDaGFuZ2VEZXRlY3RvclJlZlxuICApIHtcbiAgICBzdXBlcihjZHIpO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgbmdPbkluaXQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgc3VwZXIubmdPbkluaXQoKTtcbiAgICBpZiAodGhpcy5zdGVwRGF0YT8uY29uZmlnKSB7XG4gICAgICB0aGlzLmNvbmZpZyA9IHRoaXMuc3RlcERhdGEuY29uZmlnIGFzIE9wZW5CYW5raW5nQ29uZmlnO1xuICAgIH1cbiAgICAvLyBJZiB0cmFuc2xhdGlvbnMgYXJlIGluIHN0ZXBEYXRhLnRyYW5zbGF0aW9ucywgbWVyZ2UgdGhlbSBpbnRvIGNvbmZpZ1xuICAgIGlmICh0aGlzLnN0ZXBEYXRhPy50cmFuc2xhdGlvbnMpIHtcbiAgICAgIHRoaXMubWVyZ2VUcmFuc2xhdGlvbnNJbnRvQ29uZmlnKCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBtZXJnZVRyYW5zbGF0aW9uc0ludG9Db25maWcoKTogdm9pZCB7XG4gICAgLy8gTWFwIHRyYW5zbGF0aW9uIG5hbWVzIHRvIGNvbmZpZyBwcm9wZXJ0aWVzXG4gICAgY29uc3QgdHJhbnNsYXRpb25NYXA6IHsgW2tleTogc3RyaW5nXToga2V5b2YgT3BlbkJhbmtpbmdDb25maWcgfSA9IHtcbiAgICAgICdpbml0aWFsTWVzc2FnZVRyYW5zbGF0aW9ucyc6ICdpbml0aWFsTWVzc2FnZVRyYW5zbGF0aW9ucycsXG4gICAgICAnd2FpdGluZ01lc3NhZ2VUcmFuc2xhdGlvbnMnOiAnd2FpdGluZ01lc3NhZ2VUcmFuc2xhdGlvbnMnLFxuICAgICAgJ2NvbnNlbnRFcnJvck1lc3NhZ2VUcmFuc2xhdGlvbnMnOiAnY29uc2VudEVycm9yTWVzc2FnZVRyYW5zbGF0aW9ucycsXG4gICAgICAnY29tcGxldGlvbk1lc3NhZ2VUcmFuc2xhdGlvbnMnOiAnY29tcGxldGlvbk1lc3NhZ2VUcmFuc2xhdGlvbnMnLFxuICAgICAgJ3JldHJ5QnV0dG9uTGFiZWxUcmFuc2xhdGlvbnMnOiAncmV0cnlCdXR0b25MYWJlbFRyYW5zbGF0aW9ucycsXG4gICAgICAnbmV4dEJ1dHRvblRyYW5zbGF0aW9ucyc6ICduZXh0QnV0dG9uVHJhbnNsYXRpb25zJyxcbiAgICAgICdjb250aW51ZUJ1dHRvblRyYW5zbGF0aW9ucyc6ICdjb250aW51ZUJ1dHRvblRyYW5zbGF0aW9ucycsXG4gICAgICAnc2VsZWN0QmFua1RyYW5zbGF0aW9ucyc6ICdzZWxlY3RCYW5rVHJhbnNsYXRpb25zJyxcbiAgICAgICdjb25zZW50VGl0bGVUcmFuc2xhdGlvbnMnOiAnY29uc2VudFRpdGxlVHJhbnNsYXRpb25zJyxcbiAgICAgICdjb25zZW50RGVzY3JpcHRpb25UcmFuc2xhdGlvbnMnOiAnY29uc2VudERlc2NyaXB0aW9uVHJhbnNsYXRpb25zJyxcbiAgICAgICd3YWl0aW5nRm9yQXV0aG9yaXphdGlvblRyYW5zbGF0aW9ucyc6ICd3YWl0aW5nRm9yQXV0aG9yaXphdGlvblRyYW5zbGF0aW9ucycsXG4gICAgICAncG9wdXBXaW5kb3dNZXNzYWdlVHJhbnNsYXRpb25zJzogJ3BvcHVwV2luZG93TWVzc2FnZVRyYW5zbGF0aW9ucycsXG4gICAgICAncG9wdXBCbG9ja2VyTWVzc2FnZVRyYW5zbGF0aW9ucyc6ICdwb3B1cEJsb2NrZXJNZXNzYWdlVHJhbnNsYXRpb25zJyxcbiAgICAgICdhY2NvdW50c1JldHJpZXZlZFRyYW5zbGF0aW9ucyc6ICdhY2NvdW50c1JldHJpZXZlZFRyYW5zbGF0aW9ucycsXG4gICAgICAndHJhbnNhY3Rpb25zUmV0cmlldmVkVHJhbnNsYXRpb25zJzogJ3RyYW5zYWN0aW9uc1JldHJpZXZlZFRyYW5zbGF0aW9ucycsXG4gICAgICAnYWNjb3VudHNGb3VuZFRyYW5zbGF0aW9ucyc6ICdhY2NvdW50c0ZvdW5kVHJhbnNsYXRpb25zJyxcbiAgICAgICd0cmFuc2FjdGlvbnNTdW1tYXJ5VHJhbnNsYXRpb25zJzogJ3RyYW5zYWN0aW9uc1N1bW1hcnlUcmFuc2xhdGlvbnMnXG4gICAgfTtcblxuICAgIHRoaXMuc3RlcERhdGEudHJhbnNsYXRpb25zPy5mb3JFYWNoKCh0cmFuc2xhdGlvbjogeyBuYW1lOiBzdHJpbmcgfCBudW1iZXI7IHZhbHVlczogc3RyaW5nIHwgYW55W107IH0pID0+IHtcbiAgICAgIGNvbnN0IGNvbmZpZ0tleSA9IHRyYW5zbGF0aW9uTWFwW3RyYW5zbGF0aW9uLm5hbWVdO1xuICAgICAgaWYgKGNvbmZpZ0tleSAmJiB0cmFuc2xhdGlvbi52YWx1ZXMgJiYgdHJhbnNsYXRpb24udmFsdWVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgLy8gVXNlIHRoZSB0cmFuc2xhdGlvbiB2YWx1ZXMgZnJvbSBzdGVwRGF0YSBpZiBjb25maWcgZG9lc24ndCBoYXZlIGFsbCBsYW5ndWFnZXNcbiAgICAgICAgKHRoaXMuY29uZmlnIGFzIGFueSlbY29uZmlnS2V5XSA9IHRyYW5zbGF0aW9uLnZhbHVlcztcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIG5nQWZ0ZXJWaWV3SW5pdCgpOiB2b2lkIHtcbiAgICAvLyBPbmx5IHNldCBpbml0aWFsIHN0YXRlIGlmIHdlIGhhdmVuJ3QgYWxyZWFkeSBzZXQgYSBzdGF0ZVxuICAgIGlmICghdGhpcy5jdXJyZW50U3RhdGUudmFsdWUpIHtcbiAgICAgIHRoaXMuY3VycmVudFN0YXRlLm5leHQoT3BlbkJhbmtpbmdTdGF0ZS5Jbml0aWFsKTtcbiAgICB9XG4gIH1cblxuICBvdmVycmlkZSBvblBhZ2VTZWxlY3RlZCgpIHtcbiAgICAvLyBPbmx5IHJlc2V0IHRvIGluaXRpYWwgaWYgd2UgaGF2ZW4ndCBzdGFydGVkIHRoZSBmbG93IHlldFxuICAgIC8vIFRoaXMgcHJldmVudHMgcmVzZXQgd2hlbiBsYW5ndWFnZSBjaGFuZ2VzXG4gICAgaWYgKCF0aGlzLmN1cnJlbnRTdGF0ZS52YWx1ZSkge1xuICAgICAgdGhpcy5jdXJyZW50U3RhdGUubmV4dChPcGVuQmFua2luZ1N0YXRlLkluaXRpYWwpO1xuICAgIH1cbiAgICAvLyBVcGRhdGUgbGFuZ3VhZ2UgaWYgaXQgY2hhbmdlZFxuICAgIHRoaXMuY2RyLmRldGVjdENoYW5nZXMoKTtcbiAgfVxuXG4gIHByaXZhdGUgZGV0ZXJtaW5lTmV4dFN0ZXAoKTogdm9pZCB7XG4gICAgLy8gR2V0IGFjY291bnQgaW5mb3JtYXRpb24gZnJvbSBmb3JtIGlmIGNvbmZpZ3VyZWRcbiAgICBjb25zdCBhY2NvdW50TnVtYmVyID0gdGhpcy5nZXRGaWVsZFZhbHVlKHRoaXMuY29uZmlnLmFjY291bnROdW1iZXJDb2xsZWN0ZWQpO1xuXG4gICAgLy8gSWYgd2Ugc2hvdWxkIGV4dHJhY3QgYmFuayBmcm9tIElCQU4gYW5kIGhhdmUgYW4gSUJBTlxuICAgIGlmICh0aGlzLmNvbmZpZy5leHRyYWN0QmFua0Zyb21JQkFOICYmIGFjY291bnROdW1iZXIgJiYgdGhpcy5pc0lCQU4oYWNjb3VudE51bWJlcikpIHtcbiAgICAgIC8vIExvYWQgYmFua3MgZmlyc3QsIHRoZW4gbWF0Y2ggSUJBTiB0byBiYW5rXG4gICAgICB0aGlzLmxvYWRCYW5rc0FuZE1hdGNoSUJBTihhY2NvdW50TnVtYmVyKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBJZiB3ZSBzaG91bGQgc2hvdyBhbGwgYmFua3NcbiAgICBpZiAodGhpcy5jb25maWcuc2hvd0FsbEJhbmtzKSB7XG4gICAgICB0aGlzLmxvYWRCYW5rcygpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBHbyBkaXJlY3RseSB0byBjb25zZW50IHdpdGhvdXQgYmFuayBzZWxlY3Rpb25cbiAgICAgIHRoaXMuaW5pdGlhdGVDb25zZW50KCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBnZXRGaWVsZFZhbHVlKGZpZWxkSWQ6IHN0cmluZyB8IHVuZGVmaW5lZCk6IHN0cmluZyB7XG4gICAgaWYgKCFmaWVsZElkKSByZXR1cm4gJyc7XG4gICAgcmV0dXJuIHRoaXMuZm9ybS5nZXQoZmllbGRJZCk/LnZhbHVlIHx8ICcnO1xuICB9XG5cbiAgcHJpdmF0ZSBpc0lCQU4odmFsdWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIC8vIEJhc2ljIElCQU4gdmFsaWRhdGlvbiBmb3IgUm9tYW5pYW4gSUJBTnNcbiAgICByZXR1cm4gL15ST1xcZHsyfVtBLVpdezR9XFxkezE2fSQvLnRlc3QodmFsdWUucmVwbGFjZSgvXFxzL2csICcnKSk7XG4gIH1cblxuICBwcml2YXRlIGV4dHJhY3RCYW5rRnJvbUlCQU4oaWJhbjogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAvLyBFeHRyYWN0IGJhbmsgY29kZSBmcm9tIFJvbWFuaWFuIElCQU4gKHBvc2l0aW9ucyA1LTgpXG4gICAgY29uc3QgY2xlYW5JYmFuID0gaWJhbi5yZXBsYWNlKC9cXHMvZywgJycpO1xuICAgIGlmIChjbGVhbkliYW4uc3RhcnRzV2l0aCgnUk8nKSAmJiBjbGVhbkliYW4ubGVuZ3RoID49IDgpIHtcbiAgICAgIHJldHVybiBjbGVhbkliYW4uc3Vic3RyaW5nKDQsIDgpO1xuICAgIH1cbiAgICByZXR1cm4gJyc7XG4gIH1cblxuICBwcml2YXRlIGxvYWRCYW5rc0FuZE1hdGNoSUJBTihpYmFuOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLnNldExvYWRpbmdTdGF0ZSh0cnVlKTtcbiAgICBjb25zdCBjb3VudHJ5Q29kZSA9ICdSTyc7IC8vIERlZmF1bHQgdG8gUm9tYW5pYVxuXG4gICAgdGhpcy5vcGVuQmFua2luZ1NlcnZpY2UuZ2V0QmFua3MoY291bnRyeUNvZGUpLnN1YnNjcmliZSh7XG4gICAgICBuZXh0OiAoYmFua3MpID0+IHtcbiAgICAgICAgdGhpcy5iYW5rcyA9IGJhbmtzLmZpbHRlcihiID0+IGIuaXNBY3RpdmUpO1xuXG4gICAgICAgIC8vIEV4dHJhY3QgYmFuayBjb2RlIGZyb20gSUJBTlxuICAgICAgICBjb25zdCBpYmFuQmFua0NvZGUgPSB0aGlzLmV4dHJhY3RCYW5rRnJvbUlCQU4oaWJhbik7XG5cbiAgICAgICAgaWYgKGliYW5CYW5rQ29kZSkge1xuICAgICAgICAgIC8vIFRyeSB0byBtYXRjaCBhZ2FpbnN0IGJhbmsgY29kZXNcbiAgICAgICAgICBjb25zdCBtYXRjaGVkQmFuayA9IHRoaXMuYmFua3MuZmluZChiYW5rID0+XG4gICAgICAgICAgICBiYW5rLmJhbmtDb2RlLnRvVXBwZXJDYXNlKCkgPT09IGliYW5CYW5rQ29kZS50b1VwcGVyQ2FzZSgpXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIGlmIChtYXRjaGVkQmFuaykge1xuICAgICAgICAgICAgLy8gQmFuayBmb3VuZCAtIHNlbGVjdCBpdCBhbmQgZ28gZGlyZWN0bHkgdG8gY29uc2VudFxuICAgICAgICAgICAgdGhpcy5zZWxlY3RlZEJhbmsgPSBtYXRjaGVkQmFuay5iYW5rQ29kZTtcbiAgICAgICAgICAgIHRoaXMuc2VsZWN0ZWRCYW5rT2JqZWN0ID0gbWF0Y2hlZEJhbms7XG4gICAgICAgICAgICB0aGlzLnNldExvYWRpbmdTdGF0ZShmYWxzZSk7XG4gICAgICAgICAgICB0aGlzLmluaXRpYXRlQ29uc2VudCgpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIElmIG5vIG1hdGNoIGZvdW5kLCBzaG93IGJhbmsgc2VsZWN0aW9uXG4gICAgICAgIHRoaXMuY3VycmVudFN0YXRlLm5leHQoT3BlbkJhbmtpbmdTdGF0ZS5CYW5rU2VsZWN0aW9uKTtcbiAgICAgICAgdGhpcy5zZXRMb2FkaW5nU3RhdGUoZmFsc2UpO1xuICAgICAgfSxcbiAgICAgIGVycm9yOiAoZXJyb3IpID0+IHtcbiAgICAgICAgdGhpcy5oYW5kbGVFcnJvcihlcnJvcik7XG4gICAgICAgIHRoaXMuc2V0TG9hZGluZ1N0YXRlKGZhbHNlKTtcbiAgICAgIH0sXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGxvYWRCYW5rcygpOiB2b2lkIHtcbiAgICB0aGlzLnNldExvYWRpbmdTdGF0ZSh0cnVlKTtcbiAgICBjb25zdCBjb3VudHJ5Q29kZSA9ICdSTyc7IC8vIERlZmF1bHQgdG8gUm9tYW5pYVxuXG4gICAgdGhpcy5vcGVuQmFua2luZ1NlcnZpY2UuZ2V0QmFua3MoY291bnRyeUNvZGUpLnN1YnNjcmliZSh7XG4gICAgICBuZXh0OiAoYmFua3MpID0+IHtcbiAgICAgICAgdGhpcy5iYW5rcyA9IGJhbmtzLmZpbHRlcihiID0+IGIuaXNBY3RpdmUpO1xuICAgICAgICB0aGlzLmN1cnJlbnRTdGF0ZS5uZXh0KE9wZW5CYW5raW5nU3RhdGUuQmFua1NlbGVjdGlvbik7XG4gICAgICAgIHRoaXMuc2V0TG9hZGluZ1N0YXRlKGZhbHNlKTtcbiAgICAgIH0sXG4gICAgICBlcnJvcjogKGVycm9yKSA9PiB7XG4gICAgICAgIHRoaXMuaGFuZGxlRXJyb3IoZXJyb3IpO1xuICAgICAgICB0aGlzLnNldExvYWRpbmdTdGF0ZShmYWxzZSk7XG4gICAgICB9LFxuICAgIH0pO1xuICB9XG5cbiAgc2VsZWN0QmFuayhiYW5rOiBCYW5rKTogdm9pZCB7XG4gICAgdGhpcy5zZWxlY3RlZEJhbmsgPSBiYW5rLmJhbmtDb2RlO1xuICAgIHRoaXMuc2VsZWN0ZWRCYW5rT2JqZWN0ID0gYmFuaztcbiAgfVxuXG4gIHByb2NlZWRUb05leHRTdGVwKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmN1cnJlbnRTdGF0ZS52YWx1ZSA9PT0gT3BlbkJhbmtpbmdTdGF0ZS5Jbml0aWFsKSB7XG4gICAgICAvLyBVc2VyIGNsaWNrZWQgTmV4dCBvbiBpbml0aWFsIHNjcmVlbiAtIGRldGVybWluZSB3aGF0IHRvIHNob3cgbmV4dFxuICAgICAgdGhpcy5kZXRlcm1pbmVOZXh0U3RlcCgpO1xuICAgIH0gZWxzZSBpZiAodGhpcy5jdXJyZW50U3RhdGUudmFsdWUgPT09IE9wZW5CYW5raW5nU3RhdGUuQmFua1NlbGVjdGlvbikge1xuICAgICAgaWYgKHRoaXMuc2VsZWN0ZWRCYW5rKSB7XG4gICAgICAgIHRoaXMuaW5pdGlhdGVDb25zZW50KCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBpbml0aWF0ZUNvbnNlbnQoKTogdm9pZCB7XG4gICAgdGhpcy5zZXRMb2FkaW5nU3RhdGUodHJ1ZSk7XG5cbiAgICAvLyBHZXQgdXNlciBpbmZvcm1hdGlvblxuICAgIGNvbnN0IGVtYWlsID0gdGhpcy5nZXRGaWVsZFZhbHVlKHRoaXMuY29uZmlnLmVtYWlsQ29sbGVjdGVkKSB8fCAndXNlckBleGFtcGxlLmNvbSc7XG4gICAgLy8gR2VuZXJhdGUgYSB1bmlxdWUgUFNVIElEIGZvciB0aGlzIHNlc3Npb25cbiAgICBjb25zdCBwc3VJZCA9IHRoaXMuYXBwRGF0YUlkIHx8ICd1c2VyLScgKyBEYXRlLm5vdygpICsgJy0nICsgTWF0aC5yYW5kb20oKS50b1N0cmluZygzNikuc3Vic3RyKDIsIDkpO1xuXG4gICAgY29uc3QgY29uc2VudFJlcXVlc3Q6IENvbnNlbnRJbml0UmVxdWVzdCA9IHtcbiAgICAgIGJhbmtDb2RlOiB0aGlzLnNlbGVjdGVkQmFuayB8fCAnREVGQVVMVCcsXG4gICAgICBwc3VFbWFpbDogZW1haWwsXG4gICAgICBwc3VJbnRlcm1lZGlhcnlJZDogcHN1SWQsXG4gICAgICBwZXJpb2RPZlZhbGlkaXR5OiA5MCxcbiAgICAgIHRjQWNjZXB0ZWQ6IHRoaXMuY29uZmlnLnRjQWNjZXB0ZWRCeURlZmF1bHQgIT09IGZhbHNlXG4gICAgfTtcblxuICAgIHRoaXMub3BlbkJhbmtpbmdTZXJ2aWNlLmluaXRpYWxpemVDb25zZW50KGNvbnNlbnRSZXF1ZXN0KS5zdWJzY3JpYmUoe1xuICAgICAgbmV4dDogKHJlc3BvbnNlKSA9PiB7XG4gICAgICAgIHRoaXMuY29uc2VudElkID0gcmVzcG9uc2UuY29uc2VudElkO1xuXG4gICAgICAgIC8vIENoZWNrIGlmIGJhbmsgcmVxdWlyZXMgcmVkaXJlY3RcbiAgICAgICAgaWYgKHRoaXMuc2VsZWN0ZWRCYW5rT2JqZWN0Py5yZXF1aXJlc1JlZGlyZWN0ICE9PSBmYWxzZSkge1xuICAgICAgICAgIC8vIFRyeSBpZnJhbWUgZmlyc3QsIGJ1dCBtb3N0IGJhbmtzIHdpbGwgYmxvY2sgaXRcbiAgICAgICAgICBpZiAodGhpcy5zaG91bGRVc2VJZnJhbWUoKSkge1xuICAgICAgICAgICAgdGhpcy5hdXRob3JpemF0aW9uVXJsID0gdGhpcy5zYW5pdGl6ZXIuYnlwYXNzU2VjdXJpdHlUcnVzdFJlc291cmNlVXJsKHJlc3BvbnNlLmF1dGhvcml6YXRpb25VcmwpO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50U3RhdGUubmV4dChPcGVuQmFua2luZ1N0YXRlLkNvbnNlbnQpO1xuICAgICAgICAgICAgLy8gU2V0IGEgZmxhZyB0byBkZXRlY3QgaWYgaWZyYW1lIGZhaWxzXG4gICAgICAgICAgICB0aGlzLmNoZWNrSWZyYW1lTG9hZChyZXNwb25zZS5hdXRob3JpemF0aW9uVXJsKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gT3BlbiBpbiBuZXcgd2luZG93L3RhYlxuICAgICAgICAgICAgdGhpcy5vcGVuQ29uc2VudEluTmV3V2luZG93KHJlc3BvbnNlLmF1dGhvcml6YXRpb25VcmwpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0TG9hZGluZ1N0YXRlKGZhbHNlKTtcblxuICAgICAgICAvLyBTdGFydCBwb2xsaW5nIGZvciBjb25zZW50IHN0YXR1c1xuICAgICAgICB0aGlzLnN0YXJ0Q29uc2VudFBvbGxpbmcoKTtcbiAgICAgIH0sXG4gICAgICBlcnJvcjogKGVycm9yKSA9PiB7XG4gICAgICAgIHRoaXMuaGFuZGxlRXJyb3IoZXJyb3IpO1xuICAgICAgICB0aGlzLnNldExvYWRpbmdTdGF0ZShmYWxzZSk7XG4gICAgICB9LFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBzaG91bGRVc2VJZnJhbWUoKTogYm9vbGVhbiB7XG4gICAgLy8gTW9zdCBiYW5rcyBkb24ndCBhbGxvdyBpZnJhbWVzIGR1ZSB0byBYLUZyYW1lLU9wdGlvbnNcbiAgICAvLyBTbyBkZWZhdWx0IHRvIGZhbHNlICh1c2UgcG9wdXAgd2luZG93IGluc3RlYWQpXG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgcHJpdmF0ZSBvcGVuQ29uc2VudEluTmV3V2luZG93KGF1dGhvcml6YXRpb25Vcmw6IHN0cmluZyk6IHZvaWQge1xuICAgIGNvbnN0IGlzTW9iaWxlID0gL0FuZHJvaWR8d2ViT1N8aVBob25lfGlQYWR8aVBvZHxCbGFja0JlcnJ5fElFTW9iaWxlfE9wZXJhIE1pbmkvaS50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpO1xuXG4gICAgbGV0IGNvbnNlbnRXaW5kb3c6IFdpbmRvdyB8IG51bGw7XG5cbiAgICBpZiAoaXNNb2JpbGUpIHtcbiAgICAgIC8vIE9uIG1vYmlsZSwgb3BlbiBpbiBzYW1lIHRhYiAoZnVsbCByZWRpcmVjdCkgb3IgbmV3IHRhYlxuICAgICAgLy8gVXNpbmcgX2JsYW5rIHdpbGwgb3BlbiBhIG5ldyB0YWIgYW5kIGFsbG93IHVzZXIgdG8gcmV0dXJuXG4gICAgICBjb25zZW50V2luZG93ID0gd2luZG93Lm9wZW4oYXV0aG9yaXphdGlvblVybCwgJ19ibGFuaycpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBPbiBkZXNrdG9wLCBvcGVuIGluIGEgcG9wdXAgd2luZG93XG4gICAgICBjb25zdCB3aWR0aCA9IDgwMDtcbiAgICAgIGNvbnN0IGhlaWdodCA9IDYwMDtcbiAgICAgIGNvbnN0IGxlZnQgPSAod2luZG93LnNjcmVlbi53aWR0aCAtIHdpZHRoKSAvIDI7XG4gICAgICBjb25zdCB0b3AgPSAod2luZG93LnNjcmVlbi5oZWlnaHQgLSBoZWlnaHQpIC8gMjtcblxuICAgICAgY29uc2VudFdpbmRvdyA9IHdpbmRvdy5vcGVuKFxuICAgICAgICBhdXRob3JpemF0aW9uVXJsLFxuICAgICAgICAnYmFua0NvbnNlbnQnLFxuICAgICAgICBgd2lkdGg9JHt3aWR0aH0saGVpZ2h0PSR7aGVpZ2h0fSxsZWZ0PSR7bGVmdH0sdG9wPSR7dG9wfSx0b29sYmFyPW5vLG1lbnViYXI9bm8sc2Nyb2xsYmFycz15ZXMscmVzaXphYmxlPXllc2BcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKGNvbnNlbnRXaW5kb3cpIHtcbiAgICAgIC8vIFNob3cgYSBtZXNzYWdlIHRoYXQgY29uc2VudCBpcyBpbiBwcm9ncmVzc1xuICAgICAgdGhpcy5jdXJyZW50U3RhdGUubmV4dChPcGVuQmFua2luZ1N0YXRlLkNvbnNlbnQpO1xuXG4gICAgICAvLyBDaGVjayBpZiB3aW5kb3cgaXMgY2xvc2VkIHBlcmlvZGljYWxseSAod29ya3MgYmV0dGVyIG9uIGRlc2t0b3ApXG4gICAgICBpZiAoIWlzTW9iaWxlKSB7XG4gICAgICAgIGNvbnN0IGNoZWNrV2luZG93Q2xvc2VkID0gc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICAgICAgICAgIGlmIChjb25zZW50V2luZG93ICYmIGNvbnNlbnRXaW5kb3cuY2xvc2VkKSB7XG4gICAgICAgICAgICBjbGVhckludGVydmFsKGNoZWNrV2luZG93Q2xvc2VkKTtcbiAgICAgICAgICAgIC8vIFdpbmRvdyB3YXMgY2xvc2VkLCB0aGUgcG9sbGluZyB3aWxsIGRldGVjdCB0aGUgY29uc2VudCBzdGF0dXNcbiAgICAgICAgICB9XG4gICAgICAgIH0sIDEwMDApO1xuICAgICAgfVxuICAgICAgLy8gT24gbW9iaWxlLCB3ZSByZWx5IGVudGlyZWx5IG9uIHBvbGxpbmcgc2luY2Ugd2luZG93LmNsb3NlZCBkb2Vzbid0IHdvcmsgcmVsaWFibHlcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gUG9wdXAgd2FzIGJsb2NrZWRcbiAgICAgIHRoaXMuX2lzQ29uc2VudEVycm9yID0gZmFsc2U7XG4gICAgICB0aGlzLl9lcnJvck1lc3NhZ2UgPSAnUGxlYXNlIGFsbG93IHBvcHVwcyBmb3IgdGhpcyBzaXRlIHRvIGNvbXBsZXRlIGJhbmsgYXV0aG9yaXphdGlvbi4gVGhlbiBjbGljayBSZXRyeSB0byB0cnkgYWdhaW4uJztcbiAgICAgIHRoaXMuY3VycmVudFN0YXRlLm5leHQoT3BlbkJhbmtpbmdTdGF0ZS5FcnJvcik7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjaGVja0lmcmFtZUxvYWQoYXV0aG9yaXphdGlvblVybDogc3RyaW5nKTogdm9pZCB7XG4gICAgLy8gSWYgaWZyYW1lIGZhaWxzIHRvIGxvYWQgKFgtRnJhbWUtT3B0aW9ucyksIGZhbGwgYmFjayB0byBwb3B1cFxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgLy8gQ2hlY2sgaWYgd2UncmUgc3RpbGwgaW4gY29uc2VudCBzdGF0ZSAoaWZyYW1lIG1pZ2h0IGhhdmUgZmFpbGVkKVxuICAgICAgaWYgKHRoaXMuY3VycmVudFN0YXRlLnZhbHVlID09PSBPcGVuQmFua2luZ1N0YXRlLkNvbnNlbnQgJiYgdGhpcy5hdXRob3JpemF0aW9uVXJsKSB7XG4gICAgICAgIC8vIENsZWFyIGlmcmFtZSBhbmQgb3BlbiBpbiBuZXcgd2luZG93XG4gICAgICAgIGNvbnNvbGUud2FybignSWZyYW1lIG1pZ2h0IGJlIGJsb2NrZWQsIG9wZW5pbmcgaW4gbmV3IHdpbmRvdycpO1xuICAgICAgICB0aGlzLmF1dGhvcml6YXRpb25VcmwgPSBudWxsO1xuICAgICAgICB0aGlzLm9wZW5Db25zZW50SW5OZXdXaW5kb3coYXV0aG9yaXphdGlvblVybCk7XG4gICAgICB9XG4gICAgfSwgMjAwMCk7XG4gIH1cblxuICBwcml2YXRlIHN0YXJ0Q29uc2VudFBvbGxpbmcoKTogdm9pZCB7XG4gICAgLy8gUG9sbCBldmVyeSA1IHNlY29uZHMgZm9yIGNvbnNlbnQgc3RhdHVzICh1c2VyIG5lZWRzIHRpbWUgdG8gY29tcGxldGUgYmFuayBhdXRob3JpemF0aW9uKVxuICAgIHRoaXMucG9sbFN1YnNjcmlwdGlvbiA9IGludGVydmFsKDEwMDAwKVxuICAgICAgLnBpcGUoXG4gICAgICAgIHN3aXRjaE1hcCgoKSA9PiB0aGlzLm9wZW5CYW5raW5nU2VydmljZS5nZXRDb25zZW50U3RhdHVzKHRoaXMuc2VsZWN0ZWRCYW5rIHx8ICdERUZBVUxUJywgdGhpcy5jb25zZW50SWQpKSxcbiAgICAgICAgdGFrZVdoaWxlKChzdGF0dXMpID0+IHN0YXR1cy5zdGF0dXMgPT09ICdyZWNlaXZlZCcsIHRydWUpLFxuICAgICAgICBmaW5hbGl6ZSgoKSA9PiB0aGlzLnBvbGxTdWJzY3JpcHRpb24/LnVuc3Vic2NyaWJlKCkpXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKHtcbiAgICAgICAgbmV4dDogKHN0YXR1czogQ29uc2VudFN0YXR1cykgPT4ge1xuICAgICAgICAgIGlmIChzdGF0dXMuc3RhdHVzID09PSAndmFsaWQnKSB7XG4gICAgICAgICAgICB0aGlzLm9uQ29uc2VudEFwcHJvdmVkKCk7XG4gICAgICAgICAgfSBlbHNlIGlmIChzdGF0dXMuc3RhdHVzID09PSAncmVqZWN0ZWQnIHx8XG4gICAgICAgICAgICAgICAgICAgICBzdGF0dXMuc3RhdHVzID09PSAnZXhwaXJlZCcgfHxcbiAgICAgICAgICAgICAgICAgICAgIHN0YXR1cy5zdGF0dXMgPT09ICd0ZXJtaW5hdGVkJyB8fFxuICAgICAgICAgICAgICAgICAgICAgc3RhdHVzLnN0YXR1cyA9PT0gJ3Jldm9rZWRCeVBzdScpIHtcbiAgICAgICAgICAgIHRoaXMub25Db25zZW50UmVqZWN0ZWQoc3RhdHVzKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGVycm9yOiAoZXJyb3IpID0+IHtcbiAgICAgICAgICB0aGlzLmhhbmRsZUVycm9yKGVycm9yKTtcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBvbkNvbnNlbnRBcHByb3ZlZCgpOiB2b2lkIHtcbiAgICB0aGlzLmN1cnJlbnRTdGF0ZS5uZXh0KE9wZW5CYW5raW5nU3RhdGUuUHJvY2Vzc2luZyk7XG4gICAgdGhpcy5mZXRjaEFjY291bnREYXRhKCk7XG4gIH1cblxuICBwcml2YXRlIG9uQ29uc2VudFJlamVjdGVkKHN0YXR1czogQ29uc2VudFN0YXR1cyk6IHZvaWQge1xuICAgIHRoaXMuX2lzQ29uc2VudEVycm9yID0gdHJ1ZTtcbiAgICB0aGlzLl9jb25zZW50RXJyb3JTdGF0dXMgPSBzdGF0dXMuc3RhdHVzO1xuICAgIHRoaXMuX2Vycm9yTWVzc2FnZSA9ICcnOyAvLyBDbGVhciB0byB1c2UgdHJhbnNsYXRlZCBtZXNzYWdlXG4gICAgdGhpcy5jdXJyZW50U3RhdGUubmV4dChPcGVuQmFua2luZ1N0YXRlLkVycm9yKTtcbiAgfVxuXG4gIHByaXZhdGUgZmV0Y2hBY2NvdW50RGF0YSgpOiB2b2lkIHtcbiAgICB0aGlzLnNldExvYWRpbmdTdGF0ZSh0cnVlKTtcblxuICAgIC8vIEZpcnN0LCBmZXRjaCBhY2NvdW50c1xuICAgIHRoaXMub3BlbkJhbmtpbmdTZXJ2aWNlLmdldEFjY291bnRzKHRoaXMuY29uc2VudElkLCB0aGlzLnNlbGVjdGVkQmFuayB8fCAnREVGQVVMVCcpLnN1YnNjcmliZSh7XG4gICAgICBuZXh0OiAoYWNjb3VudHMpID0+IHtcbiAgICAgICAgdGhpcy5hY2NvdW50cyA9IGFjY291bnRzO1xuXG4gICAgICAgIC8vIFNlbGVjdCBhbGwgYWNjb3VudHMgZm9yIHRyYW5zYWN0aW9uIGZldGNoaW5nXG4gICAgICAgIHRoaXMuc2VsZWN0ZWRBY2NvdW50cyA9IGFjY291bnRzLm1hcChhID0+IGEuYWNjb3VudElkKTtcblxuICAgICAgICAvLyBGZXRjaCB0cmFuc2FjdGlvbnMgZm9yIGVhY2ggYWNjb3VudFxuICAgICAgICB0aGlzLmZldGNoVHJhbnNhY3Rpb25zRm9yQWNjb3VudHMoKTtcbiAgICAgIH0sXG4gICAgICBlcnJvcjogKGVycm9yKSA9PiB7XG4gICAgICAgIHRoaXMuaGFuZGxlRXJyb3IoZXJyb3IpO1xuICAgICAgICB0aGlzLnNldExvYWRpbmdTdGF0ZShmYWxzZSk7XG4gICAgICB9LFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBmZXRjaFRyYW5zYWN0aW9uc0ZvckFjY291bnRzKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnNlbGVjdGVkQWNjb3VudHMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aGlzLmNvbXBsZXRlUHJvY2VzcygpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHRyYW5zYWN0aW9uUmVxdWVzdHMgPSB0aGlzLnNlbGVjdGVkQWNjb3VudHMubWFwKGFjY291bnRJZCA9PiB7XG4gICAgICAvLyBDYWxjdWxhdGUgZGF0ZSByYW5nZSBiYXNlZCBvbiBiYW5rLXNwZWNpZmljIGxpbWl0c1xuICAgICAgY29uc3QgYmFua0NvZGUgPSB0aGlzLnNlbGVjdGVkQmFuayB8fCAnREVGQVVMVCc7XG4gICAgICBjb25zdCBtYXhEYXlzID0gdGhpcy5vcGVuQmFua2luZ1NlcnZpY2UuZ2V0TWF4VHJhbnNhY3Rpb25QZXJpb2QoYmFua0NvZGUpO1xuXG4gICAgICBjb25zdCB0b0RhdGUgPSBuZXcgRGF0ZSgpO1xuICAgICAgY29uc3QgZnJvbURhdGUgPSBuZXcgRGF0ZSgpO1xuXG4gICAgICAvLyBJZiB1bmxpbWl0ZWQgKC0xKSBvciB2ZXJ5IGxvbmcgcGVyaW9kLCB1c2UgMzY1IGRheXMgYXMgcHJhY3RpY2FsIGxpbWl0XG4gICAgICAvLyBPdGhlcndpc2UgdXNlIHRoZSBiYW5rJ3Mgc3BlY2lmaWMgbGltaXRcbiAgICAgIGNvbnN0IGRheXNUb0ZldGNoID0gbWF4RGF5cyA9PT0gLTEgPyAzNjUgOiBNYXRoLm1pbihtYXhEYXlzLCAzNjUpO1xuICAgICAgZnJvbURhdGUuc2V0RGF0ZShmcm9tRGF0ZS5nZXREYXRlKCkgLSBkYXlzVG9GZXRjaCk7XG5cbiAgICAgIHJldHVybiB0aGlzLm9wZW5CYW5raW5nU2VydmljZS5nZXRUcmFuc2FjdGlvbnMoe1xuICAgICAgICBjb25zZW50SWQ6IHRoaXMuY29uc2VudElkLFxuICAgICAgICBiYW5rQ29kZTogYmFua0NvZGUsXG4gICAgICAgIGFjY291bnRJZDogYWNjb3VudElkLFxuICAgICAgICBmcm9tRGF0ZTogZnJvbURhdGUudG9JU09TdHJpbmcoKSxcbiAgICAgICAgdG9EYXRlOiB0b0RhdGUudG9JU09TdHJpbmcoKSxcbiAgICAgICAgcGFnZTogMSxcbiAgICAgICAgcGFnZVNpemU6IDUwXG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIC8vIEV4ZWN1dGUgYWxsIHRyYW5zYWN0aW9uIHJlcXVlc3RzXG4gICAgUHJvbWlzZS5hbGwodHJhbnNhY3Rpb25SZXF1ZXN0cy5tYXAocmVxID0+IHJlcS50b1Byb21pc2UoKSkpXG4gICAgICAudGhlbihyZXN1bHRzID0+IHtcbiAgICAgICAgLy8gU3RvcmUgdHJhbnNhY3Rpb24gcGFnZXNcbiAgICAgICAgcmVzdWx0cy5mb3JFYWNoKChwYWdlLCBpbmRleCkgPT4ge1xuICAgICAgICAgIGlmIChwYWdlKSB7XG4gICAgICAgICAgICB0aGlzLnRyYW5zYWN0aW9uUGFnZXMuc2V0KHRoaXMuc2VsZWN0ZWRBY2NvdW50c1tpbmRleF0sIHBhZ2UpO1xuICAgICAgICAgICAgLy8gRmxhdHRlbiBhbGwgdHJhbnNhY3Rpb25zIGludG8gc2luZ2xlIGFycmF5XG4gICAgICAgICAgICB0aGlzLnRyYW5zYWN0aW9ucy5wdXNoKC4uLnBhZ2UuaXRlbXMpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5jb21wbGV0ZVByb2Nlc3MoKTtcbiAgICAgIH0pXG4gICAgICAuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBmZXRjaGluZyB0cmFuc2FjdGlvbnM6JywgZXJyb3IpO1xuICAgICAgICAvLyBFdmVuIGlmIHRyYW5zYWN0aW9ucyBmYWlsLCB3ZSBjYW4gY29udGludWUgd2l0aCBhY2NvdW50c1xuICAgICAgICB0aGlzLmNvbXBsZXRlUHJvY2VzcygpO1xuICAgICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGNvbXBsZXRlUHJvY2VzcygpOiB2b2lkIHtcbiAgICAvLyBTdG9yZSBkYXRhIGluIGZvcm0gbW9kZWxcbiAgICB0aGlzLnN0b3JlQWNjb3VudERhdGEoKTtcblxuICAgIHRoaXMuY3VycmVudFN0YXRlLm5leHQoT3BlbkJhbmtpbmdTdGF0ZS5Db21wbGV0ZSk7XG4gICAgdGhpcy5zZXRMb2FkaW5nU3RhdGUoZmFsc2UpO1xuXG4gICAgLy8gQXV0by1wcm9jZWVkIHRvIG5leHQgc3RlcCBhZnRlciBhIHNob3J0IGRlbGF5XG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLm9uRXZlbnQoJ3N1Y2Nlc3MnKTtcbiAgICB9LCAyMDAwKTtcbiAgfVxuXG4gIHByaXZhdGUgc3RvcmVBY2NvdW50RGF0YSgpOiB2b2lkIHtcbiAgICAvLyBTdG9yZSB0aGUgZmV0Y2hlZCBkYXRhIGluIHRoZSBmb3JtIG1vZGVsIGZvciB1c2UgaW4gbGF0ZXIgc3RlcHNcbiAgICBjb25zdCBncm91cCA9IHRoaXMuZm9ybSBhcyBGb3JtR3JvdXA7XG5cbiAgICAvLyBBZGQgYWNjb3VudHMgYW5kIHRyYW5zYWN0aW9ucyB0byBmb3JtXG4gICAgZ3JvdXAuYWRkQ29udHJvbCgnb3BlbkJhbmtpbmdBY2NvdW50cycsIG5ldyBGb3JtQ29udHJvbCh0aGlzLmFjY291bnRzKSk7XG4gICAgZ3JvdXAuYWRkQ29udHJvbCgnb3BlbkJhbmtpbmdUcmFuc2FjdGlvbnMnLCBuZXcgRm9ybUNvbnRyb2wodGhpcy50cmFuc2FjdGlvbnMpKTtcbiAgICBncm91cC5hZGRDb250cm9sKCdvcGVuQmFua2luZ0NvbnNlbnRJZCcsIG5ldyBGb3JtQ29udHJvbCh0aGlzLmNvbnNlbnRJZCkpO1xuICAgIGdyb3VwLmFkZENvbnRyb2woJ29wZW5CYW5raW5nQmFua0NvZGUnLCBuZXcgRm9ybUNvbnRyb2wodGhpcy5zZWxlY3RlZEJhbmspKTtcblxuICAgIC8vIFN0b3JlIGFjY291bnQgc3VtbWFyeVxuICAgIGNvbnN0IGFjY291bnRTdW1tYXJ5ID0ge1xuICAgICAgdG90YWxBY2NvdW50czogdGhpcy5hY2NvdW50cy5sZW5ndGgsXG4gICAgICB0b3RhbEJhbGFuY2U6IHRoaXMuYWNjb3VudHMucmVkdWNlKChzdW0sIGFjYykgPT4gc3VtICsgYWNjLmJhbGFuY2UsIDApLFxuICAgICAgY3VycmVuY2llczogWy4uLm5ldyBTZXQodGhpcy5hY2NvdW50cy5tYXAoYSA9PiBhLmN1cnJlbmN5KSldLFxuICAgICAgdHJhbnNhY3Rpb25Db3VudDogdGhpcy50cmFuc2FjdGlvbnMubGVuZ3RoLFxuICAgICAgb2xkZXN0VHJhbnNhY3Rpb246IHRoaXMudHJhbnNhY3Rpb25zLmxlbmd0aCA+IDBcbiAgICAgICAgPyB0aGlzLnRyYW5zYWN0aW9ucy5yZWR1Y2UoKG9sZGVzdCwgdCkgPT5cbiAgICAgICAgICAgIG5ldyBEYXRlKHQuYm9va2luZ0RhdGUgfHwgdC50cmFuc2FjdGlvbkRhdGUgfHwgJycpIDwgbmV3IERhdGUob2xkZXN0LmJvb2tpbmdEYXRlIHx8IG9sZGVzdC50cmFuc2FjdGlvbkRhdGUgfHwgJycpID8gdCA6IG9sZGVzdFxuICAgICAgICAgICkuYm9va2luZ0RhdGVcbiAgICAgICAgOiBudWxsLFxuICAgICAgbmV3ZXN0VHJhbnNhY3Rpb246IHRoaXMudHJhbnNhY3Rpb25zLmxlbmd0aCA+IDBcbiAgICAgICAgPyB0aGlzLnRyYW5zYWN0aW9ucy5yZWR1Y2UoKG5ld2VzdCwgdCkgPT5cbiAgICAgICAgICAgIG5ldyBEYXRlKHQuYm9va2luZ0RhdGUgfHwgdC50cmFuc2FjdGlvbkRhdGUgfHwgJycpID4gbmV3IERhdGUobmV3ZXN0LmJvb2tpbmdEYXRlIHx8IG5ld2VzdC50cmFuc2FjdGlvbkRhdGUgfHwgJycpID8gdCA6IG5ld2VzdFxuICAgICAgICAgICkuYm9va2luZ0RhdGVcbiAgICAgICAgOiBudWxsXG4gICAgfTtcblxuICAgIGdyb3VwLmFkZENvbnRyb2woJ29wZW5CYW5raW5nQWNjb3VudFN1bW1hcnknLCBuZXcgRm9ybUNvbnRyb2woYWNjb3VudFN1bW1hcnkpKTtcblxuICAgIC8vIFBvcHVsYXRlIHRoZSBzdGVwJ3MgY29udHJvbHMgZm9yIFNhdmVBcHBEYXRhXG4gICAgdGhpcy5wb3B1bGF0ZVN0ZXBDb250cm9scygpO1xuICB9XG5cbiAgcHJpdmF0ZSBwb3B1bGF0ZVN0ZXBDb250cm9scygpOiB2b2lkIHtcbiAgICAvLyBGaW5kIGFuZCBwb3B1bGF0ZSB0aGUgY29udHJvbHMgaW4gdGhlIHN0ZXAgc2VjdGlvbnNcbiAgICBpZiAoIXRoaXMuc3RlcERhdGE/LnNlY3Rpb25zKSByZXR1cm47XG5cbiAgICAvLyBHZXQgZW1haWwgZnJvbSBjb25maWcgbWFwcGluZyBvciB1c2UgZW1wdHkgc3RyaW5nXG4gICAgY29uc3QgZW1haWwgPSB0aGlzLmdldEZpZWxkVmFsdWUodGhpcy5jb25maWcuZW1haWxDb2xsZWN0ZWQpIHx8ICcnO1xuXG4gICAgLy8gR2V0IHRoZSBmaXJzdCBhY2NvdW50IGFzIHRoZSBwcmltYXJ5IGFjY291bnRcbiAgICBjb25zdCBwcmltYXJ5QWNjb3VudCA9IHRoaXMuYWNjb3VudHMubGVuZ3RoID4gMCA/IHRoaXMuYWNjb3VudHNbMF0gOiBudWxsO1xuXG4gICAgLy8gQ2FsY3VsYXRlIHRvdGFsIGJhbGFuY2VcbiAgICBjb25zdCB0b3RhbEJhbGFuY2UgPSB0aGlzLmFjY291bnRzLnJlZHVjZSgoc3VtLCBhY2MpID0+IHN1bSArIGFjYy5iYWxhbmNlLCAwKTtcblxuICAgIC8vIENhbGN1bGF0ZSB0cmFuc2FjdGlvbiBwZXJpb2QgaW4gbW9udGhzXG4gICAgY29uc3QgbW9udGhzID0gdGhpcy5nZXRUcmFuc2FjdGlvblBlcmlvZE1vbnRocygpO1xuXG4gICAgLy8gTWFwIG9mIGNvbnRyb2wgaWRlbnRpZmllcnMgdG8gdmFsdWVzXG4gICAgY29uc3QgY29udHJvbFZhbHVlczogeyBba2V5OiBzdHJpbmddOiBhbnkgfSA9IHtcbiAgICAgICdPcGVuQmFua2luZ0NvbnNlbnRTdGF0dXMnOiB0cnVlLCAvLyBDb25zZW50IHdhcyBzdWNjZXNzZnVsbHkgdmFsaWRhdGVkXG4gICAgICAnT3BlbkJhbmtpbmdFbWFpbCc6IGVtYWlsLFxuICAgICAgJ09wZW5CYW5raW5nQWNjb3VudE51bWJlcic6IHByaW1hcnlBY2NvdW50Py5pYmFuIHx8ICcnLFxuICAgICAgJ09wZW5CYW5raW5nQWNjb3VudEhvbGRlcic6IHByaW1hcnlBY2NvdW50Py5hY2NvdW50SG9sZGVyTmFtZSB8fCAnJyxcbiAgICAgICdPcGVuQmFua2luZ0JhbmtDb2RlJzogdGhpcy5zZWxlY3RlZEJhbmsgfHwgJycsXG4gICAgICAnT3BlbkJhbmtpbmdDb25zZW50SWQnOiB0aGlzLmNvbnNlbnRJZCxcbiAgICAgICdPcGVuQmFua2luZ0FjY291bnRzQ291bnQnOiB0aGlzLmFjY291bnRzLmxlbmd0aCxcbiAgICAgICdPcGVuQmFua2luZ0FjY291bnRzRGF0YSc6IEpTT04uc3RyaW5naWZ5KHRoaXMuYWNjb3VudHMpLFxuICAgICAgJ09wZW5CYW5raW5nVG90YWxCYWxhbmNlJzogdG90YWxCYWxhbmNlLFxuICAgICAgJ09wZW5CYW5raW5nVHJhbnNhY3Rpb25zQ291bnQnOiB0aGlzLnRyYW5zYWN0aW9ucy5sZW5ndGgsXG4gICAgICAnT3BlbkJhbmtpbmdUcmFuc2FjdGlvbnNEYXRhJzogSlNPTi5zdHJpbmdpZnkodGhpcy50cmFuc2FjdGlvbnMpLFxuICAgICAgJ09wZW5CYW5raW5nVHJhbnNhY3Rpb25zUGVyaW9kJzogbW9udGhzXG4gICAgfTtcblxuICAgIC8vIEFkZCBhbGwgY29udHJvbCB2YWx1ZXMgdG8gdGhlIGZvcm1cbiAgICBjb25zdCBncm91cCA9IHRoaXMuZm9ybSBhcyBGb3JtR3JvdXA7XG4gICAgT2JqZWN0LmtleXMoY29udHJvbFZhbHVlcykuZm9yRWFjaChjb250cm9sSWQgPT4ge1xuICAgICAgaWYgKCFncm91cC5jb250YWlucyhjb250cm9sSWQpKSB7XG4gICAgICAgIGdyb3VwLmFkZENvbnRyb2woY29udHJvbElkLCBuZXcgRm9ybUNvbnRyb2woY29udHJvbFZhbHVlc1tjb250cm9sSWRdKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBncm91cC5nZXQoY29udHJvbElkKT8uc2V0VmFsdWUoY29udHJvbFZhbHVlc1tjb250cm9sSWRdKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vIFRoZSB2YWx1ZXMgYXJlIG5vdyBzdG9yZWQgaW4gdGhlIGZvcm0gbW9kZWwgYW5kIHdpbGwgYmUgc2F2ZWQgd2l0aCBTYXZlQXBwRGF0YVxuICAgIC8vIFdoZW4gdGhlIGZvcm0gaXMgc3VibWl0dGVkLCB0aGVzZSB2YWx1ZXMgd2lsbCBiZSBhc3NvY2lhdGVkIHdpdGggdGhlIHN0ZXAncyBjb250cm9sc1xuICB9XG5cbiAgcmV0cnkoKTogdm9pZCB7XG4gICAgdGhpcy5fZXJyb3JNZXNzYWdlID0gJyc7XG4gICAgdGhpcy5faXNDb25zZW50RXJyb3IgPSBmYWxzZTtcbiAgICB0aGlzLl9jb25zZW50RXJyb3JTdGF0dXMgPSAnJztcbiAgICB0aGlzLmFjY291bnRzID0gW107XG4gICAgdGhpcy50cmFuc2FjdGlvbnMgPSBbXTtcbiAgICB0aGlzLnNlbGVjdGVkQWNjb3VudHMgPSBbXTtcbiAgICB0aGlzLnRyYW5zYWN0aW9uUGFnZXMuY2xlYXIoKTtcbiAgICB0aGlzLmNvbnNlbnRJZCA9ICcnO1xuICAgIHRoaXMuc2VsZWN0ZWRCYW5rID0gJyc7XG4gICAgdGhpcy5zZWxlY3RlZEJhbmtPYmplY3QgPSB1bmRlZmluZWQ7XG4gICAgdGhpcy5iYW5rcyA9IFtdO1xuICAgIHRoaXMuYXV0aG9yaXphdGlvblVybCA9IG51bGw7XG5cbiAgICAvLyBSZXNldCB0byBpbml0aWFsIHN0YXRlIC0gdXNlciBuZWVkcyB0byBjbGljayBOZXh0IGFnYWluXG4gICAgdGhpcy5jdXJyZW50U3RhdGUubmV4dChPcGVuQmFua2luZ1N0YXRlLkluaXRpYWwpO1xuICB9XG5cbiAgcHJpdmF0ZSBoYW5kbGVFcnJvcihlcnJvcjogSHR0cEVycm9yUmVzcG9uc2UpOiB2b2lkIHtcbiAgICBjb25zb2xlLmVycm9yKCdPcGVuQmFua2luZyBlcnJvcjonLCBlcnJvcik7XG4gICAgdGhpcy5faXNDb25zZW50RXJyb3IgPSBmYWxzZTtcbiAgICB0aGlzLl9jb25zZW50RXJyb3JTdGF0dXMgPSAnJztcbiAgICB0aGlzLl9lcnJvck1lc3NhZ2UgPSBlcnJvci5lcnJvcj8ubWVzc2FnZSB8fCBlcnJvci5tZXNzYWdlIHx8ICdBbiBlcnJvciBvY2N1cnJlZC4gUGxlYXNlIHRyeSBhZ2Fpbi4nO1xuICAgIHRoaXMuY3VycmVudFN0YXRlLm5leHQoT3BlbkJhbmtpbmdTdGF0ZS5FcnJvcik7XG4gIH1cblxuICBwcml2YXRlIGdldFRyYW5zbGF0ZWRNZXNzYWdlKHRyYW5zbGF0aW9uczogYW55W10gfCB1bmRlZmluZWQsIGRlZmF1bHRNZXNzYWdlOiBzdHJpbmcgPSAnJyk6IHN0cmluZyB7XG4gICAgaWYgKCF0cmFuc2xhdGlvbnMgfHwgdHJhbnNsYXRpb25zLmxlbmd0aCA9PT0gMCkgcmV0dXJuIGRlZmF1bHRNZXNzYWdlO1xuXG4gICAgY29uc3QgbGFuZ0lzbyA9IHRoaXMucHJvcHM/LlsnbGFuZ0lzbyddIHx8IHRoaXMubGFuZ0lzbyB8fCAnZW4nO1xuICAgIGNvbnN0IHRyYW5zbGF0aW9uID0gdHJhbnNsYXRpb25zLmZpbmQodCA9PiB0Lmxhbmd1YWdlSXNvID09PSBsYW5nSXNvKTtcbiAgICByZXR1cm4gdHJhbnNsYXRpb24/LnZhbHVlIHx8IHRyYW5zbGF0aW9uc1swXT8udmFsdWUgfHwgZGVmYXVsdE1lc3NhZ2U7XG4gIH1cblxuICBnZXQgaW5pdGlhbE1lc3NhZ2UoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5nZXRUcmFuc2xhdGVkTWVzc2FnZShcbiAgICAgIHRoaXMuY29uZmlnLmluaXRpYWxNZXNzYWdlVHJhbnNsYXRpb25zLFxuICAgICAgJ1RvIGNvbnRpbnVlLCB3ZSBuZWVkIHRvIHZlcmlmeSB5b3VyIGJhbmsgYWNjb3VudCBpbmZvcm1hdGlvbi4gQ2xpY2sgTmV4dCB0byBwcm9jZWVkLidcbiAgICApO1xuICB9XG5cbiAgZ2V0IHdhaXRpbmdNZXNzYWdlKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0VHJhbnNsYXRlZE1lc3NhZ2UoXG4gICAgICB0aGlzLmNvbmZpZy53YWl0aW5nTWVzc2FnZVRyYW5zbGF0aW9ucyxcbiAgICAgICdQbGVhc2Ugd2FpdCB3aGlsZSB3ZSByZXRyaWV2ZSB5b3VyIGFjY291bnQgaW5mb3JtYXRpb24uLi4nXG4gICAgKTtcbiAgfVxuXG4gIGdldCBjb21wbGV0aW9uTWVzc2FnZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmdldFRyYW5zbGF0ZWRNZXNzYWdlKFxuICAgICAgdGhpcy5jb25maWcuY29tcGxldGlvbk1lc3NhZ2VUcmFuc2xhdGlvbnMsXG4gICAgICAnQWNjb3VudCBpbmZvcm1hdGlvbiBzdWNjZXNzZnVsbHkgcmV0cmlldmVkLidcbiAgICApO1xuICB9XG5cbiAgZ2V0IHJldHJ5QnV0dG9uTGFiZWwoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5nZXRUcmFuc2xhdGVkTWVzc2FnZShcbiAgICAgIHRoaXMuY29uZmlnLnJldHJ5QnV0dG9uTGFiZWxUcmFuc2xhdGlvbnMsXG4gICAgICAnUmV0cnknXG4gICAgKTtcbiAgfVxuXG4gIGdldCBlcnJvck1lc3NhZ2UoKTogc3RyaW5nIHtcbiAgICAvLyBJZiBpdCdzIGEgY29uc2VudCBlcnJvciwgdXNlIHRoZSB0cmFuc2xhdGVkIGNvbnNlbnQgZXJyb3IgbWVzc2FnZVxuICAgIGlmICh0aGlzLl9pc0NvbnNlbnRFcnJvcikge1xuICAgICAgY29uc3QgbWVzc2FnZSA9IHRoaXMuZ2V0VHJhbnNsYXRlZE1lc3NhZ2UoXG4gICAgICAgIHRoaXMuY29uZmlnLmNvbnNlbnRFcnJvck1lc3NhZ2VUcmFuc2xhdGlvbnMsXG4gICAgICAgICdZb3UgbXVzdCBwcm92aWRlIGNvbnNlbnQgdG8gY29udGludWUuIFBsZWFzZSB0cnkgYWdhaW4uJ1xuICAgICAgKTtcbiAgICAgIHJldHVybiB0aGlzLl9jb25zZW50RXJyb3JTdGF0dXMgPyBgJHttZXNzYWdlfSAoU3RhdHVzOiAke3RoaXMuX2NvbnNlbnRFcnJvclN0YXR1c30pYCA6IG1lc3NhZ2U7XG4gICAgfVxuICAgIC8vIE90aGVyd2lzZSByZXR1cm4gdGhlIHN0b3JlZCBlcnJvciBtZXNzYWdlIChmcm9tIEFQSSBvciBkZWZhdWx0KVxuICAgIHJldHVybiB0aGlzLl9lcnJvck1lc3NhZ2UgfHwgJ0FuIGVycm9yIG9jY3VycmVkLiBQbGVhc2UgdHJ5IGFnYWluLic7XG4gIH1cblxuICAvLyBCdXR0b24gdHJhbnNsYXRpb25zXG4gIGdldCBuZXh0QnV0dG9uTGFiZWwoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5nZXRUcmFuc2xhdGVkTWVzc2FnZShcbiAgICAgIHRoaXMuY29uZmlnLm5leHRCdXR0b25UcmFuc2xhdGlvbnMsXG4gICAgICAnTmV4dCdcbiAgICApO1xuICB9XG5cbiAgZ2V0IGNvbnRpbnVlQnV0dG9uTGFiZWwoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5nZXRUcmFuc2xhdGVkTWVzc2FnZShcbiAgICAgIHRoaXMuY29uZmlnLmNvbnRpbnVlQnV0dG9uVHJhbnNsYXRpb25zLFxuICAgICAgJ0NvbnRpbnVlJ1xuICAgICk7XG4gIH1cblxuICAvLyBVSSBsYWJlbCB0cmFuc2xhdGlvbnNcbiAgZ2V0IHNlbGVjdEJhbmtUaXRsZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmdldFRyYW5zbGF0ZWRNZXNzYWdlKFxuICAgICAgdGhpcy5jb25maWcuc2VsZWN0QmFua1RyYW5zbGF0aW9ucyxcbiAgICAgICdTZWxlY3QgeW91ciBiYW5rJ1xuICAgICk7XG4gIH1cblxuICBnZXQgY29uc2VudFRpdGxlKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0VHJhbnNsYXRlZE1lc3NhZ2UoXG4gICAgICB0aGlzLmNvbmZpZy5jb25zZW50VGl0bGVUcmFuc2xhdGlvbnMsXG4gICAgICAnQmFuayBBdXRob3JpemF0aW9uJ1xuICAgICk7XG4gIH1cblxuICBnZXQgY29uc2VudERlc2NyaXB0aW9uKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0VHJhbnNsYXRlZE1lc3NhZ2UoXG4gICAgICB0aGlzLmNvbmZpZy5jb25zZW50RGVzY3JpcHRpb25UcmFuc2xhdGlvbnMsXG4gICAgICAnUGxlYXNlIGNvbXBsZXRlIHRoZSBhdXRob3JpemF0aW9uIHByb2Nlc3Mgd2l0aCB5b3VyIGJhbmsnXG4gICAgKTtcbiAgfVxuXG4gIGdldCB3YWl0aW5nRm9yQXV0aG9yaXphdGlvblRleHQoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5nZXRUcmFuc2xhdGVkTWVzc2FnZShcbiAgICAgIHRoaXMuY29uZmlnLndhaXRpbmdGb3JBdXRob3JpemF0aW9uVHJhbnNsYXRpb25zLFxuICAgICAgJ1dhaXRpbmcgZm9yIGF1dGhvcml6YXRpb24uLi4nXG4gICAgKTtcbiAgfVxuXG4gIGdldCBwb3B1cFdpbmRvd01lc3NhZ2UoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5nZXRUcmFuc2xhdGVkTWVzc2FnZShcbiAgICAgIHRoaXMuY29uZmlnLnBvcHVwV2luZG93TWVzc2FnZVRyYW5zbGF0aW9ucyxcbiAgICAgICdBIG5ldyB3aW5kb3cgaGFzIG9wZW5lZCBmb3IgYmFuayBhdXRob3JpemF0aW9uLiBQbGVhc2UgY29tcGxldGUgdGhlIHByb2Nlc3MgdGhlcmUuJ1xuICAgICk7XG4gIH1cblxuICBnZXQgcG9wdXBCbG9ja2VyTWVzc2FnZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmdldFRyYW5zbGF0ZWRNZXNzYWdlKFxuICAgICAgdGhpcy5jb25maWcucG9wdXBCbG9ja2VyTWVzc2FnZVRyYW5zbGF0aW9ucyxcbiAgICAgICdJZiB0aGUgd2luZG93IGRpZG5cXCd0IG9wZW4sIHBsZWFzZSBjaGVjayB5b3VyIHBvcHVwIGJsb2NrZXIgc2V0dGluZ3MuJ1xuICAgICk7XG4gIH1cblxuICBnZXQgYWNjb3VudHNSZXRyaWV2ZWRMYWJlbCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmdldFRyYW5zbGF0ZWRNZXNzYWdlKFxuICAgICAgdGhpcy5jb25maWcuYWNjb3VudHNSZXRyaWV2ZWRUcmFuc2xhdGlvbnMsXG4gICAgICAnQWNjb3VudHMgcmV0cmlldmVkJ1xuICAgICk7XG4gIH1cblxuICBnZXQgdHJhbnNhY3Rpb25zUmV0cmlldmVkTGFiZWwoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5nZXRUcmFuc2xhdGVkTWVzc2FnZShcbiAgICAgIHRoaXMuY29uZmlnLnRyYW5zYWN0aW9uc1JldHJpZXZlZFRyYW5zbGF0aW9ucyxcbiAgICAgICdUcmFuc2FjdGlvbnMgcmV0cmlldmVkJ1xuICAgICk7XG4gIH1cblxuICBnZXQgYWNjb3VudHNTdW1tYXJ5VGV4dCgpOiBzdHJpbmcge1xuICAgIGNvbnN0IGNvdW50ID0gdGhpcy5hY2NvdW50cy5sZW5ndGg7XG4gICAgY29uc3QgdGVtcGxhdGUgPSB0aGlzLmdldFRyYW5zbGF0ZWRNZXNzYWdlKFxuICAgICAgdGhpcy5jb25maWcuYWNjb3VudHNGb3VuZFRyYW5zbGF0aW9ucyxcbiAgICAgICd7MH0gYWNjb3VudChzKSBmb3VuZCdcbiAgICApO1xuICAgIHJldHVybiB0ZW1wbGF0ZS5yZXBsYWNlKCd7MH0nLCBjb3VudC50b1N0cmluZygpKTtcbiAgfVxuXG4gIGdldCB0cmFuc2FjdGlvbnNTdW1tYXJ5VGV4dCgpOiBzdHJpbmcge1xuICAgIGNvbnN0IGNvdW50ID0gdGhpcy50cmFuc2FjdGlvbnMubGVuZ3RoO1xuICAgIGNvbnN0IG1vbnRocyA9IHRoaXMuZ2V0VHJhbnNhY3Rpb25QZXJpb2RNb250aHMoKTtcbiAgICBjb25zdCB0ZW1wbGF0ZSA9IHRoaXMuZ2V0VHJhbnNsYXRlZE1lc3NhZ2UoXG4gICAgICB0aGlzLmNvbmZpZy50cmFuc2FjdGlvbnNTdW1tYXJ5VHJhbnNsYXRpb25zLFxuICAgICAgJ3swfSB0cmFuc2FjdGlvbihzKSByZXRyaWV2ZWQgZm9yIHRoZSBsYXN0IHsxfSBtb250aChzKSdcbiAgICApO1xuICAgIHJldHVybiB0ZW1wbGF0ZS5yZXBsYWNlKCd7MH0nLCBjb3VudC50b1N0cmluZygpKS5yZXBsYWNlKCd7MX0nLCBtb250aHMudG9TdHJpbmcoKSk7XG4gIH1cblxuICBwcml2YXRlIGdldFRyYW5zYWN0aW9uUGVyaW9kTW9udGhzKCk6IG51bWJlciB7XG4gICAgaWYgKCF0aGlzLnNlbGVjdGVkQmFuaykgcmV0dXJuIDM7XG5cbiAgICBjb25zdCBtYXhEYXlzID0gdGhpcy5vcGVuQmFua2luZ1NlcnZpY2UuZ2V0TWF4VHJhbnNhY3Rpb25QZXJpb2QodGhpcy5zZWxlY3RlZEJhbmspO1xuICAgIGNvbnN0IGRheXNUb0ZldGNoID0gbWF4RGF5cyA9PT0gLTEgPyAzNjUgOiBNYXRoLm1pbihtYXhEYXlzLCAzNjUpO1xuICAgIHJldHVybiBNYXRoLnJvdW5kKGRheXNUb0ZldGNoIC8gMzApO1xuICB9XG5cbiAgZ2V0IGlzSW5pdGlhbFN0YXRlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmN1cnJlbnRTdGF0ZS52YWx1ZSA9PT0gT3BlbkJhbmtpbmdTdGF0ZS5Jbml0aWFsO1xuICB9XG5cbiAgZ2V0IGlzQmFua1NlbGVjdGlvblN0YXRlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmN1cnJlbnRTdGF0ZS52YWx1ZSA9PT0gT3BlbkJhbmtpbmdTdGF0ZS5CYW5rU2VsZWN0aW9uO1xuICB9XG5cbiAgZ2V0IGlzQ29uc2VudFN0YXRlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmN1cnJlbnRTdGF0ZS52YWx1ZSA9PT0gT3BlbkJhbmtpbmdTdGF0ZS5Db25zZW50O1xuICB9XG5cbiAgZ2V0IGlzUHJvY2Vzc2luZ1N0YXRlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmN1cnJlbnRTdGF0ZS52YWx1ZSA9PT0gT3BlbkJhbmtpbmdTdGF0ZS5Qcm9jZXNzaW5nO1xuICB9XG5cbiAgZ2V0IGlzRXJyb3JTdGF0ZSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5jdXJyZW50U3RhdGUudmFsdWUgPT09IE9wZW5CYW5raW5nU3RhdGUuRXJyb3I7XG4gIH1cblxuICBnZXQgaXNDb21wbGV0ZVN0YXRlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmN1cnJlbnRTdGF0ZS52YWx1ZSA9PT0gT3BlbkJhbmtpbmdTdGF0ZS5Db21wbGV0ZTtcbiAgfVxuXG4gIHByaXZhdGUgc2V0TG9hZGluZ1N0YXRlKGxvYWRpbmc6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLmlzTG9hZGluZyA9IGxvYWRpbmc7XG4gICAgdGhpcy5pc0xvYWRpbmdTdWJqZWN0Lm5leHQobG9hZGluZyk7XG4gICAgdGhpcy5jZHIuZGV0ZWN0Q2hhbmdlcygpO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5wb2xsU3Vic2NyaXB0aW9uPy51bnN1YnNjcmliZSgpO1xuICAgIHRoaXMuaXNMb2FkaW5nU3ViamVjdC5jb21wbGV0ZSgpO1xuICB9XG59IiwiPGRpdiBjbGFzcz1cIm9wZW4tYmFua2luZy1jb250YWluZXJcIj5cbiAgPCEtLSBJbml0aWFsIFN0YXRlIC0tPlxuICA8ZGl2ICpuZ0lmPVwiaXNJbml0aWFsU3RhdGVcIiBjbGFzcz1cInN0YXRlLWluaXRpYWxcIj5cbiAgICA8ZGl2IGNsYXNzPVwibWVzc2FnZS1jb250YWluZXJcIj5cbiAgICAgIDxwIGNsYXNzPVwibWVzc2FnZVwiPnt7IGluaXRpYWxNZXNzYWdlIH19PC9wPlxuICAgICAgPGJ1dHRvbiBtYXQtcmFpc2VkLWJ1dHRvbiBjb2xvcj1cInByaW1hcnlcIiAoY2xpY2spPVwicHJvY2VlZFRvTmV4dFN0ZXAoKVwiIFtkaXNhYmxlZF09XCJpc0xvYWRpbmdTdWJqZWN0IHwgYXN5bmNcIj5cbiAgICAgICAge3sgbmV4dEJ1dHRvbkxhYmVsIH19XG4gICAgICA8L2J1dHRvbj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG5cbiAgPCEtLSBCYW5rIFNlbGVjdGlvbiBTdGF0ZSAtLT5cbiAgPGRpdiAqbmdJZj1cImlzQmFua1NlbGVjdGlvblN0YXRlXCIgY2xhc3M9XCJzdGF0ZS1iYW5rLXNlbGVjdGlvblwiPlxuICAgIDxoMyBjbGFzcz1cInNlY3Rpb24tdGl0bGVcIj57eyBzZWxlY3RCYW5rVGl0bGUgfX08L2gzPlxuXG4gICAgPCEtLSBCYW5rIEdyaWQgLS0+XG4gICAgPGRpdiBjbGFzcz1cImJhbmtzLWdyaWRcIiAqbmdJZj1cImJhbmtzLmxlbmd0aCA+IDBcIj5cbiAgICAgIDxkaXZcbiAgICAgICAgKm5nRm9yPVwibGV0IGJhbmsgb2YgYmFua3NcIlxuICAgICAgICBjbGFzcz1cImJhbmstY2FyZFwiXG4gICAgICAgIFtjbGFzcy5zZWxlY3RlZF09XCJzZWxlY3RlZEJhbmsgPT09IGJhbmsuYmFua0NvZGVcIlxuICAgICAgICAoY2xpY2spPVwic2VsZWN0QmFuayhiYW5rKVwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiYmFuay1sb2dvXCIgKm5nSWY9XCJiYW5rLmxvZ29VcmxcIj5cbiAgICAgICAgICA8aW1nIFtzcmNdPVwiYmFuay5sb2dvVXJsXCIgW2FsdF09XCJiYW5rLmRpc3BsYXlOYW1lXCI+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwiYmFuay1pbmZvXCI+XG4gICAgICAgICAgPGg0Pnt7IGJhbmsuZGlzcGxheU5hbWUgfX08L2g0PlxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwiYmFuay1jb2RlXCI+e3sgYmFuay5iYW5rQ29kZSB9fTwvc3Bhbj5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxtYXQtaWNvbiBjbGFzcz1cImNoZWNrLWljb25cIiAqbmdJZj1cInNlbGVjdGVkQmFuayA9PT0gYmFuay5iYW5rQ29kZVwiPmNoZWNrX2NpcmNsZTwvbWF0LWljb24+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDxidXR0b25cbiAgICAgIG1hdC1yYWlzZWQtYnV0dG9uXG4gICAgICBjb2xvcj1cInByaW1hcnlcIlxuICAgICAgKGNsaWNrKT1cInByb2NlZWRUb05leHRTdGVwKClcIlxuICAgICAgW2Rpc2FibGVkXT1cIiFzZWxlY3RlZEJhbmsgfHwgKGlzTG9hZGluZ1N1YmplY3QgfCBhc3luYylcIlxuICAgICAgY2xhc3M9XCJtLXQtMTZcIj5cbiAgICAgIHt7IGNvbnRpbnVlQnV0dG9uTGFiZWwgfX1cbiAgICA8L2J1dHRvbj5cbiAgPC9kaXY+XG5cbiAgPCEtLSBDb25zZW50IFN0YXRlIC0tPlxuICA8ZGl2ICpuZ0lmPVwiaXNDb25zZW50U3RhdGVcIiBjbGFzcz1cInN0YXRlLWNvbnNlbnRcIj5cbiAgICA8ZGl2IGNsYXNzPVwiY29uc2VudC1oZWFkZXJcIj5cbiAgICAgIDxoMz57eyBjb25zZW50VGl0bGUgfX08L2gzPlxuICAgICAgPHA+e3sgY29uc2VudERlc2NyaXB0aW9uIH19PC9wPlxuICAgIDwvZGl2PlxuXG4gICAgPCEtLSBTaG93IGlmcmFtZSBvbmx5IGlmIHdlIGhhdmUgYW4gYXV0aG9yaXphdGlvbiBVUkwgLS0+XG4gICAgPGRpdiBjbGFzcz1cImNvbnNlbnQtY29udGFpbmVyXCIgKm5nSWY9XCJhdXRob3JpemF0aW9uVXJsXCI+XG4gICAgICA8aWZyYW1lXG4gICAgICAgIFtzcmNdPVwiYXV0aG9yaXphdGlvblVybFwiXG4gICAgICAgIGNsYXNzPVwiY29uc2VudC1pZnJhbWVcIlxuICAgICAgICBmcmFtZWJvcmRlcj1cIjBcIlxuICAgICAgICBhbGxvd2Z1bGxzY3JlZW5cbiAgICAgICAgc2FuZGJveD1cImFsbG93LWZvcm1zIGFsbG93LXNjcmlwdHMgYWxsb3ctc2FtZS1vcmlnaW4gYWxsb3ctcG9wdXBzIGFsbG93LXBvcHVwcy10by1lc2NhcGUtc2FuZGJveCBhbGxvdy10b3AtbmF2aWdhdGlvblwiPlxuICAgICAgPC9pZnJhbWU+XG4gICAgPC9kaXY+XG5cbiAgICA8IS0tIFNob3cgd2FpdGluZyBtZXNzYWdlIHdoZW4gY29uc2VudCBpcyBpbiBwb3B1cCBvciBpZnJhbWUgZmFpbGVkIC0tPlxuICAgIDxkaXYgY2xhc3M9XCJjb25zZW50LXdhaXRpbmdcIiAqbmdJZj1cIiFhdXRob3JpemF0aW9uVXJsXCI+XG4gICAgICA8bWF0LXNwaW5uZXIgZGlhbWV0ZXI9XCI0MFwiPjwvbWF0LXNwaW5uZXI+XG4gICAgICA8cD57eyB3YWl0aW5nRm9yQXV0aG9yaXphdGlvblRleHQgfX08L3A+XG4gICAgICA8cCBjbGFzcz1cImNvbnNlbnQtcG9wdXAtaGludFwiPlxuICAgICAgICA8bWF0LWljb24+b3Blbl9pbl9uZXc8L21hdC1pY29uPlxuICAgICAgICA8c3Bhbj57eyBwb3B1cFdpbmRvd01lc3NhZ2UgfX08L3NwYW4+XG4gICAgICA8L3A+XG4gICAgICA8cCBjbGFzcz1cImNvbnNlbnQtcG9wdXAtbm90ZVwiPlxuICAgICAgICB7eyBwb3B1cEJsb2NrZXJNZXNzYWdlIH19XG4gICAgICA8L3A+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuXG4gIDwhLS0gUHJvY2Vzc2luZyBTdGF0ZSAtLT5cbiAgPGRpdiAqbmdJZj1cImlzUHJvY2Vzc2luZ1N0YXRlXCIgY2xhc3M9XCJzdGF0ZS1wcm9jZXNzaW5nXCI+XG4gICAgPGRpdiBjbGFzcz1cImxvYWRpbmctY29udGFpbmVyXCI+XG4gICAgICA8bWF0LXNwaW5uZXIgZGlhbWV0ZXI9XCI1MFwiPjwvbWF0LXNwaW5uZXI+XG4gICAgICA8cCBjbGFzcz1cImxvYWRpbmctbWVzc2FnZVwiPnt7IHdhaXRpbmdNZXNzYWdlIH19PC9wPlxuICAgICAgPGRpdiBjbGFzcz1cInByb2dyZXNzLWRldGFpbHNcIj5cbiAgICAgICAgPHAgKm5nSWY9XCJhY2NvdW50cy5sZW5ndGggPiAwXCI+XG4gICAgICAgICAge3sgYWNjb3VudHNSZXRyaWV2ZWRMYWJlbCB9fToge3sgYWNjb3VudHMubGVuZ3RoIH19XG4gICAgICAgIDwvcD5cbiAgICAgICAgPHAgKm5nSWY9XCJ0cmFuc2FjdGlvbnMubGVuZ3RoID4gMFwiPlxuICAgICAgICAgIHt7IHRyYW5zYWN0aW9uc1JldHJpZXZlZExhYmVsIH19OiB7eyB0cmFuc2FjdGlvbnMubGVuZ3RoIH19XG4gICAgICAgIDwvcD5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cblxuICA8IS0tIEVycm9yIFN0YXRlIC0tPlxuICA8ZGl2ICpuZ0lmPVwiaXNFcnJvclN0YXRlXCIgY2xhc3M9XCJzdGF0ZS1lcnJvclwiPlxuICAgIDxkaXYgY2xhc3M9XCJlcnJvci1jb250YWluZXJcIj5cbiAgICAgIDxtYXQtaWNvbiBjb2xvcj1cIndhcm5cIiBjbGFzcz1cImVycm9yLWljb25cIj5lcnJvcl9vdXRsaW5lPC9tYXQtaWNvbj5cbiAgICAgIDxwIGNsYXNzPVwiZXJyb3ItbWVzc2FnZVwiPnt7IGVycm9yTWVzc2FnZSB9fTwvcD5cbiAgICAgIDxidXR0b24gbWF0LXJhaXNlZC1idXR0b24gY29sb3I9XCJwcmltYXJ5XCIgKGNsaWNrKT1cInJldHJ5KClcIj5cbiAgICAgICAge3sgcmV0cnlCdXR0b25MYWJlbCB9fVxuICAgICAgPC9idXR0b24+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuXG4gIDwhLS0gQ29tcGxldGUgU3RhdGUgLS0+XG4gIDxkaXYgKm5nSWY9XCJpc0NvbXBsZXRlU3RhdGVcIiBjbGFzcz1cInN0YXRlLWNvbXBsZXRlXCI+XG4gICAgPGRpdiBjbGFzcz1cInN1Y2Nlc3MtY29udGFpbmVyXCI+XG4gICAgICA8bWF0LWljb24gY29sb3I9XCJwcmltYXJ5XCIgY2xhc3M9XCJzdWNjZXNzLWljb25cIj5jaGVja19jaXJjbGU8L21hdC1pY29uPlxuICAgICAgPHAgY2xhc3M9XCJzdWNjZXNzLW1lc3NhZ2VcIj57eyBjb21wbGV0aW9uTWVzc2FnZSB9fTwvcD5cblxuICAgICAgPCEtLSBEaXNwbGF5IHN1bW1hcnkgb2YgYWNjb3VudHMgZm91bmQgLS0+XG4gICAgICA8ZGl2IGNsYXNzPVwiYWNjb3VudHMtc3VtbWFyeVwiICpuZ0lmPVwiYWNjb3VudHMubGVuZ3RoID4gMFwiPlxuICAgICAgICA8aDQ+e3sgYWNjb3VudHNTdW1tYXJ5VGV4dCB9fTwvaDQ+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJhY2NvdW50cy1saXN0XCI+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImFjY291bnQtY2FyZFwiICpuZ0Zvcj1cImxldCBhY2NvdW50IG9mIGFjY291bnRzXCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiYWNjb3VudC1oZWFkZXJcIj5cbiAgICAgICAgICAgICAgPG1hdC1pY29uIGNsYXNzPVwiYWNjb3VudC1pY29uXCI+YWNjb3VudF9iYWxhbmNlPC9tYXQtaWNvbj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImFjY291bnQtaW5mb1wiPlxuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJhY2NvdW50LW5hbWVcIj57eyBhY2NvdW50Lm5hbWUgfHwgJ0FjY291bnQnIH19PC9kaXY+XG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImFjY291bnQtaWJhblwiPnt7IGFjY291bnQuaWJhbiB9fTwvZGl2PlxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImFjY291bnQtZGV0YWlsc1wiPlxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiYWNjb3VudC1iYWxhbmNlXCI+XG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJiYWxhbmNlLWFtb3VudFwiPnt7IGFjY291bnQuYmFsYW5jZSB8IGN1cnJlbmN5OmFjY291bnQuY3VycmVuY3k6J3N5bWJvbCc6JzEuMi0yJyB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJhY2NvdW50LWhvbGRlclwiPnt7IGFjY291bnQuYWNjb3VudEhvbGRlck5hbWUgfX08L2Rpdj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8ZGl2IGNsYXNzPVwidHJhbnNhY3Rpb24tc3VtbWFyeVwiICpuZ0lmPVwidHJhbnNhY3Rpb25zLmxlbmd0aCA+IDBcIj5cbiAgICAgICAgICA8cD57eyB0cmFuc2FjdGlvbnNTdW1tYXJ5VGV4dCB9fTwvcD5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG48L2Rpdj4iXX0=
|