@snabcentr/client-ui 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +6 -6
- package/banner/sc-banner.component.d.ts +1 -1
- 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 +13 -12
- 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/profile/sc-profile-accordions-content/sc-profile-accordions-content.component.mjs +29 -16
- package/esm2020/user/index.mjs +2 -1
- package/esm2020/user/reset-user-password/sc-reset-user-password.component.mjs +4 -4
- package/esm2020/user/sc-user.module.mjs +6 -5
- package/esm2020/user/update-user-info-form/sc-update-user-info-form.component.mjs +7 -7
- 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 +163 -63
- package/fesm2015/snabcentr-client-ui.mjs.map +1 -1
- package/fesm2020/snabcentr-client-ui.mjs +160 -63
- package/fesm2020/snabcentr-client-ui.mjs.map +1 -1
- 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 +4 -0
- package/user/index.d.ts +1 -0
- package/user/reset-user-password/sc-reset-user-password.component.d.ts +3 -3
- package/user/sc-user.module.d.ts +9 -8
- package/user/update-user-info-form/sc-update-user-info-form.component.d.ts +1 -1
- 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} +13 -9
- package/esm2020/verification/phone-approve-form/phone-approve-form.component.mjs +0 -176
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@snabcentr/client-ui",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.10.0",
|
4
4
|
"author": "Snabcentr Ltd.",
|
5
5
|
"repository": "https://gitlab.snabcentr.met/web/angular/snabcentr-client-ui-lib",
|
6
6
|
"license": "Commercial",
|
@@ -14,7 +14,7 @@
|
|
14
14
|
"@angular/platform-browser": ">=14.2.12",
|
15
15
|
"@angular/platform-browser-dynamic": ">=14.2.12",
|
16
16
|
"@angular/material": ">=14.2.7",
|
17
|
-
"@snabcentr/client-core": "
|
17
|
+
"@snabcentr/client-core": ">=^0.8.0",
|
18
18
|
"@maskito/angular": ">=1.7.0",
|
19
19
|
"@maskito/core": ">=1.7.0",
|
20
20
|
"@taiga-ui/addon-charts": ">=3.42.1",
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { EventEmitter } from '@angular/core';
|
2
|
-
import { ScICity, ScLocationsService, ScUser, ScUserService } from '@snabcentr/client-core';
|
3
|
-
import { Observable } from 'rxjs';
|
2
|
+
import { ScICity, ScLocationsService, ScUser, ScUserService, ScVerificationService } from '@snabcentr/client-core';
|
3
|
+
import { Observable, Subject } from 'rxjs';
|
4
4
|
import { FormControl } from '@angular/forms';
|
5
5
|
import * as i0 from "@angular/core";
|
6
6
|
/**
|
@@ -10,18 +10,35 @@ export declare class ScProfileAccordionsContentComponent {
|
|
10
10
|
readonly user$: Observable<ScUser>;
|
11
11
|
private readonly locationsService;
|
12
12
|
private readonly userService;
|
13
|
+
private readonly verificationService;
|
13
14
|
/**
|
14
15
|
* {@link FormControl} переключателя 'Я хочу получать рассылку'.
|
15
16
|
*/
|
16
17
|
getNewsControl: FormControl<boolean>;
|
17
18
|
/**
|
18
|
-
* {@link Observable}
|
19
|
+
* {@link Observable} запроса изменения признака пользователя 'Я хочу получать рассылку'.
|
19
20
|
*/
|
20
21
|
private readonly getNewsRequest$;
|
21
22
|
/**
|
22
|
-
* {@link Observable}
|
23
|
+
* {@link Observable} изменения состояния загрузки данных изменения признака пользователя 'Я хочу получать рассылку'.
|
23
24
|
*/
|
24
25
|
readonly getNewsLoading$: Observable<boolean>;
|
26
|
+
/**
|
27
|
+
* {@link Subject} события отправки сообщения для подтверждения адреса электронной почты.
|
28
|
+
*/
|
29
|
+
readonly onSendApproveEmail: Subject<string>;
|
30
|
+
/**
|
31
|
+
* {@link Observable} запроса данных аутентификации.
|
32
|
+
*/
|
33
|
+
private readonly sendApproveEmailRequest$;
|
34
|
+
/**
|
35
|
+
* {@link Observable} изменения состояния загрузки данных отправки сообщения для подтверждения адреса электронной почты.
|
36
|
+
*/
|
37
|
+
readonly approveEmailLoading$: Observable<boolean>;
|
38
|
+
/**
|
39
|
+
* {@link Observable} изменения состояния признака, отправлено ли сообщение для подтверждения адреса электронной почты.
|
40
|
+
*/
|
41
|
+
readonly isSendApproveEmail$: Observable<boolean>;
|
25
42
|
/**
|
26
43
|
* Событие нажатия на кнопку редактирование контактного лица.
|
27
44
|
*/
|
@@ -30,10 +47,6 @@ export declare class ScProfileAccordionsContentComponent {
|
|
30
47
|
* Событие нажатия на кнопку подтверждения телефона.
|
31
48
|
*/
|
32
49
|
approvePhoneClick: EventEmitter<void>;
|
33
|
-
/**
|
34
|
-
* Событие нажатия на кнопку подтверждения электронной почты.
|
35
|
-
*/
|
36
|
-
approveEmailClick: EventEmitter<void>;
|
37
50
|
/**
|
38
51
|
* Событие нажатия на кнопку добавления контрагента.
|
39
52
|
*/
|
@@ -48,8 +61,9 @@ export declare class ScProfileAccordionsContentComponent {
|
|
48
61
|
* @param user$ Поток информации о текущем пользователе.
|
49
62
|
* @param locationsService Сервис для получения списков стран, регионов, городов.
|
50
63
|
* @param userService Сервис информации о пользователе.
|
64
|
+
* @param verificationService Сервис верификации.
|
51
65
|
*/
|
52
|
-
constructor(user$: Observable<ScUser>, locationsService: ScLocationsService, userService: ScUserService);
|
66
|
+
constructor(user$: Observable<ScUser>, locationsService: ScLocationsService, userService: ScUserService, verificationService: ScVerificationService);
|
53
67
|
/**
|
54
68
|
* Создает запрос получения информации о городе текущего пользователя по идентификатору города.
|
55
69
|
*
|
@@ -57,5 +71,5 @@ export declare class ScProfileAccordionsContentComponent {
|
|
57
71
|
*/
|
58
72
|
getUserCity$(cityId: number): Observable<ScICity>;
|
59
73
|
static ɵfac: i0.ɵɵFactoryDeclaration<ScProfileAccordionsContentComponent, never>;
|
60
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<ScProfileAccordionsContentComponent, "sc-profile-accordions-content", never, {}, { "editProfileClick": "editProfileClick"; "approvePhoneClick": "approvePhoneClick"; "
|
74
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ScProfileAccordionsContentComponent, "sc-profile-accordions-content", never, {}, { "editProfileClick": "editProfileClick"; "approvePhoneClick": "approvePhoneClick"; "addContragentClick": "addContragentClick"; "addDeliveryAddressClick": "addDeliveryAddressClick"; }, never, never, false>;
|
61
75
|
}
|
package/user/index.d.ts
CHANGED
@@ -16,15 +16,15 @@ export declare class ScResetUserPasswordComponent {
|
|
16
16
|
newPasswordConfirm: FormControl<null>;
|
17
17
|
}>;
|
18
18
|
/**
|
19
|
-
* {@link Subject}
|
19
|
+
* {@link Subject} события отправки формы.
|
20
20
|
*/
|
21
21
|
readonly onSubmit: Subject<void>;
|
22
22
|
/**
|
23
|
-
* {@link Observable}
|
23
|
+
* {@link Observable} запроса данных аутентификации.
|
24
24
|
*/
|
25
25
|
private readonly request$;
|
26
26
|
/**
|
27
|
-
* {@link Observable}
|
27
|
+
* {@link Observable} изменения состояния загрузки данных аутентификации по email.
|
28
28
|
*/
|
29
29
|
readonly loading$: Observable<boolean>;
|
30
30
|
/**
|
package/user/sc-user.module.d.ts
CHANGED
@@ -1,18 +1,19 @@
|
|
1
1
|
import * as i0 from "@angular/core";
|
2
2
|
import * as i1 from "./reset-user-password/sc-reset-user-password.component";
|
3
3
|
import * as i2 from "./update-user-info-form/sc-update-user-info-form.component";
|
4
|
-
import * as i3 from "
|
5
|
-
import * as i4 from "@angular/
|
6
|
-
import * as i5 from "@
|
7
|
-
import * as i6 from "@taiga-ui/
|
8
|
-
import * as i7 from "@taiga-ui/
|
9
|
-
import * as i8 from "
|
10
|
-
import * as i9 from "../
|
4
|
+
import * as i3 from "./user-phone-approve-dialog/sc-user-phone-approve-dialog.component";
|
5
|
+
import * as i4 from "@angular/common";
|
6
|
+
import * as i5 from "@angular/forms";
|
7
|
+
import * as i6 from "@taiga-ui/kit";
|
8
|
+
import * as i7 from "@taiga-ui/core";
|
9
|
+
import * as i8 from "@taiga-ui/cdk";
|
10
|
+
import * as i9 from "../verification/sc-verification.module";
|
11
|
+
import * as i10 from "../form-fields/form-fields.module";
|
11
12
|
/**
|
12
13
|
* Модуль компонентов пользователя.
|
13
14
|
*/
|
14
15
|
export declare class ScUserModule {
|
15
16
|
static ɵfac: i0.ɵɵFactoryDeclaration<ScUserModule, never>;
|
16
|
-
static ɵmod: i0.ɵɵNgModuleDeclaration<ScUserModule, [typeof i1.ScResetUserPasswordComponent, typeof i2.ScUpdateUserInfoFormComponent], [typeof
|
17
|
+
static ɵmod: i0.ɵɵNgModuleDeclaration<ScUserModule, [typeof i1.ScResetUserPasswordComponent, typeof i2.ScUpdateUserInfoFormComponent, typeof i3.ScUserPhoneApproveDialogComponent], [typeof i4.CommonModule, typeof i5.FormsModule, typeof i5.ReactiveFormsModule, typeof i6.TuiFieldErrorPipeModule, typeof i6.TuiInputPasswordModule, typeof i7.TuiButtonModule, typeof i7.TuiErrorModule, typeof i7.TuiLabelModule, typeof i7.TuiTextfieldControllerModule, typeof i8.TuiLetModule, typeof i9.ScVerificationModule, typeof i10.ScFormFieldsModule, typeof i7.TuiLoaderModule, typeof i6.TuiInputModule, typeof i6.TuiInputPhoneModule, typeof i6.TuiCheckboxModule, typeof i6.TuiCheckboxLabeledModule, typeof i7.TuiDataListModule, typeof i6.TuiSelectModule, typeof i7.TuiModeModule], [typeof i1.ScResetUserPasswordComponent, typeof i2.ScUpdateUserInfoFormComponent, typeof i3.ScUserPhoneApproveDialogComponent]>;
|
17
18
|
static ɵinj: i0.ɵɵInjectorDeclaration<ScUserModule>;
|
18
19
|
}
|
@@ -41,7 +41,7 @@ export declare class ScUpdateUserInfoFormComponent {
|
|
41
41
|
*/
|
42
42
|
private readonly request$;
|
43
43
|
/**
|
44
|
-
* {@link Observable}
|
44
|
+
* {@link Observable} изменения состояния загрузки данных аутентификации по email.
|
45
45
|
*/
|
46
46
|
readonly loading$: Observable<boolean>;
|
47
47
|
/**
|
@@ -0,0 +1,48 @@
|
|
1
|
+
import { FormGroup, FormControl } from '@angular/forms';
|
2
|
+
import { Subject, Observable } from 'rxjs';
|
3
|
+
import { ScApprovedData, ScUser, ScUserService, ScVerificationService } from '@snabcentr/client-core';
|
4
|
+
import { TuiDialogContext } from '@taiga-ui/core';
|
5
|
+
import * as i0 from "@angular/core";
|
6
|
+
/**
|
7
|
+
* Диалоговое окно подтверждения номера телефона.
|
8
|
+
*/
|
9
|
+
export declare class ScUserPhoneApproveDialogComponent {
|
10
|
+
private readonly verificationService;
|
11
|
+
readonly user$: Observable<ScUser>;
|
12
|
+
private readonly userService;
|
13
|
+
readonly context?: TuiDialogContext<ScApprovedData, ScUserPhoneApproveDialogComponent> | undefined;
|
14
|
+
/**
|
15
|
+
* Наличие кода подтверждения у пользователя.
|
16
|
+
*/
|
17
|
+
haveCode: boolean;
|
18
|
+
/**
|
19
|
+
* Группа полей ввода для подтверждения номера телефона.
|
20
|
+
*/
|
21
|
+
readonly form: FormGroup<{
|
22
|
+
phone: FormControl<string | null>;
|
23
|
+
verificationCode: FormControl<string | null>;
|
24
|
+
}>;
|
25
|
+
/**
|
26
|
+
* {@link Subject} события отправки формы.
|
27
|
+
*/
|
28
|
+
readonly onSubmit: Subject<void>;
|
29
|
+
/**
|
30
|
+
* {@link Observable} запроса подтверждения номера телефона.
|
31
|
+
*/
|
32
|
+
private readonly request$;
|
33
|
+
/**
|
34
|
+
* {@link Observable} изменения состояния запроса подтверждения номера телефона..
|
35
|
+
*/
|
36
|
+
readonly loading$: Observable<boolean>;
|
37
|
+
/**
|
38
|
+
* Инициализирует экземпляр класса {@link ScUserPhoneApproveDialogComponent}.
|
39
|
+
*
|
40
|
+
* @param verificationService Сервис верификации.
|
41
|
+
* @param user$ Поток информации о текущем пользователе.
|
42
|
+
* @param userService Сервис информации о пользователе.
|
43
|
+
* @param context Контекст диалогового окна, в котором открыт компонент.
|
44
|
+
*/
|
45
|
+
constructor(verificationService: ScVerificationService, user$: Observable<ScUser>, userService: ScUserService, context?: TuiDialogContext<ScApprovedData, ScUserPhoneApproveDialogComponent> | undefined);
|
46
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ScUserPhoneApproveDialogComponent, [null, null, null, { optional: true; }]>;
|
47
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ScUserPhoneApproveDialogComponent, "sc-user-phone-approve-dialog", never, {}, {}, never, never, false>;
|
48
|
+
}
|
package/verification/index.d.ts
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
export * from './phone-
|
1
|
+
export * from './verification-phone-check-form/sc-verification-phone-check-form.component';
|
2
2
|
export * from './sc-verification.module';
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import * as i0 from "@angular/core";
|
2
|
-
import * as i1 from "./phone-
|
2
|
+
import * as i1 from "./verification-phone-check-form/sc-verification-phone-check-form.component";
|
3
3
|
import * as i2 from "@angular/common";
|
4
4
|
import * as i3 from "@angular/forms";
|
5
5
|
import * as i4 from "@taiga-ui/kit";
|
@@ -11,6 +11,6 @@ import * as i7 from "@maskito/angular";
|
|
11
11
|
*/
|
12
12
|
export declare class ScVerificationModule {
|
13
13
|
static ɵfac: i0.ɵɵFactoryDeclaration<ScVerificationModule, never>;
|
14
|
-
static ɵmod: i0.ɵɵNgModuleDeclaration<ScVerificationModule, [typeof i1.
|
14
|
+
static ɵmod: i0.ɵɵNgModuleDeclaration<ScVerificationModule, [typeof i1.ScVerificationPhoneCheckFormComponent], [typeof i2.CommonModule, typeof i3.FormsModule, typeof i3.ReactiveFormsModule, typeof i4.TuiInputPasswordModule, typeof i4.TuiInputModule, typeof i5.TuiTextfieldControllerModule, typeof i5.TuiLinkModule, typeof i5.TuiButtonModule, typeof i5.TuiLabelModule, typeof i5.TuiModeModule, typeof i4.TuiFieldErrorPipeModule, typeof i5.TuiErrorModule, typeof i6.TuiLetModule, typeof i5.TuiLoaderModule, typeof i4.TuiInputPhoneModule, typeof i7.MaskitoModule], [typeof i1.ScVerificationPhoneCheckFormComponent]>;
|
15
15
|
static ɵinj: i0.ɵɵInjectorDeclaration<ScVerificationModule>;
|
16
16
|
}
|
@@ -7,7 +7,7 @@ import * as i0 from "@angular/core";
|
|
7
7
|
/**
|
8
8
|
* Компонент формы проверки телефона и получения кода подтверждения.
|
9
9
|
*/
|
10
|
-
export declare class
|
10
|
+
export declare class ScVerificationPhoneCheckFormComponent implements OnInit {
|
11
11
|
private readonly verificationService;
|
12
12
|
private readonly formGroupDirective?;
|
13
13
|
/**
|
@@ -22,6 +22,10 @@ export declare class ScPhoneApproveFormComponent implements OnInit {
|
|
22
22
|
* Признак, следует ли отображать функционал кода подтверждения.
|
23
23
|
*/
|
24
24
|
get showCodeFields(): boolean;
|
25
|
+
/**
|
26
|
+
* Признак, что поле ввода телефона только для чтения.
|
27
|
+
*/
|
28
|
+
readOnly: boolean;
|
25
29
|
/**
|
26
30
|
* Признак, следует ли телефону быть в системе. От этого признака зависит в каких случаях выдавать ошибку при проверки занятости телефона.
|
27
31
|
*/
|
@@ -29,7 +33,7 @@ export declare class ScPhoneApproveFormComponent implements OnInit {
|
|
29
33
|
/**
|
30
34
|
* Признак, следует ли проверять подтверждён ли телефона в системе. При `true` будет вызывать ошибку при наличие телефона в системе без подтверждения.
|
31
35
|
*/
|
32
|
-
shouldBeConfirmed
|
36
|
+
shouldBeConfirmed?: boolean;
|
33
37
|
/**
|
34
38
|
* Наличие кода подтверждения у пользователя.
|
35
39
|
*/
|
@@ -50,15 +54,15 @@ export declare class ScPhoneApproveFormComponent implements OnInit {
|
|
50
54
|
*/
|
51
55
|
get phoneControl(): FormControl<string | null>;
|
52
56
|
/**
|
53
|
-
* {@link Observable}
|
57
|
+
* {@link Observable} запроса проверки номера телефона.
|
54
58
|
*/
|
55
59
|
phoneCheck$?: Observable<boolean | null>;
|
56
60
|
/**
|
57
|
-
* {@link Subject}
|
61
|
+
* {@link Subject} события отправки кода подтверждения.
|
58
62
|
*/
|
59
63
|
readonly onSendCode: Subject<void>;
|
60
64
|
/**
|
61
|
-
* {@link Observable}
|
65
|
+
* {@link Observable} запроса данных получения кода подтверждения.
|
62
66
|
*/
|
63
67
|
readonly loadingApproveCode$: Observable<boolean>;
|
64
68
|
/**
|
@@ -66,7 +70,7 @@ export declare class ScPhoneApproveFormComponent implements OnInit {
|
|
66
70
|
*/
|
67
71
|
readonly verificationCodeMask: MaskitoOptions;
|
68
72
|
/**
|
69
|
-
* {@link Subject}
|
73
|
+
* {@link Subject} события запуска/остановки таймера.
|
70
74
|
*/
|
71
75
|
readonly reloadTimer$: Subject<number>;
|
72
76
|
/**
|
@@ -76,7 +80,7 @@ export declare class ScPhoneApproveFormComponent implements OnInit {
|
|
76
80
|
*/
|
77
81
|
readonly timer$: Observable<string | null>;
|
78
82
|
/**
|
79
|
-
* Инициализирует экземпляр класса {@link
|
83
|
+
* Инициализирует экземпляр класса {@link ScVerificationPhoneCheckFormComponent}.
|
80
84
|
*
|
81
85
|
* @param verificationService Сервис верификации.
|
82
86
|
* @param formGroupDirective Директива c `FormGroup` из DOM.
|
@@ -90,6 +94,6 @@ export declare class ScPhoneApproveFormComponent implements OnInit {
|
|
90
94
|
* @param haveCode Признак того есть ли код подтверждения или нет.
|
91
95
|
*/
|
92
96
|
setHaveCode(haveCode: boolean): void;
|
93
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<
|
94
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<
|
97
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ScVerificationPhoneCheckFormComponent, never>;
|
98
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ScVerificationPhoneCheckFormComponent, "sc-verification-phone-check-form", never, { "showCodeFields": "showCodeFields"; "readOnly": "readOnly"; "shouldBeBusy": "shouldBeBusy"; "shouldBeConfirmed": "shouldBeConfirmed"; "haveCode": "haveCode"; }, { "haveCodeChange": "haveCodeChange"; }, never, never, false>;
|
95
99
|
}
|
@@ -1,176 +0,0 @@
|
|
1
|
-
import { ChangeDetectionStrategy, Component, EventEmitter, Inject, Input, Output } from '@angular/core';
|
2
|
-
import { FormGroupDirective } from '@angular/forms';
|
3
|
-
import { verificationCodeMask } 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._showCodeFields = true;
|
31
|
-
/**
|
32
|
-
* Признак, следует ли телефону быть в системе. От этого признака зависит в каких случаях выдавать ошибку при проверки занятости телефона.
|
33
|
-
*/
|
34
|
-
this.shouldBeBusy = true;
|
35
|
-
/**
|
36
|
-
* Признак, следует ли проверять подтверждён ли телефона в системе. При `true` будет вызывать ошибку при наличие телефона в системе без подтверждения.
|
37
|
-
*/
|
38
|
-
this.shouldBeConfirmed = false;
|
39
|
-
/**
|
40
|
-
* Наличие кода подтверждения у пользователя.
|
41
|
-
*/
|
42
|
-
this.haveCode = false;
|
43
|
-
/**
|
44
|
-
* Событие для обратной привязки наличия кода подтверждения
|
45
|
-
*/
|
46
|
-
this.haveCodeChange = new EventEmitter();
|
47
|
-
/**
|
48
|
-
* {@link Subject} События отправки кода подтверждения.
|
49
|
-
*/
|
50
|
-
this.onSendCode = new Subject();
|
51
|
-
/**
|
52
|
-
* {@link Observable} Запроса данных получения кода подтверждения.
|
53
|
-
*/
|
54
|
-
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) => {
|
55
|
-
const errorResponse = error.error;
|
56
|
-
const regex = /(\d{2}):\d{2}/;
|
57
|
-
const match = errorResponse.message.match(regex);
|
58
|
-
if (match && match.length > 1) {
|
59
|
-
const timeParts = match[0].split(':');
|
60
|
-
const seconds = parseInt(timeParts[1], 10);
|
61
|
-
this.reloadTimer$.next(seconds);
|
62
|
-
}
|
63
|
-
else {
|
64
|
-
this.phoneControl.setErrors({ serverResponse: errorResponse?.errors?.[`phone`] ?? [errorResponse.message] });
|
65
|
-
}
|
66
|
-
return of(false);
|
67
|
-
}), finalize(() => this.setHaveCode(true)), startWith(true))), startWith(false), share());
|
68
|
-
/**
|
69
|
-
* Маска поля ввода кода для подтверждения.
|
70
|
-
*/
|
71
|
-
this.verificationCodeMask = verificationCodeMask;
|
72
|
-
/**
|
73
|
-
* {@link Subject} События запуска/остановки таймера.
|
74
|
-
*/
|
75
|
-
this.reloadTimer$ = new Subject();
|
76
|
-
/**
|
77
|
-
* {@link Observable} Таймера.
|
78
|
-
*
|
79
|
-
* TODO: Вынести таймер в отдельную директиву TASK:[#9260].
|
80
|
-
*/
|
81
|
-
this.timer$ = this.reloadTimer$.pipe(switchMap((sec) => timer(0, 1000).pipe(scan((total) => --total, sec), takeWhile((total) => total >= 0), map((total) => {
|
82
|
-
const minutes = Math.floor(total / 60);
|
83
|
-
const seconds = total % 60;
|
84
|
-
return `${Math.round(minutes).toString().padStart(2, '0')}:${Math.round(seconds).toString().padStart(2, '0')}`;
|
85
|
-
}), endWith(null), startWith(null), distinctUntilChanged())));
|
86
|
-
}
|
87
|
-
/**
|
88
|
-
* Признак, следует ли отображать функционал кода подтверждения.
|
89
|
-
*/
|
90
|
-
set showCodeFields(showCodeFields) {
|
91
|
-
this._showCodeFields = showCodeFields;
|
92
|
-
this.form.controls.verificationCode[showCodeFields ? 'enable' : 'disable']();
|
93
|
-
}
|
94
|
-
/**
|
95
|
-
* Признак, следует ли отображать функционал кода подтверждения.
|
96
|
-
*/
|
97
|
-
get showCodeFields() {
|
98
|
-
return this._showCodeFields;
|
99
|
-
}
|
100
|
-
/**
|
101
|
-
* Группа полей ввода для формы «Вход на сайт».
|
102
|
-
*/
|
103
|
-
get form() {
|
104
|
-
return this.formGroupDirective?.form;
|
105
|
-
}
|
106
|
-
/**
|
107
|
-
* Поле ввода 'Номер телефона'.
|
108
|
-
*/
|
109
|
-
get phoneControl() {
|
110
|
-
return this.form?.controls.phone;
|
111
|
-
}
|
112
|
-
/** @inheritDoc */
|
113
|
-
ngOnInit() {
|
114
|
-
this.phoneCheck$ = tuiControlValue(this.phoneControl).pipe(tap(() => this.reloadTimer$.next(0)), switchMap((value) => {
|
115
|
-
if (this.phoneControl.valid && !!value) {
|
116
|
-
return this.verificationService.getPhoneCheck$(value).pipe(map((result) => {
|
117
|
-
if (this.shouldBeBusy !== result.isBusy) {
|
118
|
-
this.phoneControl.setErrors({
|
119
|
-
serverResponse: [
|
120
|
-
this.shouldBeBusy ? 'Пользователя с таким номером телефона не существует' : 'Пользователь с таким номером телефона уже существует',
|
121
|
-
],
|
122
|
-
});
|
123
|
-
this.phoneControl.markAsTouched();
|
124
|
-
return false;
|
125
|
-
}
|
126
|
-
if (this.shouldBeConfirmed && (result.isConfirmed === false || result.isConfirmed === null)) {
|
127
|
-
this.phoneControl.setErrors({
|
128
|
-
serverResponse: [
|
129
|
-
'Вход по указанному телефону невозможен. Обратитесь к вашему персональному менеджеру или войдите с использованием e-mail и пароля.',
|
130
|
-
],
|
131
|
-
});
|
132
|
-
this.phoneControl.markAsTouched();
|
133
|
-
return false;
|
134
|
-
}
|
135
|
-
return true;
|
136
|
-
}), catchError((error) => {
|
137
|
-
const errorResponse = error.error;
|
138
|
-
this.phoneControl.setErrors({ serverResponse: errorResponse?.errors?.[`phone`] ?? [errorResponse.message] });
|
139
|
-
return of(false);
|
140
|
-
}), startWith(null));
|
141
|
-
}
|
142
|
-
this.setHaveCode(false);
|
143
|
-
return of(false);
|
144
|
-
}), share());
|
145
|
-
this.setHaveCode(false);
|
146
|
-
}
|
147
|
-
/**
|
148
|
-
* Устанавливает состояние наличия кода подтверждения у пользователя.
|
149
|
-
*
|
150
|
-
* @param haveCode Признак того есть ли код подтверждения или нет.
|
151
|
-
*/
|
152
|
-
setHaveCode(haveCode) {
|
153
|
-
this.haveCode = haveCode;
|
154
|
-
this.haveCodeChange.emit(haveCode);
|
155
|
-
}
|
156
|
-
}
|
157
|
-
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 });
|
158
|
-
ScPhoneApproveFormComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: ScPhoneApproveFormComponent, selector: "sc-phone-approve-form", inputs: { showCodeFields: "showCodeFields", 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 <ng-container *ngIf=\"showCodeFields\">\n <label *ngIf=\"loadingApproveCode === false && haveCode\" tuiLabel=\"\u041A\u043E\u0434 \u0438\u0437 \u0421\u041C\u0421\">\n <tui-input formControlName=\"verificationCode\">\n \u041A\u043E\u0434 \u0438\u0437 \u0421\u041C\u0421\n <input tuiTextfield [maskito]=\"verificationCodeMask\" autocomplete=\"new-password\" />\n </tui-input>\n <tui-error formControlName=\"verificationCode\" [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 </ng-container>\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 });
|
159
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ScPhoneApproveFormComponent, decorators: [{
|
160
|
-
type: Component,
|
161
|
-
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 <ng-container *ngIf=\"showCodeFields\">\n <label *ngIf=\"loadingApproveCode === false && haveCode\" tuiLabel=\"\u041A\u043E\u0434 \u0438\u0437 \u0421\u041C\u0421\">\n <tui-input formControlName=\"verificationCode\">\n \u041A\u043E\u0434 \u0438\u0437 \u0421\u041C\u0421\n <input tuiTextfield [maskito]=\"verificationCodeMask\" autocomplete=\"new-password\" />\n </tui-input>\n <tui-error formControlName=\"verificationCode\" [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 </ng-container>\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" }]
|
162
|
-
}], ctorParameters: function () { return [{ type: i1.ScVerificationService }, { type: i3.FormGroupDirective, decorators: [{
|
163
|
-
type: Inject,
|
164
|
-
args: [FormGroupDirective]
|
165
|
-
}] }]; }, propDecorators: { showCodeFields: [{
|
166
|
-
type: Input
|
167
|
-
}], shouldBeBusy: [{
|
168
|
-
type: Input
|
169
|
-
}], shouldBeConfirmed: [{
|
170
|
-
type: Input
|
171
|
-
}], haveCode: [{
|
172
|
-
type: Input
|
173
|
-
}], haveCodeChange: [{
|
174
|
-
type: Output
|
175
|
-
}] } });
|
176
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGhvbmUtYXBwcm92ZS1mb3JtLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2NsaWVudC11aS92ZXJpZmljYXRpb24vcGhvbmUtYXBwcm92ZS1mb3JtL3Bob25lLWFwcHJvdmUtZm9ybS5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9jbGllbnQtdWkvdmVyaWZpY2F0aW9uL3Bob25lLWFwcHJvdmUtZm9ybS9waG9uZS1hcHByb3ZlLWZvcm0uY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLHVCQUF1QixFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBVSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDaEgsT0FBTyxFQUEwQixrQkFBa0IsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRzVFLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDhDQUE4QyxDQUFDO0FBRXBGLE9BQU8sRUFBRSxPQUFPLEVBQWMsTUFBTSxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzNLLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxlQUFlLENBQUM7Ozs7Ozs7OztBQUVoRDs7R0FFRztBQU1ILE1BQU0sT0FBTywyQkFBMkI7SUFnSnBDOzs7OztPQUtHO0lBQ0gsWUFDcUIsbUJBQTBDLEVBRTFDLGtCQUF1QztRQUZ2Qyx3QkFBbUIsR0FBbkIsbUJBQW1CLENBQXVCO1FBRTFDLHVCQUFrQixHQUFsQixrQkFBa0IsQ0FBcUI7UUF4SjVEOztXQUVHO1FBQ0ssb0JBQWUsR0FBWSxJQUFJ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LENBQUMsS0FBeUIsQ0FBQztvQkFDdEQsSUFBSSxDQUFDLFlBQVksQ0FBQyxTQUFTLENBQUMsRUFBRSxjQUFjLEVBQUUsYUFBYSxFQUFFLE1BQU0sRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQztvQkFDN0csT0FBTyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQ3JCLENBQUMsQ0FBQyxFQUNGLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FDbEIsQ0FBQzthQUNMO1lBRUQsSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUV4QixPQUFPLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNyQixDQUFDLENBQUMsRUFDRixLQUFLLEVBQUUsQ0FDVixDQUFDO1FBRUYsSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUM1QixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLFdBQVcsQ0FBQyxRQUFpQjtRQUNoQyxJQUFJLENBQUMsUUFBUSxHQUFHLFFBQVEsQ0FBQztRQUN6QixJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUN2QyxDQUFDOzt3SEF2TlEsMkJBQTJCLHVEQXdKeEIsa0JBQWtCOzRHQXhKckIsMkJBQTJCLHNQQ2xCeEMsNDNGQWdEQTsyRkQ5QmEsMkJBQTJCO2tCQUx2QyxTQUFTOytCQUNJLHVCQUF1QixtQkFFaEIsdUJBQXVCLENBQUMsTUFBTTs7MEJBMEoxQyxNQUFNOzJCQUFDLGtCQUFrQjs0Q0E5SW5CLGNBQWM7c0JBRHhCLEtBQUs7Z0JBaUJDLFlBQVk7c0JBRGxCLEtBQUs7Z0JBT0MsaUJBQWlCO3NCQUR2QixLQUFLO2dCQU9DLFFBQVE7c0JBRGQsS0FBSztnQkFPQyxjQUFjO3NCQURwQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSHR0cEVycm9yUmVzcG9uc2UgfSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCc7XG5pbXBvcnQgeyBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSwgQ29tcG9uZW50LCBFdmVudEVtaXR0ZXIsIEluamVjdCwgSW5wdXQsIE9uSW5pdCwgT3V0cHV0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBGb3JtR3JvdXAsIEZvcm1Db250cm9sLCBGb3JtR3JvdXBEaXJlY3RpdmUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBNYXNraXRvT3B0aW9ucyB9IGZyb20gJ0BtYXNraXRvL2NvcmUnO1xuaW1wb3J0IHsgU2NWZXJpZmljYXRpb25TZXJ2aWNlIH0gZnJvbSAnQHNuYWJjZW50ci9jbGllbnQtY29yZSc7XG5pbXBvcnQgeyB2ZXJpZmljYXRpb25Db2RlTWFzayB9IGZyb20gJy4uLy4uL2F1dGgvY29uc3RhbnRzL3Bob25lLWFwcHJvdmUtY29kZS1tYXNrJztcbmltcG9ydCB7IEFwaUVycm9yUmVzcG9uc2UgfSBmcm9tICcuLi8uLi9hdXRoL2ludGVyZmFjZXMvQXBpRXJyb3JSZXNwb25zZSc7XG5pbXBvcnQgeyBTdWJqZWN0LCBPYnNlcnZhYmxlLCBmaWx0ZXIsIG1hcCwgc3dpdGNoTWFwLCBjYXRjaEVycm9yLCBvZiwgc3RhcnRXaXRoLCBzaGFyZSwgdGFwLCBmaW5hbGl6ZSwgdGltZXIsIHNjYW4sIHRha2VXaGlsZSwgZW5kV2l0aCwgZGlzdGluY3RVbnRpbENoYW5nZWQgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IHR1aUNvbnRyb2xWYWx1ZSB9IGZyb20gJ0B0YWlnYS11aS9jZGsnO1xuXG4vKipcbiAqINCa0L7QvNC/0L7QvdC10L3RgiDRhNC+0YDQvNGLINC/0YDQvtCy0LXRgNC60Lgg0YLQtdC70LXRhNC+0L3QsCDQuCDQv9C+0LvRg9GH0LXQvdC40Y8g0LrQvtC00LAg0L/QvtC00YLQstC10YDQttC00LXQvdC40Y8uXG4gKi9cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAnc2MtcGhvbmUtYXBwcm92ZS1mb3JtJyxcbiAgICB0ZW1wbGF0ZVVybDogJy4vcGhvbmUtYXBwcm92ZS1mb3JtLmNvbXBvbmVudC5odG1sJyxcbiAgICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbn0pXG5leHBvcnQgY2xhc3MgU2NQaG9uZUFwcHJvdmVGb3JtQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcbiAgICAvKipcbiAgICAgKiDQn9GA0LjQt9C90LDQuiwg0YHQu9C10LTRg9C10YIg0LvQuCDQvtGC0L7QsdGA0LDQttCw0YLRjCDRhNGD0L3QutGG0LjQvtC90LDQuyDQutC+0LTQsCDQv9C+0LTRgtCy0LXRgNC20LTQtdC90LjRjy5cbiAgICAgKi9cbiAgICBwcml2YXRlIF9zaG93Q29kZUZpZWxkczogYm9vbGVhbiA9IHRydWU7XG5cbiAgICAvKipcbiAgICAgKiDQn9GA0LjQt9C90LDQuiwg0YHQu9C10LTRg9C10YIg0LvQuCDQvtGC0L7QsdGA0LDQttCw0YLRjCDRhNGD0L3QutGG0LjQvtC90LDQuyDQutC+0LTQsCDQv9C+0LTRgtCy0LXRgNC20LTQtdC90LjRjy5cbiAgICAgKi9cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBzZXQgc2hvd0NvZGVGaWVsZHMoc2hvd0NvZGVGaWVsZHM6IGJvb2xlYW4pIHtcbiAgICAgICAgdGhpcy5fc2hvd0NvZGVGaWVsZHMgPSBzaG93Q29kZUZpZWxkcztcbiAgICAgICAgdGhpcy5mb3JtLmNvbnRyb2xzLnZlcmlmaWNhdGlvbkNvZGVbc2hvd0NvZGVGaWVsZHMgPyAnZW5hYmxlJyA6ICdkaXNhYmxlJ10oKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiDQn9GA0LjQt9C90LDQuiwg0YHQu9C10LTRg9C10YIg0LvQuCDQvtGC0L7QsdGA0LDQttCw0YLRjCDRhNGD0L3QutGG0LjQvtC90LDQuyDQutC+0LTQsCDQv9C+0LTRgtCy0LXRgNC20LTQtdC90LjRjy5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IHNob3dDb2RlRmllbGRzKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5fc2hvd0NvZGVGaWVsZHM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICog0J/RgNC40LfQvdCw0LosINGB0LvQtdC00YPQtdGCINC70Lgg0YLQtdC70LXRhNC+0L3RgyDQsdGL0YLRjCDQsiDRgdC40YHRgtC10LzQtS4g0J7RgiDRjdGC0L7Qs9C+INC/0YDQuNC30L3QsNC60LAg0LfQsNCy0LjRgdC40YIg0LIg0LrQsNC60LjRhSDRgdC70YPRh9Cw0Y/RhSDQstGL0LTQsNCy0LDRgtGMINC+0YjQuNCx0LrRgyDQv9GA0Lgg0L/RgNC+0LLQtdGA0LrQuCDQt9Cw0L3Rj9GC0L7RgdGC0Lgg0YLQtdC70LXRhNC+0L3QsC5cbiAgICAgKi9cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBzaG91bGRCZUJ1c3k6IGJvb2xlYW4gPSB0cnVlO1xuXG4gICAgLyoqXG4gICAgICog0J/RgNC40LfQvdCw0LosINGB0LvQtdC00YPQtdGCINC70Lgg0L/RgNC+0LLQtdGA0Y/RgtGMINC/0L7QtNGC0LLQtdGA0LbQtNGR0L0g0LvQuCDRgtC10LvQtdGE0L7QvdCwINCyINGB0LjRgdGC0LXQvNC1LiDQn9GA0LggYHRydWVgINCx0YPQtNC10YIg0LLRi9C30YvQstCw0YLRjCDQvtGI0LjQsdC60YMg0L/RgNC4INC90LDQu9C40YfQuNC1INGC0LXQu9C10YTQvtC90LAg0LIg0YHQuNGB0YLQtdC80LUg0LHQtdC3INC/0L7QtNGC0LLQtdGA0LbQtNC10L3QuNGPLlxuICAgICAqL1xuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIHNob3VsZEJlQ29uZmlybWVkOiBib29sZWFuID0gZmFsc2U7XG5cbiAgICAvKipcbiAgICAgKiDQndCw0LvQuNGH0LjQtSDQutC+0LTQsCDQv9C+0LTRgtCy0LXRgNC20LTQtdC90LjRjyDRgyDQv9C+0LvRjNC30L7QstCw0YLQtdC70Y8uXG4gICAgICovXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgaGF2ZUNvZGU6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIC8qKlxuICAgICAqINCh0L7QsdGL0YLQuNC1INC00LvRjyDQvtCx0YDQsNGC0L3QvtC5INC/0YDQuNCy0Y/Qt9C60Lgg0L3QsNC70LjRh9C40Y8g0LrQvtC00LAg0L/QvtC00YLQstC10YDQttC00LXQvdC40Y9cbiAgICAgKi9cbiAgICBAT3V0cHV0KClcbiAgICBwdWJsaWMgaGF2ZUNvZGVDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XG5cbiAgICAvKipcbiAgICAgKiDQk9GA0YPQv9C/0LAg0L/QvtC70LXQuSDQstCy0L7QtNCwINC00LvRjyDRhNC+0YDQvNGLIMKr0JLRhdC+0LQg0L3QsCDRgdCw0LnRgsK7LlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgZm9ybSgpOiBGb3JtR3JvdXA8e1xuICAgICAgICBwaG9uZTogRm9ybUNvbnRyb2w8c3RyaW5nIHwgbnVsbD47XG4gICAgICAgIHZlcmlmaWNhdGlvbkNvZGU6IEZvcm1Db250cm9sPHN0cmluZyB8IG51bGw+O1xuICAgIH0+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZm9ybUdyb3VwRGlyZWN0aXZlPy5mb3JtIGFzIEZvcm1Hcm91cDx7XG4gICAgICAgICAgICBwaG9uZTogRm9ybUNvbnRyb2w8c3RyaW5nIHwgbnVsbD47XG4gICAgICAgICAgICB2ZXJpZmljYXRpb25Db2RlOiBGb3JtQ29udHJvbDxzdHJpbmcgfCBudWxsPjtcbiAgICAgICAgfT47XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICog0J/QvtC70LUg0LLQstC+0LTQsCAn0J3QvtC80LXRgCDRgtC10LvQtdGE0L7QvdCwJy5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IHBob25lQ29udHJvbCgpOiBGb3JtQ29udHJvbDxzdHJpbmcgfCBudWxsPiB7XG4gICAgICAgIHJldHVybiB0aGlzLmZvcm0/LmNvbnRyb2xzLnBob25lO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIHtAbGluayBPYnNlcnZhYmxlfSDQl9Cw0L/RgNC+0YHQsCDQv9GA0L7QstC10YDQutC4INC90L7QvNC10YDQsCDRgtC10LvQtdGE0L7QvdCwLlxuICAgICAqL1xuICAgIHB1YmxpYyBwaG9uZUNoZWNrJD86IE9ic2VydmFibGU8Ym9vbGVhbiB8IG51bGw+O1xuXG4gICAgLyoqXG4gICAgICoge0BsaW5rIFN1YmplY3R9INCh0L7QsdGL0YLQuNGPINC+0YLQv9GA0LDQstC60Lgg0LrQvtC00LAg0L/QvtC00YLQstC10YDQttC00LXQvdC40Y8uXG4gICAgICovXG4gICAgcHVibGljIHJlYWRvbmx5IG9uU2VuZENvZGU6IFN1YmplY3Q8dm9pZD4gPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gICAgLyoqXG4gICAgICoge0BsaW5rIE9ic2VydmFibGV9INCX0LDQv9GA0L7RgdCwINC00LDQvdC90YvRhSDQv9C+0LvRg9GH0LXQvdC40Y8g0LrQvtC00LAg0L/QvtC00YLQstC10YDQttC00LXQvdC40Y8uXG4gICAgICovXG4gICAgcHVibGljIHJlYWRvbmx5IGxvYWRpbmdBcHByb3ZlQ29kZSQ6IE9ic2VydmFibGU8Ym9vbGVhbj4gPSB0aGlzLm9uU2VuZENvZGUucGlwZShcbiAgICAgICAgZmlsdGVyKCgpID0+IHRoaXMucGhvbmVDb250cm9sLnZhbGlkKSxcbiAgICAgICAgbWFwKCgpID0+IHRoaXMucGhvbmVDb250cm9sLnZhbHVlIGFzIHN0cmluZyksXG4gICAgICAgIHN3aXRjaE1hcCgodmFsdWUpID0+XG4gICAgICAgICAgICB0aGlzLnZlcmlmaWNhdGlvblNlcnZpY2Uuc2VuZFBob25lQXBwcm92ZUNvZGUodmFsdWUpLnBpcGUoXG4gICAgICAgICAgICAgICAgdGFwKCgpID0+IHRoaXMucmVsb2FkVGltZXIkLm5leHQoNjApKSxcbiAgICAgICAgICAgICAgICBtYXAoKCkgPT4gZmFsc2UpLFxuICAgICAgICAgICAgICAgIGNhdGNoRXJyb3IoKGVycm9yOiBIdHRwRXJyb3JSZXNwb25zZSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBlcnJvclJlc3BvbnNlID0gZXJyb3IuZXJyb3IgYXMgQXBpRXJyb3JSZXNwb25zZTtcblxuICAgICAgICAgICAgICAgICAgICBjb25zdCByZWdleCA9IC8oXFxkezJ9KTpcXGR7Mn0vO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBtYXRjaCA9IGVycm9yUmVzcG9uc2UubWVzc2FnZS5tYXRjaChyZWdleCk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKG1hdGNoICYmIG1hdGNoLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHRpbWVQYXJ0cyA9IG1hdGNoWzBdLnNwbGl0KCc6Jyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBzZWNvbmRzID0gcGFyc2VJbnQodGltZVBhcnRzWzFdLCAxMCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucmVsb2FkVGltZXIkLm5leHQoc2Vjb25kcyk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBob25lQ29udHJvbC5zZXRFcnJvcnMoeyBzZXJ2ZXJSZXNwb25zZTogZXJyb3JSZXNwb25zZT8uZXJyb3JzPy5bYHBob25lYF0gPz8gW2Vycm9yUmVzcG9uc2UubWVzc2FnZV0gfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gb2YoZmFsc2UpO1xuICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgIGZpbmFsaXplKCgpID0+IHRoaXMuc2V0SGF2ZUNvZGUodHJ1ZSkpLFxuICAgICAgICAgICAgICAgIHN0YXJ0V2l0aCh0cnVlKVxuICAgICAgICAgICAgKVxuICAgICAgICApLFxuICAgICAgICBzdGFydFdpdGgoZmFsc2UpLFxuICAgICAgICBzaGFyZSgpXG4gICAgKTtcblxuICAgIC8qKlxuICAgICAqINCc0LDRgdC60LAg0L/QvtC70Y8g0LLQstC+0LTQsCDQutC+0LTQsCDQtNC70Y8g0L/QvtC00YLQstC10YDQttC00LXQvdC40Y8uXG4gICAgICovXG4gICAgcHVibGljIHJlYWRvbmx5IHZlcmlmaWNhdGlvbkNvZGVNYXNrOiBNYXNraXRvT3B0aW9ucyA9IHZlcmlmaWNhdGlvbkNvZGVNYXNrO1xuXG4gICAgLyoqXG4gICAgICoge0BsaW5rIFN1YmplY3R9INCh0L7QsdGL0YLQuNGPINC30LDQv9GD0YHQutCwL9C+0YHRgtCw0L3QvtCy0LrQuCDRgtCw0LnQvNC10YDQsC5cbiAgICAgKi9cbiAgICBwdWJsaWMgcmVhZG9ubHkgcmVsb2FkVGltZXIkOiBTdWJqZWN0PG51bWJlcj4gPSBuZXcgU3ViamVjdDxudW1iZXI+KCk7XG5cbiAgICAvKipcbiAgICAgKiB7QGxpbmsgT2JzZXJ2YWJsZX0g0KLQsNC50LzQtdGA0LAuXG4gICAgICpcbiAgICAgKiBUT0RPOiDQktGL0L3QtdGB0YLQuCDRgtCw0LnQvNC10YAg0LIg0L7RgtC00LXQu9GM0L3Rg9GOINC00LjRgNC10LrRgtC40LLRgyBUQVNLOlsjOTI2MF0uXG4gICAgICovXG4gICAgcHVibGljIHJlYWRvbmx5IHRpbWVyJDogT2JzZXJ2YWJsZTxzdHJpbmcgfCBudWxsPiA9IHRoaXMucmVsb2FkVGltZXIkLnBpcGUoXG4gICAgICAgIHN3aXRjaE1hcCgoc2VjKSA9PlxuICAgICAgICAgICAgdGltZXIoMCwgMTAwMCkucGlwZShcbiAgICAgICAgICAgICAgICBzY2FuKCh0b3RhbCkgPT4gLS10b3RhbCwgc2VjKSxcbiAgICAgICAgICAgICAgICB0YWtlV2hpbGUoKHRvdGFsKSA9PiB0b3RhbCA+PSAwKSxcbiAgICAgICAgICAgICAgICBtYXAoKHRvdGFsKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG1pbnV0ZXMgPSBNYXRoLmZsb29yKHRvdGFsIC8gNjApO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBzZWNvbmRzID0gdG90YWwgJSA2MDtcblxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYCR7TWF0aC5yb3VuZChtaW51dGVzKS50b1N0cmluZygpLnBhZFN0YXJ0KDIsICcwJyl9OiR7TWF0aC5yb3VuZChzZWNvbmRzKS50b1N0cmluZygpLnBhZFN0YXJ0KDIsICcwJyl9YDtcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICBlbmRXaXRoKG51bGwpLFxuICAgICAgICAgICAgICAgIHN0YXJ0V2l0aChudWxsKSxcbiAgICAgICAgICAgICAgICBkaXN0aW5jdFVudGlsQ2hhbmdlZCgpXG4gICAgICAgICAgICApXG4gICAgICAgIClcbiAgICApO1xuXG4gICAgLyoqXG4gICAgICog0JjQvdC40YbQuNCw0LvQuNC30LjRgNGD0LXRgiDRjdC60LfQtdC80L/Qu9GP0YAg0LrQu9Cw0YHRgdCwIHtAbGluayBTY1Bob25lQXBwcm92ZUZvcm1Db21wb25lbnR9LlxuICAgICAqXG4gICAgICogQHBhcmFtIHZlcmlmaWNhdGlvblNlcnZpY2Ug0KHQtdGA0LLQuNGBINCy0LXRgNC40YTQuNC60LDRhtC40LguXG4gICAgICogQHBhcmFtIGZvcm1Hcm91cERpcmVjdGl2ZSDQlNC40YDQtdC60YLQuNCy0LAgYyBgRm9ybUdyb3VwYCDQuNC3IERPTS5cbiAgICAgKi9cbiAgICBwdWJsaWMgY29uc3RydWN0b3IoXG4gICAgICAgIHByaXZhdGUgcmVhZG9ubHkgdmVyaWZpY2F0aW9uU2VydmljZTogU2NWZXJpZmljYXRpb25TZXJ2aWNlLFxuICAgICAgICBASW5qZWN0KEZvcm1Hcm91cERpcmVjdGl2ZSlcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSBmb3JtR3JvdXBEaXJlY3RpdmU/OiBGb3JtR3JvdXBEaXJlY3RpdmVcbiAgICApIHt9XG5cbiAgICAvKiogQGluaGVyaXREb2MgKi9cbiAgICBwdWJsaWMgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgICAgIHRoaXMucGhvbmVDaGVjayQgPSB0dWlDb250cm9sVmFsdWU8c3RyaW5nIHwgbnVsbD4odGhpcy5waG9uZUNvbnRyb2wpLnBpcGUoXG4gICAgICAgICAgICB0YXAoKCkgPT4gdGhpcy5yZWxvYWRUaW1lciQubmV4dCgwKSksXG4gICAgICAgICAgICBzd2l0Y2hNYXAoKHZhbHVlKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMucGhvbmVDb250cm9sLnZhbGlkICYmICEhdmFsdWUpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMudmVyaWZpY2F0aW9uU2VydmljZS5nZXRQaG9uZUNoZWNrJCh2YWx1ZSkucGlwZShcbiAgICAgICAgICAgICAgICAgICAgICAgIG1hcCgocmVzdWx0KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuc2hvdWxkQmVCdXN5ICE9PSByZXN1bHQuaXNCdXN5KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucGhvbmVDb250cm9sLnNldEVycm9ycyh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJ2ZXJSZXNwb25zZTogW1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc2hvdWxkQmVCdXN5ID8gJ9Cf0L7Qu9GM0LfQvtCy0LDRgtC10LvRjyDRgSDRgtCw0LrQuNC8INC90L7QvNC10YDQvtC8INGC0LXQu9C10YTQvtC90LAg0L3QtSDRgdGD0YnQtdGB0YLQstGD0LXRgicgOiAn0J/QvtC70YzQt9C+0LLQsNGC0LXQu9GMINGBINGC0LDQutC40Lwg0L3QvtC80LXRgNC+0Lwg0YLQtdC70LXRhNC+0L3QsCDRg9C20LUg0YHRg9GJ0LXRgdGC0LLRg9C10YInLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucGhvbmVDb250cm9sLm1hcmtBc1RvdWNoZWQoKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuc2hvdWxkQmVDb25maXJtZWQgJiYgKHJlc3VsdC5pc0NvbmZpcm1lZCA9PT0gZmFsc2UgfHwgcmVzdWx0LmlzQ29uZmlybWVkID09PSBudWxsKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBob25lQ29udHJvbC5zZXRFcnJvcnMoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VydmVyUmVzcG9uc2U6IFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAn0JLRhdC+0LQg0L/QviDRg9C60LDQt9Cw0L3QvdC+0LzRgyDRgtC10LvQtdGE0L7QvdGDINC90LXQstC+0LfQvNC+0LbQtdC9LiDQntCx0YDQsNGC0LjRgtC10YHRjCDQuiDQstCw0YjQtdC80YMg0L/QtdGA0YHQvtC90LDQu9GM0L3QvtC80YMg0LzQtdC90LXQtNC20LXRgNGDINC40LvQuCDQstC+0LnQtNC40YLQtSDRgSDQuNGB0L/QvtC70YzQt9C+0LLQsNC90LjQtdC8IGUtbWFpbCDQuCDQv9Cw0YDQvtC70Y8uJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBob25lQ29udHJvbC5tYXJrQXNUb3VjaGVkKCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgICAgICAgICBjYXRjaEVycm9yKChlcnJvcjogSHR0cEVycm9yUmVzcG9uc2UpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBlcnJvclJlc3BvbnNlID0gZXJyb3IuZXJyb3IgYXMgQXBpRXJyb3JSZXNwb25zZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBob25lQ29udHJvbC5zZXRFcnJvcnMoeyBzZXJ2ZXJSZXNwb25zZTogZXJyb3JSZXNwb25zZT8uZXJyb3JzPy5bYHBob25lYF0gPz8gW2Vycm9yUmVzcG9uc2UubWVzc2FnZV0gfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9mKGZhbHNlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnRXaXRoKG51bGwpXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdGhpcy5zZXRIYXZlQ29kZShmYWxzZSk7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gb2YoZmFsc2UpO1xuICAgICAgICAgICAgfSksXG4gICAgICAgICAgICBzaGFyZSgpXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5zZXRIYXZlQ29kZShmYWxzZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICog0KPRgdGC0LDQvdCw0LLQu9C40LLQsNC10YIg0YHQvtGB0YLQvtGP0L3QuNC1INC90LDQu9C40YfQuNGPINC60L7QtNCwINC/0L7QtNGC0LLQtdGA0LbQtNC10L3QuNGPINGDINC/0L7Qu9GM0LfQvtCy0LDRgtC10LvRjy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBoYXZlQ29kZSDQn9GA0LjQt9C90LDQuiDRgtC+0LPQviDQtdGB0YLRjCDQu9C4INC60L7QtCDQv9C+0LTRgtCy0LXRgNC20LTQtdC90LjRjyDQuNC70Lgg0L3QtdGCLlxuICAgICAqL1xuICAgIHB1YmxpYyBzZXRIYXZlQ29kZShoYXZlQ29kZTogYm9vbGVhbik6IHZvaWQge1xuICAgICAgICB0aGlzLmhhdmVDb2RlID0gaGF2ZUNvZGU7XG4gICAgICAgIHRoaXMuaGF2ZUNvZGVDaGFuZ2UuZW1pdChoYXZlQ29kZSk7XG4gICAgfVxufVxuIiwiPGZvcm0gW2Zvcm1Hcm91cF09XCJmb3JtXCIgKnR1aUxldD1cIihsb2FkaW5nQXBwcm92ZUNvZGUkIHwgYXN5bmMpIGFzIGxvYWRpbmdBcHByb3ZlQ29kZVwiIGNsYXNzPVwiZmxleCBmbGV4LWNvbCBnYXAtM1wiPlxuICAgIDxsYWJlbCB0dWlMYWJlbD1cItCd0L7QvNC10YAg0YLQtdC70LXRhNC+0L3QsFwiPlxuICAgICAgICA8dHVpLWlucHV0LXBob25lIGZvcm1Db250cm9sTmFtZT1cInBob25lXCIgW3R1aVRleHRmaWVsZEN1c3RvbUNvbnRlbnRdPVwiY2hlY2tpbmdQaG9uZVwiPlxuICAgICAgICAgICAg0J3QvtC80LXRgCDRgtC10LvQtdGE0L7QvdCwXG4gICAgICAgICAgICA8aW5wdXQgdHVpVGV4dGZpZWxkIGF1dG9jb21wbGV0ZT1cInBob25lXCIgLz5cbiAgICAgICAgPC90dWktaW5wdXQtcGhvbmU+XG4gICAgICAgIDx0dWktZXJyb3IgZm9ybUNvbnRyb2xOYW1lPVwicGhvbmVcIiBbZXJyb3JdPVwiW10gfCB0dWlGaWVsZEVycm9yIHwgYXN5bmNcIj48L3R1aS1lcnJvcj5cbiAgICA8L2xhYmVsPlxuICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJzaG93Q29kZUZpZWxkc1wiPlxuICAgICAgICA8bGFiZWwgKm5nSWY9XCJsb2FkaW5nQXBwcm92ZUNvZGUgPT09IGZhbHNlICYmIGhhdmVDb2RlXCIgdHVpTGFiZWw9XCLQmtC+0LQg0LjQtyDQodCc0KFcIj5cbiAgICAgICAgICAgIDx0dWktaW5wdXQgZm9ybUNvbnRyb2xOYW1lPVwidmVyaWZpY2F0aW9uQ29kZVwiPlxuICAgICAgICAgICAgICAgINCa0L7QtCDQuNC3INCh0JzQoVxuICAgICAgICAgICAgICAgIDxpbnB1dCB0dWlUZXh0ZmllbGQgW21hc2tpdG9dPVwidmVyaWZpY2F0aW9uQ29kZU1hc2tcIiBhdXRvY29tcGxldGU9XCJuZXctcGFzc3dvcmRcIiAvPlxuICAgICAgICAgICAgPC90dWktaW5wdXQ+XG4gICAgICAgICAgICA8dHVpLWVycm9yIGZvcm1Db250cm9sTmFtZT1cInZlcmlmaWNhdGlvbkNvZGVcIiBbZXJyb3JdPVwiW10gfCB0dWlGaWVsZEVycm9yIHwgYXN5bmNcIj48L3R1aS1lcnJvcj5cbiAgICAgICAgPC9sYWJlbD5cblxuICAgICAgICA8ZGl2ICp0dWlMZXQ9XCIhIWxvYWRpbmdBcHByb3ZlQ29kZSBhcyBsb2FkaW5nQXBwcm92ZUNvZGVcIiBjbGFzcz1cImZsZXggZ2FwLTQganVzdGlmeS1jZW50ZXJcIj5cbiAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICAqbmdJZj1cIiFoYXZlQ29kZVwiXG4gICAgICAgICAgICAgICAgdHVpQnV0dG9uXG4gICAgICAgICAgICAgICAgc2l6ZT1cInNcIlxuICAgICAgICAgICAgICAgIChjbGljayk9XCJvblNlbmRDb2RlLm5leHQoKVwiXG4gICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cImxvYWRpbmdBcHByb3ZlQ29kZSB8fCAhISEocGhvbmVDaGVjayQgfCBhc3luYykgfHwgcGhvbmVDb250cm9sLmludmFsaWRcIlxuICAgICAgICAgICAgICAgIFtzaG93TG9hZGVyXT1cImxvYWRpbmdBcHByb3ZlQ29kZVwiXG4gICAgICAgICAgICAgICAgaWNvbj1cInNjSWNvbkxvZ0luXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICDQn9C+0LvRg9GH0LjRgtGMINC60L7QtFxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICA8YnV0dG9uICpuZ0lmPVwiIWxvYWRpbmdBcHByb3ZlQ29kZSAmJiAhaGF2ZUNvZGVcIiB0dWlMaW5rIFtwc2V1ZG9dPVwidHJ1ZVwiIFtkaXNhYmxlZF09XCIhISEocGhvbmVDaGVjayQgfCBhc3luYykgfHwgcGhvbmVDb250cm9sLmludmFsaWRcIiAoY2xpY2spPVwic2V0SGF2ZUNvZGUodHJ1ZSlcIj5cbiAgICAgICAgICAgICAgICDQoyDQvNC10L3RjyDQtdGB0YLRjCDQutC+0LRcbiAgICAgICAgICAgIDwvYnV0dG9uPlxuXG4gICAgICAgICAgICA8bmctY29udGFpbmVyICp0dWlMZXQ9XCJ0aW1lciQgfCBhc3luYyBhcyB0aW1lclwiPlxuICAgICAgICAgICAgICAgIDx0dWktbG9hZGVyICpuZ0lmPVwiaGF2ZUNvZGVcIiBbc2hvd0xvYWRlcl09XCJsb2FkaW5nQXBwcm92ZUNvZGVcIj5cbiAgICAgICAgICAgICAgICAgICAgPGJ1dHRvbiB0dWlMaW5rIFtwc2V1ZG9dPVwidHJ1ZVwiIFtkaXNhYmxlZF09XCJsb2FkaW5nQXBwcm92ZUNvZGUgfHwgdGltZXJcIiAoY2xpY2spPVwib25TZW5kQ29kZS5uZXh0KClcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgINCf0L7QstGC0L7RgNC90L4g0L7RgtC/0YDQsNCy0LjRgtGMINC60L7QtFxuICAgICAgICAgICAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cInRpbWVyXCIgY2xhc3M9XCIhdGV4dC10dWktYmFzZS0wOFwiPijRh9C10YDQtdC3IHt7IHRpbWVyIH19KTwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgICAgICA8L3R1aS1sb2FkZXI+XG4gICAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgPC9kaXY+XG4gICAgPC9uZy1jb250YWluZXI+XG48L2Zvcm0+XG5cbjxuZy10ZW1wbGF0ZSAjY2hlY2tpbmdQaG9uZT5cbiAgICA8dHVpLWxvYWRlciAqbmdJZj1cIiEhIShwaG9uZUNoZWNrJCB8IGFzeW5jKSAmJiBwaG9uZUNvbnRyb2wudmFsaWRcIiBjbGFzcz1cInctNCBoLTRcIj4gPC90dWktbG9hZGVyPlxuPC9uZy10ZW1wbGF0ZT5cbiJdfQ==
|