@snabcentr/client-ui 0.8.7 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- package/auth/constants/phone-approve-code-mask.d.ts +1 -1
- package/auth/sc-sign-in-form/sc-sign-in-form-by-email/sc-sign-in-form-by-email.component.d.ts +3 -3
- package/auth/sc-sign-in-form/sc-sign-in-form-by-phone/sc-sign-in-form-by-phone.component.d.ts +10 -7
- package/banner/sc-banner.component.d.ts +1 -1
- package/esm2020/auth/constants/phone-approve-code-mask.mjs +2 -2
- package/esm2020/auth/sc-sign-in-form/sc-sign-in-form-by-email/sc-sign-in-form-by-email.component.mjs +6 -6
- package/esm2020/auth/sc-sign-in-form/sc-sign-in-form-by-phone/sc-sign-in-form-by-phone.component.mjs +14 -13
- package/esm2020/auth/sc-sign-in-form/sc-sign-in-form.component.mjs +3 -3
- package/esm2020/banner/sc-banner.component.mjs +2 -2
- package/esm2020/catalog/price-card/sc-price-card.component.mjs +4 -1
- package/esm2020/form-fields/addresses-selection-field/sc-addresses-selection-field.component.mjs +117 -0
- package/esm2020/form-fields/form-fields.module.mjs +80 -0
- package/esm2020/form-fields/suggestion-field/sc-suggestion-field.component.mjs +111 -0
- package/esm2020/profile/sc-profile-accordions-content/sc-profile-accordions-content.component.mjs +29 -16
- package/esm2020/user/index.mjs +3 -1
- package/esm2020/user/reset-user-password/sc-reset-user-password.component.mjs +4 -4
- package/esm2020/user/sc-user.module.mjs +42 -8
- package/esm2020/user/update-user-info-form/sc-update-user-info-form.component.mjs +97 -0
- package/esm2020/user/user-phone-approve-dialog/sc-user-phone-approve-dialog.component.mjs +91 -0
- package/esm2020/verification/index.mjs +2 -2
- package/esm2020/verification/sc-verification.module.mjs +6 -6
- package/esm2020/verification/verification-phone-check-form/sc-verification-phone-check-form.component.mjs +184 -0
- package/fesm2015/snabcentr-client-ui.mjs +608 -94
- package/fesm2015/snabcentr-client-ui.mjs.map +1 -1
- package/fesm2020/snabcentr-client-ui.mjs +594 -94
- package/fesm2020/snabcentr-client-ui.mjs.map +1 -1
- package/form-fields/addresses-selection-field/sc-addresses-selection-field.component.d.ts +65 -0
- package/form-fields/form-fields.module.d.ts +17 -0
- package/form-fields/suggestion-field/sc-suggestion-field.component.d.ts +45 -0
- package/package.json +2 -2
- package/profile/sc-profile-accordions-content/sc-profile-accordions-content.component.d.ts +24 -10
- package/styles/tailwind/tailwind.scss +22 -0
- package/user/index.d.ts +2 -0
- package/user/reset-user-password/sc-reset-user-password.component.d.ts +3 -3
- package/user/sc-user.module.d.ts +10 -6
- package/user/update-user-info-form/sc-update-user-info-form.component.d.ts +56 -0
- package/user/user-phone-approve-dialog/sc-user-phone-approve-dialog.component.d.ts +48 -0
- package/verification/index.d.ts +1 -1
- package/verification/sc-verification.module.d.ts +2 -2
- package/verification/{phone-approve-form/phone-approve-form.component.d.ts → verification-phone-check-form/sc-verification-phone-check-form.component.d.ts} +27 -11
- package/esm2020/verification/phone-approve-form/phone-approve-form.component.mjs +0 -156
@@ -1,156 +0,0 @@
|
|
1
|
-
import { ChangeDetectionStrategy, Component, EventEmitter, Inject, Input, Output } from '@angular/core';
|
2
|
-
import { FormGroupDirective } from '@angular/forms';
|
3
|
-
import { phoneApproveCodeMask } from '../../auth/constants/phone-approve-code-mask';
|
4
|
-
import { Subject, filter, map, switchMap, catchError, of, startWith, share, tap, finalize, timer, scan, takeWhile, endWith, distinctUntilChanged } from 'rxjs';
|
5
|
-
import { tuiControlValue } from '@taiga-ui/cdk';
|
6
|
-
import * as i0 from "@angular/core";
|
7
|
-
import * as i1 from "@snabcentr/client-core";
|
8
|
-
import * as i2 from "@angular/common";
|
9
|
-
import * as i3 from "@angular/forms";
|
10
|
-
import * as i4 from "@taiga-ui/core";
|
11
|
-
import * as i5 from "@taiga-ui/kit";
|
12
|
-
import * as i6 from "@taiga-ui/cdk";
|
13
|
-
import * as i7 from "@maskito/angular";
|
14
|
-
/**
|
15
|
-
* Компонент формы проверки телефона и получения кода подтверждения.
|
16
|
-
*/
|
17
|
-
export class ScPhoneApproveFormComponent {
|
18
|
-
/**
|
19
|
-
* Инициализирует экземпляр класса {@link ScPhoneApproveFormComponent}.
|
20
|
-
*
|
21
|
-
* @param verificationService Сервис верификации.
|
22
|
-
* @param formGroupDirective Директива c `FormGroup` из DOM.
|
23
|
-
*/
|
24
|
-
constructor(verificationService, formGroupDirective) {
|
25
|
-
this.verificationService = verificationService;
|
26
|
-
this.formGroupDirective = formGroupDirective;
|
27
|
-
/**
|
28
|
-
* Признак, следует ли телефону быть в системе. От этого признака зависит в каких случаях выдавать ошибку при проверки занятости телефона.
|
29
|
-
*/
|
30
|
-
this.shouldBeBusy = true;
|
31
|
-
/**
|
32
|
-
* Признак, следует ли проверять подтверждён ли телефона в системе. При `true` будет вызывать ошибку при наличие телефона в системе без подтверждения.
|
33
|
-
*/
|
34
|
-
this.shouldBeConfirmed = false;
|
35
|
-
/**
|
36
|
-
* Наличие кода подтверждения у пользователя.
|
37
|
-
*/
|
38
|
-
this.haveCode = false;
|
39
|
-
/**
|
40
|
-
* Событие для обратной привязки наличия кода подтверждения
|
41
|
-
*/
|
42
|
-
this.haveCodeChange = new EventEmitter();
|
43
|
-
/**
|
44
|
-
* {@link Subject} События отправки кода подтверждения.
|
45
|
-
*/
|
46
|
-
this.onSendCode = new Subject();
|
47
|
-
/**
|
48
|
-
* {@link Observable} Запроса данных получения кода подтверждения.
|
49
|
-
*/
|
50
|
-
this.loadingApproveCode$ = this.onSendCode.pipe(filter(() => this.phoneControl.valid), map(() => this.phoneControl.value), switchMap((value) => this.verificationService.sendPhoneApproveCode(value).pipe(tap(() => this.reloadTimer$.next(60)), map(() => false), catchError((error) => {
|
51
|
-
const errorResponse = error.error;
|
52
|
-
const regex = /(\d{2}):\d{2}/;
|
53
|
-
const match = errorResponse.message.match(regex);
|
54
|
-
if (match && match.length > 1) {
|
55
|
-
const timeParts = match[0].split(':');
|
56
|
-
const seconds = parseInt(timeParts[1], 10);
|
57
|
-
this.reloadTimer$.next(seconds);
|
58
|
-
}
|
59
|
-
else {
|
60
|
-
this.phoneControl.setErrors({ serverResponse: errorResponse?.errors?.[`phone`] ?? [errorResponse.message] });
|
61
|
-
}
|
62
|
-
return of(false);
|
63
|
-
}), finalize(() => this.setHaveCode(true)), startWith(true))), startWith(false), share());
|
64
|
-
/**
|
65
|
-
* Маска поля ввода кода для подтверждения.
|
66
|
-
*/
|
67
|
-
this.approveCodeMask = phoneApproveCodeMask;
|
68
|
-
/**
|
69
|
-
* {@link Subject} События запуска/остановки таймера.
|
70
|
-
*/
|
71
|
-
this.reloadTimer$ = new Subject();
|
72
|
-
/**
|
73
|
-
* {@link Observable} Таймера.
|
74
|
-
*
|
75
|
-
* TODO: Вынести таймер в отдельную директиву TASK:[#9260].
|
76
|
-
*/
|
77
|
-
this.timer$ = this.reloadTimer$.pipe(switchMap((sec) => timer(0, 1000).pipe(scan((total) => --total, sec), takeWhile((total) => total >= 0), map((total) => {
|
78
|
-
const minutes = Math.floor(total / 60);
|
79
|
-
const seconds = total % 60;
|
80
|
-
return `${Math.round(minutes).toString().padStart(2, '0')}:${Math.round(seconds).toString().padStart(2, '0')}`;
|
81
|
-
}), endWith(null), startWith(null), distinctUntilChanged())));
|
82
|
-
}
|
83
|
-
/**
|
84
|
-
* Группа полей ввода для формы «Вход на сайт».
|
85
|
-
*/
|
86
|
-
get form() {
|
87
|
-
return this.formGroupDirective?.form;
|
88
|
-
}
|
89
|
-
/**
|
90
|
-
* Поле ввода 'Номер телефона'.
|
91
|
-
*/
|
92
|
-
get phoneControl() {
|
93
|
-
return this.form?.controls.phone;
|
94
|
-
}
|
95
|
-
/** @inheritDoc */
|
96
|
-
ngOnInit() {
|
97
|
-
this.phoneCheck$ = tuiControlValue(this.phoneControl).pipe(tap(() => this.reloadTimer$.next(0)), switchMap((value) => {
|
98
|
-
if (this.phoneControl.valid && !!value) {
|
99
|
-
return this.verificationService.getPhoneCheck$(value).pipe(map((result) => {
|
100
|
-
if (this.shouldBeBusy !== result.isBusy) {
|
101
|
-
this.phoneControl.setErrors({
|
102
|
-
serverResponse: [
|
103
|
-
this.shouldBeBusy ? 'Пользователя с таким номером телефона не существует' : 'Пользователь с таким номером телефона уже существует',
|
104
|
-
],
|
105
|
-
});
|
106
|
-
this.phoneControl.markAsTouched();
|
107
|
-
return false;
|
108
|
-
}
|
109
|
-
if (this.shouldBeConfirmed && (result.isConfirmed === false || result.isConfirmed === null)) {
|
110
|
-
this.phoneControl.setErrors({
|
111
|
-
serverResponse: [
|
112
|
-
'Вход по указанному телефону невозможен. Обратитесь к вашему персональному менеджеру или войдите с использованием e-mail и пароля.',
|
113
|
-
],
|
114
|
-
});
|
115
|
-
this.phoneControl.markAsTouched();
|
116
|
-
return false;
|
117
|
-
}
|
118
|
-
return true;
|
119
|
-
}), catchError((error) => {
|
120
|
-
const errorResponse = error.error;
|
121
|
-
this.phoneControl.setErrors({ serverResponse: errorResponse?.errors?.[`phone`] ?? [errorResponse.message] });
|
122
|
-
return of(false);
|
123
|
-
}), startWith(null));
|
124
|
-
}
|
125
|
-
this.setHaveCode(false);
|
126
|
-
return of(false);
|
127
|
-
}), share());
|
128
|
-
}
|
129
|
-
/**
|
130
|
-
* Устанавливает состояние наличия кода подтверждения у пользователя.
|
131
|
-
*
|
132
|
-
* @param haveCode Признак того есть ли код подтверждения или нет.
|
133
|
-
*/
|
134
|
-
setHaveCode(haveCode) {
|
135
|
-
this.haveCode = haveCode;
|
136
|
-
this.haveCodeChange.emit(haveCode);
|
137
|
-
}
|
138
|
-
}
|
139
|
-
ScPhoneApproveFormComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ScPhoneApproveFormComponent, deps: [{ token: i1.ScVerificationService }, { token: FormGroupDirective }], target: i0.ɵɵFactoryTarget.Component });
|
140
|
-
ScPhoneApproveFormComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: ScPhoneApproveFormComponent, selector: "sc-phone-approve-form", inputs: { shouldBeBusy: "shouldBeBusy", shouldBeConfirmed: "shouldBeConfirmed", haveCode: "haveCode" }, outputs: { haveCodeChange: "haveCodeChange" }, ngImport: i0, template: "<form [formGroup]=\"form\" *tuiLet=\"(loadingApproveCode$ | async) as loadingApproveCode\" class=\"flex flex-col gap-3\">\n <label tuiLabel=\"\u041D\u043E\u043C\u0435\u0440 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430\">\n <tui-input-phone formControlName=\"phone\" [tuiTextfieldCustomContent]=\"checkingPhone\">\n \u041D\u043E\u043C\u0435\u0440 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430\n <input tuiTextfield autocomplete=\"phone\" />\n </tui-input-phone>\n <tui-error formControlName=\"phone\" [error]=\"[] | tuiFieldError | async\"></tui-error>\n </label>\n\n <label *ngIf=\"loadingApproveCode === false && haveCode\" tuiLabel=\"\u041A\u043E\u0434 \u0438\u0437 \u0421\u041C\u0421\">\n <tui-input formControlName=\"phoneApproveCode\">\n \u041A\u043E\u0434 \u0438\u0437 \u0421\u041C\u0421\n <input tuiTextfield [maskito]=\"approveCodeMask\" autocomplete=\"new-password\" />\n </tui-input>\n <tui-error formControlName=\"phoneApproveCode\" [error]=\"[] | tuiFieldError | async\"></tui-error>\n </label>\n\n <div *tuiLet=\"!!loadingApproveCode as loadingApproveCode\" class=\"flex gap-4 justify-center\">\n <button\n *ngIf=\"!haveCode\"\n tuiButton\n size=\"s\"\n (click)=\"onSendCode.next()\"\n [disabled]=\"loadingApproveCode || !!!(phoneCheck$ | async) || phoneControl.invalid\"\n [showLoader]=\"loadingApproveCode\"\n icon=\"scIconLogIn\"\n >\n \u041F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u043A\u043E\u0434\n </button>\n <button *ngIf=\"!loadingApproveCode && !haveCode\" tuiLink [pseudo]=\"true\" [disabled]=\"!!!(phoneCheck$ | async) || phoneControl.invalid\" (click)=\"setHaveCode(true)\">\n \u0423 \u043C\u0435\u043D\u044F \u0435\u0441\u0442\u044C \u043A\u043E\u0434\n </button>\n\n <ng-container *tuiLet=\"timer$ | async as timer\">\n <tui-loader *ngIf=\"haveCode\" [showLoader]=\"loadingApproveCode\">\n <button tuiLink [pseudo]=\"true\" [disabled]=\"loadingApproveCode || timer\" (click)=\"onSendCode.next()\">\n \u041F\u043E\u0432\u0442\u043E\u0440\u043D\u043E \u043E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u043A\u043E\u0434\n <ng-container *ngIf=\"timer\" class=\"!text-tui-base-08\">(\u0447\u0435\u0440\u0435\u0437 {{ timer }})</ng-container>\n </button>\n </tui-loader>\n </ng-container>\n </div>\n</form>\n\n<ng-template #checkingPhone>\n <tui-loader *ngIf=\"!!!(phoneCheck$ | async) && phoneControl.valid\" class=\"w-4 h-4\"> </tui-loader>\n</ng-template>\n", dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i4.TuiTextfieldComponent, selector: "input[tuiTextfield], textarea[tuiTextfield]" }, { kind: "component", type: i5.TuiInputComponent, selector: "tui-input" }, { kind: "directive", type: i5.TuiInputDirective, selector: "tui-input" }, { kind: "directive", type: i4.TuiTextfieldCustomContentDirective, selector: "[tuiTextfieldCustomContent]", inputs: ["tuiTextfieldCustomContent"] }, { kind: "component", type: i4.TuiLinkComponent, selector: "a[tuiLink], button[tuiLink]", inputs: ["pseudo", "icon", "iconAlign", "iconRotated", "mode"], exportAs: ["tuiLink"] }, { kind: "component", type: i4.TuiButtonComponent, selector: "button[tuiButton], button[tuiIconButton], a[tuiButton], a[tuiIconButton]", inputs: ["appearance", "disabled", "icon", "iconRight", "shape", "showLoader", "size"] }, { kind: "component", type: i4.TuiLabelComponent, selector: "label[tuiLabel]", inputs: ["tuiLabel", "context"] }, { kind: "component", type: i4.TuiErrorComponent, selector: "tui-error", inputs: ["error"] }, { kind: "directive", type: i6.TuiLetDirective, selector: "[tuiLet]", inputs: ["tuiLet"] }, { kind: "component", type: i4.TuiLoaderComponent, selector: "tui-loader", inputs: ["size", "inheritColor", "overlay", "textContent", "showLoader"] }, { kind: "component", type: i5.TuiInputPhoneComponent, selector: "tui-input-phone", inputs: ["countryCode", "phoneMaskAfterCountryCode", "allowText", "search"], outputs: ["searchChange"] }, { kind: "directive", type: i5.TuiInputPhoneDirective, selector: "tui-input-phone" }, { kind: "directive", type: i7.MaskitoDirective, selector: "[maskito]", inputs: ["maskito", "maskitoElement"] }, { kind: "directive", type: i7.MaskitoCva, selector: "input[maskito], textarea[maskito]", inputs: ["maskito"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.TuiFieldErrorPipe, name: "tuiFieldError" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
141
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ScPhoneApproveFormComponent, decorators: [{
|
142
|
-
type: Component,
|
143
|
-
args: [{ selector: 'sc-phone-approve-form', changeDetection: ChangeDetectionStrategy.OnPush, template: "<form [formGroup]=\"form\" *tuiLet=\"(loadingApproveCode$ | async) as loadingApproveCode\" class=\"flex flex-col gap-3\">\n <label tuiLabel=\"\u041D\u043E\u043C\u0435\u0440 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430\">\n <tui-input-phone formControlName=\"phone\" [tuiTextfieldCustomContent]=\"checkingPhone\">\n \u041D\u043E\u043C\u0435\u0440 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430\n <input tuiTextfield autocomplete=\"phone\" />\n </tui-input-phone>\n <tui-error formControlName=\"phone\" [error]=\"[] | tuiFieldError | async\"></tui-error>\n </label>\n\n <label *ngIf=\"loadingApproveCode === false && haveCode\" tuiLabel=\"\u041A\u043E\u0434 \u0438\u0437 \u0421\u041C\u0421\">\n <tui-input formControlName=\"phoneApproveCode\">\n \u041A\u043E\u0434 \u0438\u0437 \u0421\u041C\u0421\n <input tuiTextfield [maskito]=\"approveCodeMask\" autocomplete=\"new-password\" />\n </tui-input>\n <tui-error formControlName=\"phoneApproveCode\" [error]=\"[] | tuiFieldError | async\"></tui-error>\n </label>\n\n <div *tuiLet=\"!!loadingApproveCode as loadingApproveCode\" class=\"flex gap-4 justify-center\">\n <button\n *ngIf=\"!haveCode\"\n tuiButton\n size=\"s\"\n (click)=\"onSendCode.next()\"\n [disabled]=\"loadingApproveCode || !!!(phoneCheck$ | async) || phoneControl.invalid\"\n [showLoader]=\"loadingApproveCode\"\n icon=\"scIconLogIn\"\n >\n \u041F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u043A\u043E\u0434\n </button>\n <button *ngIf=\"!loadingApproveCode && !haveCode\" tuiLink [pseudo]=\"true\" [disabled]=\"!!!(phoneCheck$ | async) || phoneControl.invalid\" (click)=\"setHaveCode(true)\">\n \u0423 \u043C\u0435\u043D\u044F \u0435\u0441\u0442\u044C \u043A\u043E\u0434\n </button>\n\n <ng-container *tuiLet=\"timer$ | async as timer\">\n <tui-loader *ngIf=\"haveCode\" [showLoader]=\"loadingApproveCode\">\n <button tuiLink [pseudo]=\"true\" [disabled]=\"loadingApproveCode || timer\" (click)=\"onSendCode.next()\">\n \u041F\u043E\u0432\u0442\u043E\u0440\u043D\u043E \u043E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u043A\u043E\u0434\n <ng-container *ngIf=\"timer\" class=\"!text-tui-base-08\">(\u0447\u0435\u0440\u0435\u0437 {{ timer }})</ng-container>\n </button>\n </tui-loader>\n </ng-container>\n </div>\n</form>\n\n<ng-template #checkingPhone>\n <tui-loader *ngIf=\"!!!(phoneCheck$ | async) && phoneControl.valid\" class=\"w-4 h-4\"> </tui-loader>\n</ng-template>\n" }]
|
144
|
-
}], ctorParameters: function () { return [{ type: i1.ScVerificationService }, { type: i3.FormGroupDirective, decorators: [{
|
145
|
-
type: Inject,
|
146
|
-
args: [FormGroupDirective]
|
147
|
-
}] }]; }, propDecorators: { shouldBeBusy: [{
|
148
|
-
type: Input
|
149
|
-
}], shouldBeConfirmed: [{
|
150
|
-
type: Input
|
151
|
-
}], haveCode: [{
|
152
|
-
type: Input
|
153
|
-
}], haveCodeChange: [{
|
154
|
-
type: Output
|
155
|
-
}] } });
|
156
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGhvbmUtYXBwcm92ZS1mb3JtLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2NsaWVudC11aS92ZXJpZmljYXRpb24vcGhvbmUtYXBwcm92ZS1mb3JtL3Bob25lLWFwcHJvdmUtZm9ybS5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9jbGllbnQtdWkvdmVyaWZpY2F0aW9uL3Bob25lLWFwcHJvdmUtZm9ybS9waG9uZS1hcHByb3ZlLWZvcm0uY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLHVCQUF1QixFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBVSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDaEgsT0FBTyxFQUEwQixrQkFBa0IsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRzVFLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDhDQUE4QyxDQUFDO0FBRXBGLE9BQU8sRUFBRSxPQUFPLEVBQWMsTUFBTSxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzNLLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxlQUFlLENBQUM7Ozs7Ozs7OztBQUVoRDs7R0FFRztBQU1ILE1BQU0sT0FBTywyQkFBMkI7SUEySHBDOzs7OztPQUtHO0lBQ0gsWUFDcUIsbUJBQTBDLEVBRTFDLGtCQUF1QztRQUZ2Qyx3QkFBbUIsR0FBbkIsbUJBQW1CLENBQXVCO1FBRTFDLHVCQUFrQixHQUFsQixrQkFBa0IsQ0FBcUI7UUFuSTVEOztXQUVHO1FBRUksaUJBQVksR0FBWSxJQUFJ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QUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3JCLENBQUMsQ0FBQyxFQUNGLEtBQUssRUFBRSxDQUNWLENBQUM7SUFDTixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLFdBQVcsQ0FBQyxRQUFpQjtRQUNoQyxJQUFJLENBQUMsUUFBUSxHQUFHLFFBQVEsQ0FBQztRQUN6QixJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUN2QyxDQUFDOzt3SEFoTVEsMkJBQTJCLHVEQW1JeEIsa0JBQWtCOzRHQW5JckIsMkJBQTJCLG9OQ2xCeEMsMnJGQStDQTsyRkQ3QmEsMkJBQTJCO2tCQUx2QyxTQUFTOytCQUNJLHVCQUF1QixtQkFFaEIsdUJBQXVCLENBQUMsTUFBTTs7MEJBcUkxQyxNQUFNOzJCQUFDLGtCQUFrQjs0Q0E5SHZCLFlBQVk7c0JBRGxCLEtBQUs7Z0JBT0MsaUJBQWlCO3NCQUR2QixLQUFLO2dCQU9DLFFBQVE7c0JBRGQsS0FBSztnQkFPQyxjQUFjO3NCQURwQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSHR0cEVycm9yUmVzcG9uc2UgfSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCc7XG5pbXBvcnQgeyBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSwgQ29tcG9uZW50LCBFdmVudEVtaXR0ZXIsIEluamVjdCwgSW5wdXQsIE9uSW5pdCwgT3V0cHV0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBGb3JtR3JvdXAsIEZvcm1Db250cm9sLCBGb3JtR3JvdXBEaXJlY3RpdmUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBNYXNraXRvT3B0aW9ucyB9IGZyb20gJ0BtYXNraXRvL2NvcmUnO1xuaW1wb3J0IHsgU2NWZXJpZmljYXRpb25TZXJ2aWNlIH0gZnJvbSAnQHNuYWJjZW50ci9jbGllbnQtY29yZSc7XG5pbXBvcnQgeyBwaG9uZUFwcHJvdmVDb2RlTWFzayB9IGZyb20gJy4uLy4uL2F1dGgvY29uc3RhbnRzL3Bob25lLWFwcHJvdmUtY29kZS1tYXNrJztcbmltcG9ydCB7IEFwaUVycm9yUmVzcG9uc2UgfSBmcm9tICcuLi8uLi9hdXRoL2ludGVyZmFjZXMvQXBpRXJyb3JSZXNwb25zZSc7XG5pbXBvcnQgeyBTdWJqZWN0LCBPYnNlcnZhYmxlLCBmaWx0ZXIsIG1hcCwgc3dpdGNoTWFwLCBjYXRjaEVycm9yLCBvZiwgc3RhcnRXaXRoLCBzaGFyZSwgdGFwLCBmaW5hbGl6ZSwgdGltZXIsIHNjYW4sIHRha2VXaGlsZSwgZW5kV2l0aCwgZGlzdGluY3RVbnRpbENoYW5nZWQgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IHR1aUNvbnRyb2xWYWx1ZSB9IGZyb20gJ0B0YWlnYS11aS9jZGsnO1xuXG4vKipcbiAqINCa0L7QvNC/0L7QvdC10L3RgiDRhNC+0YDQvNGLINC/0YDQvtCy0LXRgNC60Lgg0YLQtdC70LXRhNC+0L3QsCDQuCDQv9C+0LvRg9GH0LXQvdC40Y8g0LrQvtC00LAg0L/QvtC00YLQstC10YDQttC00LXQvdC40Y8uXG4gKi9cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAnc2MtcGhvbmUtYXBwcm92ZS1mb3JtJyxcbiAgICB0ZW1wbGF0ZVVybDogJy4vcGhvbmUtYXBwcm92ZS1mb3JtLmNvbXBvbmVudC5odG1sJyxcbiAgICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbn0pXG5leHBvcnQgY2xhc3MgU2NQaG9uZUFwcHJvdmVGb3JtQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcbiAgICAvKipcbiAgICAgKiDQn9GA0LjQt9C90LDQuiwg0YHQu9C10LTRg9C10YIg0LvQuCDRgtC10LvQtdGE0L7QvdGDINCx0YvRgtGMINCyINGB0LjRgdGC0LXQvNC1LiDQntGCINGN0YLQvtCz0L4g0L/RgNC40LfQvdCw0LrQsCDQt9Cw0LLQuNGB0LjRgiDQsiDQutCw0LrQuNGFINGB0LvRg9GH0LDRj9GFINCy0YvQtNCw0LLQsNGC0Ywg0L7RiNC40LHQutGDINC/0YDQuCDQv9GA0L7QstC10YDQutC4INC30LDQvdGP0YLQvtGB0YLQuCDRgtC10LvQtdGE0L7QvdCwLlxuICAgICAqL1xuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIHNob3VsZEJlQnVzeTogYm9vbGVhbiA9IHRydWU7XG5cbiAgICAvKipcbiAgICAgKiDQn9GA0LjQt9C90LDQuiwg0YHQu9C10LTRg9C10YIg0LvQuCDQv9GA0L7QstC10YDRj9GC0Ywg0L/QvtC00YLQstC10YDQttC00ZHQvSDQu9C4INGC0LXQu9C10YTQvtC90LAg0LIg0YHQuNGB0YLQtdC80LUuINCf0YDQuCBgdHJ1ZWAg0LHRg9C00LXRgiDQstGL0LfRi9Cy0LDRgtGMINC+0YjQuNCx0LrRgyDQv9GA0Lgg0L3QsNC70LjRh9C40LUg0YLQtdC70LXRhNC+0L3QsCDQsiDRgdC40YHRgtC10LzQtSDQsdC10Lcg0L/QvtC00YLQstC10YDQttC00LXQvdC40Y8uXG4gICAgICovXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgc2hvdWxkQmVDb25maXJtZWQ6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIC8qKlxuICAgICAqINCd0LDQu9C40YfQuNC1INC60L7QtNCwINC/0L7QtNGC0LLQtdGA0LbQtNC10L3QuNGPINGDINC/0L7Qu9GM0LfQvtCy0LDRgtC10LvRjy5cbiAgICAgKi9cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBoYXZlQ29kZTogYm9vbGVhbiA9IGZhbHNlO1xuXG4gICAgLyoqXG4gICAgICog0KHQvtCx0YvRgtC40LUg0LTQu9GPINC+0LHRgNCw0YLQvdC+0Lkg0L/RgNC40LLRj9C30LrQuCDQvdCw0LvQuNGH0LjRjyDQutC+0LTQsCDQv9C+0LTRgtCy0LXRgNC20LTQtdC90LjRj1xuICAgICAqL1xuICAgIEBPdXRwdXQoKVxuICAgIHB1YmxpYyBoYXZlQ29kZUNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8Ym9vbGVhbj4oKTtcblxuICAgIC8qKlxuICAgICAqINCT0YDRg9C/0L/QsCDQv9C+0LvQtdC5INCy0LLQvtC00LAg0LTQu9GPINGE0L7RgNC80YsgwqvQktGF0L7QtCDQvdCwINGB0LDQudGCwrsuXG4gICAgICovXG4gICAgcHVibGljIGdldCBmb3JtKCk6IEZvcm1Hcm91cDx7XG4gICAgICAgIHBob25lOiBGb3JtQ29udHJvbDxzdHJpbmcgfCBudWxsPjtcbiAgICAgICAgcGhvbmVBcHByb3ZlQ29kZTogRm9ybUNvbnRyb2w8c3RyaW5nIHwgbnVsbD47XG4gICAgfT4ge1xuICAgICAgICByZXR1cm4gdGhpcy5mb3JtR3JvdXBEaXJlY3RpdmU/LmZvcm0gYXMgRm9ybUdyb3VwPHtcbiAgICAgICAgICAgIHBob25lOiBGb3JtQ29udHJvbDxzdHJpbmcgfCBudWxsPjtcbiAgICAgICAgICAgIHBob25lQXBwcm92ZUNvZGU6IEZvcm1Db250cm9sPHN0cmluZyB8IG51bGw+O1xuICAgICAgICB9PjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiDQn9C+0LvQtSDQstCy0L7QtNCwICfQndC+0LzQtdGAINGC0LXQu9C10YTQvtC90LAnLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgcGhvbmVDb250cm9sKCk6IEZvcm1Db250cm9sPHN0cmluZyB8IG51bGw+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZm9ybT8uY29udHJvbHMucGhvbmU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICoge0BsaW5rIE9ic2VydmFibGV9INCX0LDQv9GA0L7RgdCwINC/0YDQvtCy0LXRgNC60Lgg0L3QvtC80LXRgNCwINGC0LXQu9C10YTQvtC90LAuXG4gICAgICovXG4gICAgcHVibGljIHBob25lQ2hlY2skPzogT2JzZXJ2YWJsZTxib29sZWFuIHwgbnVsbD47XG5cbiAgICAvKipcbiAgICAgKiB7QGxpbmsgU3ViamVjdH0g0KHQvtCx0YvRgtC40Y8g0L7RgtC/0YDQsNCy0LrQuCDQutC+0LTQsCDQv9C+0LTRgtCy0LXRgNC20LTQtdC90LjRjy5cbiAgICAgKi9cbiAgICBwdWJsaWMgcmVhZG9ubHkgb25TZW5kQ29kZTogU3ViamVjdDx2b2lkPiA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgICAvKipcbiAgICAgKiB7QGxpbmsgT2JzZXJ2YWJsZX0g0JfQsNC/0YDQvtGB0LAg0LTQsNC90L3Ri9GFINC/0L7Qu9GD0YfQtdC90LjRjyDQutC+0LTQsCDQv9C+0LTRgtCy0LXRgNC20LTQtdC90LjRjy5cbiAgICAgKi9cbiAgICBwdWJsaWMgcmVhZG9ubHkgbG9hZGluZ0FwcHJvdmVDb2RlJDogT2JzZXJ2YWJsZTxib29sZWFuPiA9IHRoaXMub25TZW5kQ29kZS5waXBlKFxuICAgICAgICBmaWx0ZXIoKCkgPT4gdGhpcy5waG9uZUNvbnRyb2wudmFsaWQpLFxuICAgICAgICBtYXAoKCkgPT4gdGhpcy5waG9uZUNvbnRyb2wudmFsdWUgYXMgc3RyaW5nKSxcbiAgICAgICAgc3dpdGNoTWFwKCh2YWx1ZSkgPT5cbiAgICAgICAgICAgIHRoaXMudmVyaWZpY2F0aW9uU2VydmljZS5zZW5kUGhvbmVBcHByb3ZlQ29kZSh2YWx1ZSkucGlwZShcbiAgICAgICAgICAgICAgICB0YXAoKCkgPT4gdGhpcy5yZWxvYWRUaW1lciQubmV4dCg2MCkpLFxuICAgICAgICAgICAgICAgIG1hcCgoKSA9PiBmYWxzZSksXG4gICAgICAgICAgICAgICAgY2F0Y2hFcnJvcigoZXJyb3I6IEh0dHBFcnJvclJlc3BvbnNlKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGVycm9yUmVzcG9uc2UgPSBlcnJvci5lcnJvciBhcyBBcGlFcnJvclJlc3BvbnNlO1xuXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHJlZ2V4ID0gLyhcXGR7Mn0pOlxcZHsyfS87XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG1hdGNoID0gZXJyb3JSZXNwb25zZS5tZXNzYWdlLm1hdGNoKHJlZ2V4KTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAobWF0Y2ggJiYgbWF0Y2gubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdGltZVBhcnRzID0gbWF0Y2hbMF0uc3BsaXQoJzonKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHNlY29uZHMgPSBwYXJzZUludCh0aW1lUGFydHNbMV0sIDEwKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yZWxvYWRUaW1lciQubmV4dChzZWNvbmRzKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucGhvbmVDb250cm9sLnNldEVycm9ycyh7IHNlcnZlclJlc3BvbnNlOiBlcnJvclJlc3BvbnNlPy5lcnJvcnM/LltgcGhvbmVgXSA/PyBbZXJyb3JSZXNwb25zZS5tZXNzYWdlXSB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBvZihmYWxzZSk7XG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgZmluYWxpemUoKCkgPT4gdGhpcy5zZXRIYXZlQ29kZSh0cnVlKSksXG4gICAgICAgICAgICAgICAgc3RhcnRXaXRoKHRydWUpXG4gICAgICAgICAgICApXG4gICAgICAgICksXG4gICAgICAgIHN0YXJ0V2l0aChmYWxzZSksXG4gICAgICAgIHNoYXJlKClcbiAgICApO1xuXG4gICAgLyoqXG4gICAgICog0JzQsNGB0LrQsCDQv9C+0LvRjyDQstCy0L7QtNCwINC60L7QtNCwINC00LvRjyDQv9C+0LTRgtCy0LXRgNC20LTQtdC90LjRjy5cbiAgICAgKi9cbiAgICBwdWJsaWMgcmVhZG9ubHkgYXBwcm92ZUNvZGVNYXNrOiBNYXNraXRvT3B0aW9ucyA9IHBob25lQXBwcm92ZUNvZGVNYXNrO1xuXG4gICAgLyoqXG4gICAgICoge0BsaW5rIFN1YmplY3R9INCh0L7QsdGL0YLQuNGPINC30LDQv9GD0YHQutCwL9C+0YHRgtCw0L3QvtCy0LrQuCDRgtCw0LnQvNC10YDQsC5cbiAgICAgKi9cbiAgICBwdWJsaWMgcmVhZG9ubHkgcmVsb2FkVGltZXIkOiBTdWJqZWN0PG51bWJlcj4gPSBuZXcgU3ViamVjdDxudW1iZXI+KCk7XG5cbiAgICAvKipcbiAgICAgKiB7QGxpbmsgT2JzZXJ2YWJsZX0g0KLQsNC50LzQtdGA0LAuXG4gICAgICpcbiAgICAgKiBUT0RPOiDQktGL0L3QtdGB0YLQuCDRgtCw0LnQvNC10YAg0LIg0L7RgtC00LXQu9GM0L3Rg9GOINC00LjRgNC10LrRgtC40LLRgyBUQVNLOlsjOTI2MF0uXG4gICAgICovXG4gICAgcHVibGljIHJlYWRvbmx5IHRpbWVyJDogT2JzZXJ2YWJsZTxzdHJpbmcgfCBudWxsPiA9IHRoaXMucmVsb2FkVGltZXIkLnBpcGUoXG4gICAgICAgIHN3aXRjaE1hcCgoc2VjKSA9PlxuICAgICAgICAgICAgdGltZXIoMCwgMTAwMCkucGlwZShcbiAgICAgICAgICAgICAgICBzY2FuKCh0b3RhbCkgPT4gLS10b3RhbCwgc2VjKSxcbiAgICAgICAgICAgICAgICB0YWtlV2hpbGUoKHRvdGFsKSA9PiB0b3RhbCA+PSAwKSxcbiAgICAgICAgICAgICAgICBtYXAoKHRvdGFsKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG1pbnV0ZXMgPSBNYXRoLmZsb29yKHRvdGFsIC8gNjApO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBzZWNvbmRzID0gdG90YWwgJSA2MDtcblxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYCR7TWF0aC5yb3VuZChtaW51dGVzKS50b1N0cmluZygpLnBhZFN0YXJ0KDIsICcwJyl9OiR7TWF0aC5yb3VuZChzZWNvbmRzKS50b1N0cmluZygpLnBhZFN0YXJ0KDIsICcwJyl9YDtcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICBlbmRXaXRoKG51bGwpLFxuICAgICAgICAgICAgICAgIHN0YXJ0V2l0aChudWxsKSxcbiAgICAgICAgICAgICAgICBkaXN0aW5jdFVudGlsQ2hhbmdlZCgpXG4gICAgICAgICAgICApXG4gICAgICAgIClcbiAgICApO1xuXG4gICAgLyoqXG4gICAgICog0JjQvdC40YbQuNCw0LvQuNC30LjRgNGD0LXRgiDRjdC60LfQtdC80L/Qu9GP0YAg0LrQu9Cw0YHRgdCwIHtAbGluayBTY1Bob25lQXBwcm92ZUZvcm1Db21wb25lbnR9LlxuICAgICAqXG4gICAgICogQHBhcmFtIHZlcmlmaWNhdGlvblNlcnZpY2Ug0KHQtdGA0LLQuNGBINCy0LXRgNC40YTQuNC60LDRhtC40LguXG4gICAgICogQHBhcmFtIGZvcm1Hcm91cERpcmVjdGl2ZSDQlNC40YDQtdC60YLQuNCy0LAgYyBgRm9ybUdyb3VwYCDQuNC3IERPTS5cbiAgICAgKi9cbiAgICBwdWJsaWMgY29uc3RydWN0b3IoXG4gICAgICAgIHByaXZhdGUgcmVhZG9ubHkgdmVyaWZpY2F0aW9uU2VydmljZTogU2NWZXJpZmljYXRpb25TZXJ2aWNlLFxuICAgICAgICBASW5qZWN0KEZvcm1Hcm91cERpcmVjdGl2ZSlcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSBmb3JtR3JvdXBEaXJlY3RpdmU/OiBGb3JtR3JvdXBEaXJlY3RpdmVcbiAgICApIHt9XG5cbiAgICAvKiogQGluaGVyaXREb2MgKi9cbiAgICBwdWJsaWMgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgICAgIHRoaXMucGhvbmVDaGVjayQgPSB0dWlDb250cm9sVmFsdWU8c3RyaW5nIHwgbnVsbD4odGhpcy5waG9uZUNvbnRyb2wpLnBpcGUoXG4gICAgICAgICAgICB0YXAoKCkgPT4gdGhpcy5yZWxvYWRUaW1lciQubmV4dCgwKSksXG4gICAgICAgICAgICBzd2l0Y2hNYXAoKHZhbHVlKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMucGhvbmVDb250cm9sLnZhbGlkICYmICEhdmFsdWUpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMudmVyaWZpY2F0aW9uU2VydmljZS5nZXRQaG9uZUNoZWNrJCh2YWx1ZSkucGlwZShcbiAgICAgICAgICAgICAgICAgICAgICAgIG1hcCgocmVzdWx0KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuc2hvdWxkQmVCdXN5ICE9PSByZXN1bHQuaXNCdXN5KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucGhvbmVDb250cm9sLnNldEVycm9ycyh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJ2ZXJSZXNwb25zZTogW1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc2hvdWxkQmVCdXN5ID8gJ9Cf0L7Qu9GM0LfQvtCy0LDRgtC10LvRjyDRgSDRgtCw0LrQuNC8INC90L7QvNC10YDQvtC8INGC0LXQu9C10YTQvtC90LAg0L3QtSDRgdGD0YnQtdGB0YLQstGD0LXRgicgOiAn0J/QvtC70YzQt9C+0LLQsNGC0LXQu9GMINGBINGC0LDQutC40Lwg0L3QvtC80LXRgNC+0Lwg0YLQtdC70LXRhNC+0L3QsCDRg9C20LUg0YHRg9GJ0LXRgdGC0LLRg9C10YInLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucGhvbmVDb250cm9sLm1hcmtBc1RvdWNoZWQoKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuc2hvdWxkQmVDb25maXJtZWQgJiYgKHJlc3VsdC5pc0NvbmZpcm1lZCA9PT0gZmFsc2UgfHwgcmVzdWx0LmlzQ29uZmlybWVkID09PSBudWxsKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBob25lQ29udHJvbC5zZXRFcnJvcnMoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VydmVyUmVzcG9uc2U6IFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAn0JLRhdC+0LQg0L/QviDRg9C60LDQt9Cw0L3QvdC+0LzRgyDRgtC10LvQtdGE0L7QvdGDINC90LXQstC+0LfQvNC+0LbQtdC9LiDQntCx0YDQsNGC0LjRgtC10YHRjCDQuiDQstCw0YjQtdC80YMg0L/QtdGA0YHQvtC90LDQu9GM0L3QvtC80YMg0LzQtdC90LXQtNC20LXRgNGDINC40LvQuCDQstC+0LnQtNC40YLQtSDRgSDQuNGB0L/QvtC70YzQt9C+0LLQsNC90LjQtdC8IGUtbWFpbCDQuCDQv9Cw0YDQvtC70Y8uJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBob25lQ29udHJvbC5tYXJrQXNUb3VjaGVkKCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgICAgICAgICBjYXRjaEVycm9yKChlcnJvcjogSHR0cEVycm9yUmVzcG9uc2UpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBlcnJvclJlc3BvbnNlID0gZXJyb3IuZXJyb3IgYXMgQXBpRXJyb3JSZXNwb25zZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBob25lQ29udHJvbC5zZXRFcnJvcnMoeyBzZXJ2ZXJSZXNwb25zZTogZXJyb3JSZXNwb25zZT8uZXJyb3JzPy5bYHBob25lYF0gPz8gW2Vycm9yUmVzcG9uc2UubWVzc2FnZV0gfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9mKGZhbHNlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnRXaXRoKG51bGwpXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdGhpcy5zZXRIYXZlQ29kZShmYWxzZSk7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gb2YoZmFsc2UpO1xuICAgICAgICAgICAgfSksXG4gICAgICAgICAgICBzaGFyZSgpXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICog0KPRgdGC0LDQvdCw0LLQu9C40LLQsNC10YIg0YHQvtGB0YLQvtGP0L3QuNC1INC90LDQu9C40YfQuNGPINC60L7QtNCwINC/0L7QtNGC0LLQtdGA0LbQtNC10L3QuNGPINGDINC/0L7Qu9GM0LfQvtCy0LDRgtC10LvRjy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBoYXZlQ29kZSDQn9GA0LjQt9C90LDQuiDRgtC+0LPQviDQtdGB0YLRjCDQu9C4INC60L7QtCDQv9C+0LTRgtCy0LXRgNC20LTQtdC90LjRjyDQuNC70Lgg0L3QtdGCLlxuICAgICAqL1xuICAgIHB1YmxpYyBzZXRIYXZlQ29kZShoYXZlQ29kZTogYm9vbGVhbik6IHZvaWQge1xuICAgICAgICB0aGlzLmhhdmVDb2RlID0gaGF2ZUNvZGU7XG4gICAgICAgIHRoaXMuaGF2ZUNvZGVDaGFuZ2UuZW1pdChoYXZlQ29kZSk7XG4gICAgfVxufVxuIiwiPGZvcm0gW2Zvcm1Hcm91cF09XCJmb3JtXCIgKnR1aUxldD1cIihsb2FkaW5nQXBwcm92ZUNvZGUkIHwgYXN5bmMpIGFzIGxvYWRpbmdBcHByb3ZlQ29kZVwiIGNsYXNzPVwiZmxleCBmbGV4LWNvbCBnYXAtM1wiPlxuICAgIDxsYWJlbCB0dWlMYWJlbD1cItCd0L7QvNC10YAg0YLQtdC70LXRhNC+0L3QsFwiPlxuICAgICAgICA8dHVpLWlucHV0LXBob25lIGZvcm1Db250cm9sTmFtZT1cInBob25lXCIgW3R1aVRleHRmaWVsZEN1c3RvbUNvbnRlbnRdPVwiY2hlY2tpbmdQaG9uZVwiPlxuICAgICAgICAgICAg0J3QvtC80LXRgCDRgtC10LvQtdGE0L7QvdCwXG4gICAgICAgICAgICA8aW5wdXQgdHVpVGV4dGZpZWxkIGF1dG9jb21wbGV0ZT1cInBob25lXCIgLz5cbiAgICAgICAgPC90dWktaW5wdXQtcGhvbmU+XG4gICAgICAgIDx0dWktZXJyb3IgZm9ybUNvbnRyb2xOYW1lPVwicGhvbmVcIiBbZXJyb3JdPVwiW10gfCB0dWlGaWVsZEVycm9yIHwgYXN5bmNcIj48L3R1aS1lcnJvcj5cbiAgICA8L2xhYmVsPlxuXG4gICAgPGxhYmVsICpuZ0lmPVwibG9hZGluZ0FwcHJvdmVDb2RlID09PSBmYWxzZSAmJiBoYXZlQ29kZVwiIHR1aUxhYmVsPVwi0JrQvtC0INC40Lcg0KHQnNChXCI+XG4gICAgICAgIDx0dWktaW5wdXQgZm9ybUNvbnRyb2xOYW1lPVwicGhvbmVBcHByb3ZlQ29kZVwiPlxuICAgICAgICAgICAg0JrQvtC0INC40Lcg0KHQnNChXG4gICAgICAgICAgICA8aW5wdXQgdHVpVGV4dGZpZWxkIFttYXNraXRvXT1cImFwcHJvdmVDb2RlTWFza1wiIGF1dG9jb21wbGV0ZT1cIm5ldy1wYXNzd29yZFwiIC8+XG4gICAgICAgIDwvdHVpLWlucHV0PlxuICAgICAgICA8dHVpLWVycm9yIGZvcm1Db250cm9sTmFtZT1cInBob25lQXBwcm92ZUNvZGVcIiBbZXJyb3JdPVwiW10gfCB0dWlGaWVsZEVycm9yIHwgYXN5bmNcIj48L3R1aS1lcnJvcj5cbiAgICA8L2xhYmVsPlxuXG4gICAgPGRpdiAqdHVpTGV0PVwiISFsb2FkaW5nQXBwcm92ZUNvZGUgYXMgbG9hZGluZ0FwcHJvdmVDb2RlXCIgY2xhc3M9XCJmbGV4IGdhcC00IGp1c3RpZnktY2VudGVyXCI+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICpuZ0lmPVwiIWhhdmVDb2RlXCJcbiAgICAgICAgICAgIHR1aUJ1dHRvblxuICAgICAgICAgICAgc2l6ZT1cInNcIlxuICAgICAgICAgICAgKGNsaWNrKT1cIm9uU2VuZENvZGUubmV4dCgpXCJcbiAgICAgICAgICAgIFtkaXNhYmxlZF09XCJsb2FkaW5nQXBwcm92ZUNvZGUgfHwgISEhKHBob25lQ2hlY2skIHwgYXN5bmMpIHx8IHBob25lQ29udHJvbC5pbnZhbGlkXCJcbiAgICAgICAgICAgIFtzaG93TG9hZGVyXT1cImxvYWRpbmdBcHByb3ZlQ29kZVwiXG4gICAgICAgICAgICBpY29uPVwic2NJY29uTG9nSW5cIlxuICAgICAgICA+XG4gICAgICAgICAgICDQn9C+0LvRg9GH0LjRgtGMINC60L7QtFxuICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgPGJ1dHRvbiAqbmdJZj1cIiFsb2FkaW5nQXBwcm92ZUNvZGUgJiYgIWhhdmVDb2RlXCIgdHVpTGluayBbcHNldWRvXT1cInRydWVcIiBbZGlzYWJsZWRdPVwiISEhKHBob25lQ2hlY2skIHwgYXN5bmMpIHx8IHBob25lQ29udHJvbC5pbnZhbGlkXCIgKGNsaWNrKT1cInNldEhhdmVDb2RlKHRydWUpXCI+XG4gICAgICAgICAgICDQoyDQvNC10L3RjyDQtdGB0YLRjCDQutC+0LRcbiAgICAgICAgPC9idXR0b24+XG5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqdHVpTGV0PVwidGltZXIkIHwgYXN5bmMgYXMgdGltZXJcIj5cbiAgICAgICAgICAgIDx0dWktbG9hZGVyICpuZ0lmPVwiaGF2ZUNvZGVcIiBbc2hvd0xvYWRlcl09XCJsb2FkaW5nQXBwcm92ZUNvZGVcIj5cbiAgICAgICAgICAgICAgICA8YnV0dG9uIHR1aUxpbmsgW3BzZXVkb109XCJ0cnVlXCIgW2Rpc2FibGVkXT1cImxvYWRpbmdBcHByb3ZlQ29kZSB8fCB0aW1lclwiIChjbGljayk9XCJvblNlbmRDb2RlLm5leHQoKVwiPlxuICAgICAgICAgICAgICAgICAgICDQn9C+0LLRgtC+0YDQvdC+INC+0YLQv9GA0LDQstC40YLRjCDQutC+0LRcbiAgICAgICAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cInRpbWVyXCIgY2xhc3M9XCIhdGV4dC10dWktYmFzZS0wOFwiPijRh9C10YDQtdC3IHt7IHRpbWVyIH19KTwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgPC90dWktbG9hZGVyPlxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICA8L2Rpdj5cbjwvZm9ybT5cblxuPG5nLXRlbXBsYXRlICNjaGVja2luZ1Bob25lPlxuICAgIDx0dWktbG9hZGVyICpuZ0lmPVwiISEhKHBob25lQ2hlY2skIHwgYXN5bmMpICYmIHBob25lQ29udHJvbC52YWxpZFwiIGNsYXNzPVwidy00IGgtNFwiPiA8L3R1aS1sb2FkZXI+XG48L25nLXRlbXBsYXRlPlxuIl19
|