@firestitch/form 12.0.0 → 12.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/app/components/form-dialog-actions/form-dialog-actions.component.d.ts +21 -21
  2. package/app/consts/error-messages.const.d.ts +19 -19
  3. package/app/directives/form/form.directive.d.ts +105 -105
  4. package/app/directives/form-dialog-close.directive.d.ts +12 -12
  5. package/app/directives/submit-button.directive.d.ts +31 -31
  6. package/app/directives/validators/compare.directive.d.ts +15 -15
  7. package/app/directives/validators/control.directive.d.ts +48 -48
  8. package/app/directives/validators/daterange.directive.d.ts +13 -13
  9. package/app/directives/validators/email.directive.d.ts +13 -13
  10. package/app/directives/validators/emails.directive.d.ts +13 -13
  11. package/app/directives/validators/function.directive.d.ts +14 -14
  12. package/app/directives/validators/greater.directive.d.ts +13 -13
  13. package/app/directives/validators/integer.directive.d.ts +13 -13
  14. package/app/directives/validators/lesser.directive.d.ts +13 -13
  15. package/app/directives/validators/max.directive.d.ts +13 -13
  16. package/app/directives/validators/maxlength.directive.d.ts +13 -13
  17. package/app/directives/validators/min.directive.d.ts +13 -13
  18. package/app/directives/validators/minlength.directive.d.ts +13 -13
  19. package/app/directives/validators/numeric.directive.d.ts +13 -13
  20. package/app/directives/validators/pattern.directive.d.ts +13 -13
  21. package/app/directives/validators/phone.directive.d.ts +13 -13
  22. package/app/directives/validators/required.directive.d.ts +16 -16
  23. package/app/directives/validators/url.directive.d.ts +14 -14
  24. package/app/directives/validators/validate.directive.d.ts +14 -14
  25. package/app/enums/confirm-result.d.ts +7 -7
  26. package/app/enums/form-status.d.ts +9 -9
  27. package/app/fs-form.module.d.ts +35 -35
  28. package/app/guards/form-deactivate.guard.d.ts +12 -12
  29. package/app/helpers/confirm-result-continue.d.ts +1 -1
  30. package/app/helpers/confirm-unsaved.d.ts +5 -5
  31. package/app/helpers/get-form-errors.d.ts +2 -2
  32. package/app/helpers/index.d.ts +2 -2
  33. package/app/helpers/is-enabled.d.ts +1 -1
  34. package/app/interfaces/async-validator.d.ts +14 -14
  35. package/app/interfaces/confirm-config.d.ts +7 -7
  36. package/app/interfaces/confirm-tab-group.d.ts +10 -10
  37. package/app/interfaces/form-deactivate.d.ts +4 -4
  38. package/app/interfaces/index.d.ts +4 -4
  39. package/app/interfaces/submit-event.d.ts +5 -5
  40. package/app/interfaces/submitted-event.d.ts +6 -6
  41. package/app/interfaces/validator.d.ts +13 -13
  42. package/app/providers/validate-messages.provider.d.ts +25 -25
  43. package/app/services/fsform.service.d.ts +10 -10
  44. package/app/validators/validators.d.ts +12 -12
  45. package/bundles/firestitch-form.umd.js +2619 -2613
  46. package/bundles/firestitch-form.umd.js.map +1 -1
  47. package/esm2015/app/components/form-dialog-actions/form-dialog-actions.component.js +85 -85
  48. package/esm2015/app/consts/error-messages.const.js +19 -19
  49. package/esm2015/app/directives/form/form.directive.js +618 -618
  50. package/esm2015/app/directives/form-dialog-close.directive.js +30 -30
  51. package/esm2015/app/directives/submit-button.directive.js +130 -130
  52. package/esm2015/app/directives/validators/compare.directive.js +48 -48
  53. package/esm2015/app/directives/validators/control.directive.js +256 -256
  54. package/esm2015/app/directives/validators/daterange.directive.js +40 -40
  55. package/esm2015/app/directives/validators/email.directive.js +40 -40
  56. package/esm2015/app/directives/validators/emails.directive.js +40 -40
  57. package/esm2015/app/directives/validators/function.directive.js +30 -30
  58. package/esm2015/app/directives/validators/greater.directive.js +39 -39
  59. package/esm2015/app/directives/validators/integer.directive.js +40 -40
  60. package/esm2015/app/directives/validators/lesser.directive.js +39 -39
  61. package/esm2015/app/directives/validators/max.directive.js +35 -35
  62. package/esm2015/app/directives/validators/maxlength.directive.js +34 -34
  63. package/esm2015/app/directives/validators/min.directive.js +35 -35
  64. package/esm2015/app/directives/validators/minlength.directive.js +34 -34
  65. package/esm2015/app/directives/validators/numeric.directive.js +40 -40
  66. package/esm2015/app/directives/validators/pattern.directive.js +35 -35
  67. package/esm2015/app/directives/validators/phone.directive.js +40 -40
  68. package/esm2015/app/directives/validators/required.directive.js +70 -70
  69. package/esm2015/app/directives/validators/url.directive.js +46 -46
  70. package/esm2015/app/directives/validators/validate.directive.js +32 -32
  71. package/esm2015/app/enums/confirm-result.js +8 -8
  72. package/esm2015/app/enums/form-status.js +10 -10
  73. package/esm2015/app/fs-form.module.js +171 -165
  74. package/esm2015/app/guards/form-deactivate.guard.js +39 -39
  75. package/esm2015/app/helpers/confirm-result-continue.js +4 -4
  76. package/esm2015/app/helpers/confirm-unsaved.js +69 -69
  77. package/esm2015/app/helpers/get-form-errors.js +24 -24
  78. package/esm2015/app/helpers/index.js +2 -2
  79. package/esm2015/app/helpers/is-enabled.js +3 -3
  80. package/esm2015/app/interfaces/async-validator.js +1 -1
  81. package/esm2015/app/interfaces/confirm-config.js +1 -1
  82. package/esm2015/app/interfaces/confirm-tab-group.js +1 -1
  83. package/esm2015/app/interfaces/form-deactivate.js +1 -1
  84. package/esm2015/app/interfaces/index.js +4 -4
  85. package/esm2015/app/interfaces/submit-event.js +1 -1
  86. package/esm2015/app/interfaces/submitted-event.js +1 -1
  87. package/esm2015/app/interfaces/validator.js +1 -1
  88. package/esm2015/app/providers/validate-messages.provider.js +10 -10
  89. package/esm2015/app/services/fsform.service.js +24 -24
  90. package/esm2015/app/validators/validators.js +96 -96
  91. package/esm2015/firestitch-form.js +4 -4
  92. package/esm2015/public_api.js +34 -34
  93. package/fesm2015/firestitch-form.js +2067 -2061
  94. package/fesm2015/firestitch-form.js.map +1 -1
  95. package/firestitch-form.d.ts +5 -5
  96. package/package.json +1 -1
  97. package/public_api.d.ts +33 -33
@@ -1,619 +1,619 @@
1
- import { ContentChildren, Directive, ElementRef, EventEmitter, HostBinding, Inject, Input, NgZone, Optional, Output, QueryList, } from '@angular/core';
2
- import { NgForm } from '@angular/forms';
3
- import { MatDialogRef } from '@angular/material/dialog';
4
- import { MatTabGroup } from '@angular/material/tabs';
5
- import { FsMessage, MessageMode } from '@firestitch/message';
6
- import { FsPrompt } from '@firestitch/prompt';
7
- import { guid } from '@firestitch/common';
8
- import { DrawerRef } from '@firestitch/drawer';
9
- import { BehaviorSubject, defer, fromEvent, iif, isObservable, of, Subject, throwError } from 'rxjs';
10
- import { catchError, delay, filter, first, map, mergeMap, startWith, switchMap, take, takeUntil, tap } from 'rxjs/operators';
11
- import { confirmUnsaved } from '../../helpers/confirm-unsaved';
12
- import { FsFormDialogCloseDirective } from '../form-dialog-close.directive';
13
- import { ConfirmResult } from './../../enums/confirm-result';
14
- import { FsForm } from '../../services/fsform.service';
15
- import { FormStatus } from './../../enums/form-status';
16
- import { confirmResultContinue } from '../../helpers/confirm-result-continue';
17
- import { getFormErrors } from '../../helpers/get-form-errors';
18
- import * as i0 from "@angular/core";
19
- import * as i1 from "../../services/fsform.service";
20
- import * as i2 from "@firestitch/message";
21
- import * as i3 from "@firestitch/prompt";
22
- import * as i4 from "@angular/forms";
23
- import * as i5 from "@angular/material/dialog";
24
- import * as i6 from "@firestitch/drawer";
25
- export class FsFormDirective {
26
- constructor(ngForm, _form, _element, _message, _prompt, _ngZone, _dialogRef, _drawerRef) {
27
- this.ngForm = ngForm;
28
- this._form = _form;
29
- this._element = _element;
30
- this._message = _message;
31
- this._prompt = _prompt;
32
- this._ngZone = _ngZone;
33
- this._dialogRef = _dialogRef;
34
- this._drawerRef = _drawerRef;
35
- this.wrapperSelector = '.fs-form-wrapper,.mat-form-field';
36
- this.messageSelector = '.fs-form-message,.mat-form-field-subscript-wrapper';
37
- this.hintSelector = '.fs-form-hint,.mat-form-field-hint-wrapper';
38
- this.labelSelector = '.fs-form-label,.mat-form-field-label';
39
- this.autocomplete = false;
40
- this.shortcuts = true; // Ctrl + s
41
- this.confirm = true;
42
- this.confirmDialog = true;
43
- this.confirmDrawer = true;
44
- this.confirmBrowser = true;
45
- this.confirmTabs = true;
46
- this.dirtySubmitButton = true;
47
- this.successDelay = 0;
48
- this.errorDelay = 1000;
49
- this.submitEvent = new EventEmitter();
50
- this.invalid = new EventEmitter();
51
- this.valid = new EventEmitter();
52
- this.submitted = new EventEmitter();
53
- this.reseted = new EventEmitter();
54
- this.cleared = new EventEmitter();
55
- this.fsformClass = true;
56
- this._tabGroups = new QueryList();
57
- this._submitButtons = new QueryList();
58
- this._dialogBackdropEscape = false;
59
- this._snapshot = {};
60
- this._status$ = new BehaviorSubject(FormStatus.Valid);
61
- this._destroy$ = new Subject();
62
- }
63
- get submitting() {
64
- return this._status$.getValue() === FormStatus.Submitting;
65
- }
66
- get completing() {
67
- return this._status$.getValue() === FormStatus.Completing;
68
- }
69
- get _submitEvent() {
70
- return {
71
- ngForm: this.ngForm,
72
- submitter: this._submitter,
73
- };
74
- }
75
- get _formValidState$() {
76
- this._form.broadcast('valid', this._submitEvent);
77
- this.submitEvent.emit(this._submitEvent);
78
- this.valid.emit(this._submitEvent);
79
- const submittedEvent = {
80
- ngForm: this.ngForm,
81
- submitter: this._submitter,
82
- response: null
83
- };
84
- if (!this.submit) {
85
- return of(submittedEvent);
86
- }
87
- const result = this.submit(this._submitEvent);
88
- if (!isObservable(result)) {
89
- return of(submittedEvent);
90
- }
91
- return result
92
- .pipe(map((response) => {
93
- submittedEvent.response = response;
94
- return submittedEvent;
95
- }));
96
- }
97
- get _formInvalidState$() {
98
- this._form.broadcast('invalid', this._submitEvent);
99
- if (this.invalid) {
100
- this.invalid.emit(this._submitEvent);
101
- }
102
- const message = 'Changes not saved. Please review errors highlighted in red.';
103
- this._message.error(message, { mode: MessageMode.Toast });
104
- const el = this._element.nativeElement.querySelector('.ng-invalid');
105
- if (el) {
106
- el.scrollIntoView({ behavior: 'smooth', block: 'center' });
107
- }
108
- return throwError('Form validation error');
109
- }
110
- get _submitter() {
111
- return this._activeSubmitButton
112
- ? this._activeSubmitButton.name
113
- : null;
114
- }
115
- ngOnInit() {
116
- this._registerConfirmDialogBackdropEscape();
117
- this._listenHotKeys();
118
- this._listenWindowClose();
119
- this._listenSubmit();
120
- if (!this.autocomplete) {
121
- this._registerAutocomplete();
122
- }
123
- }
124
- ngOnChanges(changes) {
125
- if (changes.confirm) {
126
- this._updateDirtySubmitButtons();
127
- }
128
- }
129
- ngAfterContentInit() {
130
- this._registerConfirm();
131
- this._registerConfirmDialogClose();
132
- this._registerConfirmDrawerClose();
133
- this._registerConfirmTabs();
134
- this._registerDrawerClose();
135
- this._registerDirtySubmitButton();
136
- }
137
- ngOnDestroy() {
138
- this._destroy$.next();
139
- this._destroy$.complete();
140
- }
141
- createSnapshot() {
142
- this._snapshot = this.ngForm.value;
143
- }
144
- reset() {
145
- this.ngForm.resetForm();
146
- Object.keys(this.ngForm.controls)
147
- .forEach((name) => {
148
- const control = this.ngForm.controls[name];
149
- control.reset(this._snapshot[name]);
150
- });
151
- this.reseted.emit();
152
- }
153
- clear() {
154
- this.ngForm.resetForm();
155
- this.cleared.emit();
156
- }
157
- dirty() {
158
- this.ngForm.form.markAsDirty();
159
- this._updateDirtySubmitButtons();
160
- }
161
- triggerSubmit() {
162
- this.ngForm.ngSubmit.next();
163
- }
164
- triggerConfirm() {
165
- const submitted = this.submitting ? this.submitted.asObservable() : of({});
166
- return submitted
167
- .pipe(take(1), mergeMap(() => confirmUnsaved(this, this._prompt)));
168
- }
169
- enable() {
170
- this.ngForm.control.enable();
171
- this._updateDirtySubmitButtons();
172
- }
173
- disable() {
174
- this.ngForm.control.disable();
175
- this._submitButtons.forEach((button) => {
176
- button.disable();
177
- });
178
- }
179
- addSubmitButton(submitButton) {
180
- this._submitButtons.reset([
181
- ...this._submitButtons.toArray(),
182
- submitButton,
183
- ]);
184
- }
185
- removeSubmitButton(submitButton) {
186
- this._submitButtons.reset([
187
- ...this._submitButtons.toArray()
188
- .filter((submitButton_) => (submitButton !== submitButton_)),
189
- ]);
190
- }
191
- _listenSubmit() {
192
- this.ngForm
193
- .ngSubmit
194
- .pipe(tap((event) => {
195
- event === null || event === void 0 ? void 0 : event.preventDefault();
196
- }), filter(() => {
197
- return [FormStatus.Valid, FormStatus.Invalid]
198
- .includes(this._status$.getValue());
199
- }), tap(() => this._markControlsAsTouchedAndUpdateValidity()), tap(() => this._broadcastSubmittingEvents()), switchMap(() => this._waitUntilStatusPending()), tap(() => this._setupActiveSubmitButton()), mergeMap(() => {
200
- return this.ngForm.status === 'INVALID'
201
- ? this._formInvalidState$
202
- : this._formValidState$;
203
- }), catchError((e, source$) => {
204
- this._handleError(e);
205
- return source$;
206
- }), tap((submittedEvent) => {
207
- this._completeSubmit(true, submittedEvent);
208
- }), takeUntil(this._destroy$))
209
- .subscribe(() => { });
210
- }
211
- _listenWindowClose() {
212
- fromEvent(window, 'beforeunload')
213
- .pipe(takeUntil(this._destroy$))
214
- .subscribe((event) => {
215
- if (this.confirm && this.confirmBrowser && this.ngForm.dirty) {
216
- event.returnValue = false;
217
- }
218
- });
219
- }
220
- _listenHotKeys() {
221
- this._ngZone.runOutsideAngular(() => {
222
- fromEvent(document, 'keydown')
223
- .pipe(takeUntil(this._destroy$))
224
- .subscribe((event) => {
225
- if (this._dialogBackdropEscape && event.code === 'Escape') {
226
- const dialog = document.getElementById(this._dialogRef.id);
227
- const paths = event.composedPath();
228
- if (paths) {
229
- paths.forEach(item => {
230
- if (dialog === item) {
231
- this._ngZone.run(() => {
232
- this._formClose();
233
- });
234
- }
235
- });
236
- }
237
- }
238
- if ((event.ctrlKey || event.metaKey) && event.code === 'KeyS') {
239
- event.preventDefault();
240
- if (this.shortcuts) {
241
- if (this._elementInForm(document.activeElement)) {
242
- this.ngForm.ngSubmit.next();
243
- }
244
- }
245
- }
246
- });
247
- });
248
- }
249
- _formClose() {
250
- if (this.confirm && this.confirmDialog) {
251
- this.triggerConfirm()
252
- .pipe(filter((result) => confirmResultContinue(result)), switchMap((result) => {
253
- return result === ConfirmResult.Pristine || result === ConfirmResult.Discard
254
- ? of(null)
255
- : this.submitted.asObservable();
256
- }), takeUntil(this._destroy$))
257
- .subscribe((result) => {
258
- this._dialogRef.close(result === null || result === void 0 ? void 0 : result.response);
259
- });
260
- }
261
- else {
262
- this._dialogRef.close(null);
263
- }
264
- }
265
- _registerDialogClose(directive) {
266
- if (!directive.registered) {
267
- directive.registered = true;
268
- directive.clicked$
269
- .pipe(takeUntil(this._destroy$))
270
- .subscribe(() => {
271
- this._formClose();
272
- });
273
- }
274
- }
275
- _getActiveButton() {
276
- const activeButton = this._submitButtons.find(button => {
277
- return button.active;
278
- });
279
- return activeButton ? activeButton : this._submitButtons.first;
280
- }
281
- _elementInForm(el) {
282
- if (el.isSameNode(this._element.nativeElement)) {
283
- return true;
284
- }
285
- else if (el.parentElement) {
286
- return this._elementInForm(el.parentElement);
287
- }
288
- return false;
289
- }
290
- _completeSubmit(success, submitEvent) {
291
- if (success) {
292
- this.ngForm.control.markAsPristine();
293
- this.createSnapshot();
294
- this.submitted.emit(submitEvent);
295
- }
296
- else {
297
- this._resetButtons();
298
- }
299
- if (this._activeSubmitButton) {
300
- if (success) {
301
- this._activeSubmitButton.success();
302
- }
303
- else {
304
- this._activeSubmitButton.error();
305
- }
306
- }
307
- this._status$.next(FormStatus.Submitted);
308
- if (success) {
309
- this._status$.next(FormStatus.Success);
310
- }
311
- else {
312
- this._status$.next(FormStatus.Error);
313
- }
314
- this._status$.next(FormStatus.Completing);
315
- const resetDelay = success ? this.successDelay : this.errorDelay;
316
- of(true)
317
- .pipe(delay(resetDelay), first(), takeUntil(this._destroy$)).subscribe(() => {
318
- if (this.ngForm.form.status === 'VALID') {
319
- this._status$.next(FormStatus.Valid);
320
- }
321
- else {
322
- this._status$.next(FormStatus.Invalid);
323
- }
324
- this._resetButtons();
325
- this._updateDirtySubmitButtons();
326
- });
327
- }
328
- _resetButtons() {
329
- this._submitButtons.forEach((button) => {
330
- button.reset();
331
- });
332
- }
333
- _registerConfirm() {
334
- this.ngForm.form.valueChanges
335
- .pipe(takeUntil(this._destroy$))
336
- .subscribe((changes) => {
337
- if (this.confirm) {
338
- const existing = Object.keys(this._snapshot);
339
- Object.keys(changes)
340
- .forEach((name) => {
341
- if (existing.indexOf(name) === -1) {
342
- this._snapshot[name] = changes[name];
343
- }
344
- });
345
- }
346
- });
347
- }
348
- _registerDrawerClose() {
349
- if (this._drawerRef) {
350
- this._drawerRef.closeStart$
351
- .pipe(takeUntil(this._destroy$))
352
- .subscribe((subscriber) => {
353
- if (this.submitting) {
354
- this._status$
355
- .pipe(filter((status) => status === FormStatus.Success || status === FormStatus.Error), takeUntil(this._destroy$))
356
- .subscribe((status) => {
357
- if (status === FormStatus.Success) {
358
- subscriber.next();
359
- subscriber.complete();
360
- }
361
- else {
362
- subscriber.error();
363
- }
364
- });
365
- }
366
- else {
367
- subscriber.next();
368
- subscriber.complete();
369
- }
370
- });
371
- }
372
- }
373
- _registerConfirmDrawerClose() {
374
- if (this._drawerRef) {
375
- this._drawerRef.closeStart$
376
- .pipe(switchMap((subscriber) => {
377
- return iif(() => this.confirm && this.confirmDrawer, this.triggerConfirm()
378
- .pipe(map((result) => confirmResultContinue(result)), tap((result) => {
379
- if (result) {
380
- subscriber.next();
381
- subscriber.complete();
382
- }
383
- })), defer(() => {
384
- subscriber.next();
385
- subscriber.complete();
386
- }));
387
- }), takeUntil(this._destroy$))
388
- .subscribe();
389
- }
390
- }
391
- _registerConfirmTabs() {
392
- if (this.tabGroup) {
393
- this.registerConfirmTabGroup(this.tabGroup);
394
- }
395
- this.registerConfirmTabGroups(this._tabGroups.toArray());
396
- this._tabGroups.changes
397
- .pipe(takeUntil(this._destroy$))
398
- .subscribe(() => {
399
- this.registerConfirmTabGroups(this._tabGroups.toArray());
400
- });
401
- }
402
- registerConfirmTabGroups(tabGroups) {
403
- tabGroups.forEach((tabGroup) => {
404
- this.registerConfirmTabGroup(tabGroup);
405
- });
406
- }
407
- registerConfirmTabGroup(tabGroup) {
408
- const confirmTabGroup = tabGroup;
409
- if (!confirmTabGroup._originalHandleClick) {
410
- confirmTabGroup._originalHandleClick = tabGroup._handleClick;
411
- confirmTabGroup._handlClick$ = new Subject();
412
- confirmTabGroup._handleClick = (tab, tabHeader, idx) => {
413
- if (confirmTabGroup._handlClick$.observers.length) {
414
- confirmTabGroup._handlClick$.next({ tab, tabHeader, idx });
415
- }
416
- else {
417
- confirmTabGroup._originalHandleClick(tab, tabHeader, idx);
418
- }
419
- };
420
- }
421
- confirmTabGroup._handlClick$
422
- .pipe(takeUntil(this._destroy$))
423
- .subscribe((event) => {
424
- if (!this.submitting) {
425
- if (this.confirm && this.confirmTabs) {
426
- this.triggerConfirm()
427
- .pipe(takeUntil(this._destroy$))
428
- .subscribe((result) => {
429
- if (confirmResultContinue(result)) {
430
- confirmTabGroup.selectedIndex = event.idx;
431
- }
432
- });
433
- }
434
- else {
435
- confirmTabGroup._originalHandleClick(event.tab, event.tabHeader, event.idx);
436
- }
437
- }
438
- });
439
- }
440
- _registerConfirmDialogClose() {
441
- if (this._dialogRef) {
442
- this.formDialogClose.forEach(item => {
443
- this._registerDialogClose(item);
444
- });
445
- this.formDialogClose.changes
446
- .pipe(takeUntil(this._destroy$))
447
- .subscribe((e) => {
448
- e.forEach(item => {
449
- this._registerDialogClose(item);
450
- });
451
- });
452
- }
453
- }
454
- _registerConfirmDialogBackdropEscape() {
455
- this._dialogBackdropEscape = this._dialogRef && this._dialogRef.disableClose !== true;
456
- if (this._dialogRef && !this._dialogRef.disableClose) {
457
- this._dialogRef.disableClose = true;
458
- this._dialogRef.backdropClick()
459
- .pipe(takeUntil(this._destroy$))
460
- .subscribe(() => {
461
- this._formClose();
462
- });
463
- this._destroy$
464
- .subscribe(() => {
465
- this._dialogRef.disableClose = false;
466
- });
467
- }
468
- }
469
- _registerAutocomplete() {
470
- this._registerControl = this.ngForm.form.registerControl.bind(this.ngForm.form);
471
- this.ngForm.form.registerControl = (name, control) => {
472
- const el = this._element.nativeElement.querySelector(`input[name='${name}']`);
473
- if (el) {
474
- el.setAttribute('name', name + '_' + guid());
475
- if (!el.getAttribute('autocomplete')) {
476
- el.setAttribute('autocomplete', 'none');
477
- }
478
- }
479
- return this._registerControl(name, control);
480
- };
481
- }
482
- _registerDirtySubmitButton() {
483
- if (!this.ngForm) {
484
- return;
485
- }
486
- this.ngForm.form.valueChanges
487
- .pipe(takeUntil(this._destroy$))
488
- .subscribe(() => {
489
- this._updateDirtySubmitButtons();
490
- });
491
- this._submitButtons.changes
492
- .pipe(takeUntil(this._destroy$))
493
- .subscribe(() => {
494
- this._updateDirtySubmitButtons();
495
- });
496
- }
497
- _updateDirtySubmitButtons() {
498
- this._submitButtons
499
- .forEach((submitButton) => {
500
- if (!this.confirm || !this.dirtySubmitButton || this.ngForm.dirty || !submitButton.dirtySubmit) {
501
- submitButton.enable();
502
- }
503
- else {
504
- submitButton.disable();
505
- }
506
- });
507
- }
508
- _broadcastSubmittingEvents() {
509
- this._status$.next(FormStatus.Submitting);
510
- this._form.broadcast('submit', this.ngForm);
511
- }
512
- _markControlsAsTouchedAndUpdateValidity() {
513
- Object.values(this.ngForm.controls)
514
- .forEach(control => {
515
- control.markAsDirty();
516
- control.markAsTouched();
517
- control.updateValueAndValidity();
518
- });
519
- }
520
- _setupActiveSubmitButton() {
521
- this._activeSubmitButton = this._getActiveButton();
522
- this._resetButtons();
523
- if (this._activeSubmitButton) {
524
- this._activeSubmitButton.process();
525
- }
526
- }
527
- _waitUntilStatusPending() {
528
- return this.ngForm.statusChanges
529
- .pipe(startWith(this.ngForm.status), first((state) => state !== 'PENDING'));
530
- }
531
- _handleError(e) {
532
- console.log('%c Form Submit ', 'color: white; background-color: #D33F49', 'Error occured');
533
- console.group('Error Details:');
534
- console.log('Message: ', e);
535
- console.log('FormRef: ', this);
536
- if (this.ngForm.invalid) {
537
- const errors = getFormErrors(this.ngForm.control, null);
538
- console.log('Validation Errors: ', errors);
539
- }
540
- console.groupEnd();
541
- this._completeSubmit(false, null);
542
- }
543
- }
544
- FsFormDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsFormDirective, deps: [{ token: NgForm }, { token: i1.FsForm }, { token: i0.ElementRef }, { token: i2.FsMessage }, { token: i3.FsPrompt }, { token: i0.NgZone }, { token: MatDialogRef, optional: true }, { token: DrawerRef, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
545
- FsFormDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.2.16", type: FsFormDirective, selector: "[fsForm]", inputs: { wrapperSelector: "wrapperSelector", messageSelector: "messageSelector", hintSelector: "hintSelector", labelSelector: "labelSelector", autocomplete: "autocomplete", shortcuts: "shortcuts", confirm: "confirm", confirmDialog: "confirmDialog", confirmDrawer: "confirmDrawer", confirmBrowser: "confirmBrowser", confirmTabs: "confirmTabs", dirtySubmitButton: "dirtySubmitButton", submit: "submit", successDelay: "successDelay", errorDelay: "errorDelay", tabGroup: "tabGroup" }, outputs: { submitEvent: "fsForm", invalid: "invalid", valid: "valid", submitted: "submitted", reseted: "reseted", cleared: "cleared" }, host: { properties: { "class.fs-form": "this.fsformClass" } }, queries: [{ propertyName: "formDialogClose", predicate: FsFormDialogCloseDirective, descendants: true }, { propertyName: "_tabGroups", predicate: MatTabGroup, descendants: true }], usesOnChanges: true, ngImport: i0 });
546
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsFormDirective, decorators: [{
547
- type: Directive,
548
- args: [{
549
- selector: '[fsForm]',
550
- }]
551
- }], ctorParameters: function () { return [{ type: i4.NgForm, decorators: [{
552
- type: Inject,
553
- args: [NgForm]
554
- }] }, { type: i1.FsForm }, { type: i0.ElementRef }, { type: i2.FsMessage }, { type: i3.FsPrompt }, { type: i0.NgZone }, { type: i5.MatDialogRef, decorators: [{
555
- type: Optional
556
- }, {
557
- type: Inject,
558
- args: [MatDialogRef]
559
- }] }, { type: i6.DrawerRef, decorators: [{
560
- type: Optional
561
- }, {
562
- type: Inject,
563
- args: [DrawerRef]
564
- }] }]; }, propDecorators: { wrapperSelector: [{
565
- type: Input
566
- }], messageSelector: [{
567
- type: Input
568
- }], hintSelector: [{
569
- type: Input
570
- }], labelSelector: [{
571
- type: Input
572
- }], autocomplete: [{
573
- type: Input
574
- }], shortcuts: [{
575
- type: Input
576
- }], confirm: [{
577
- type: Input
578
- }], confirmDialog: [{
579
- type: Input
580
- }], confirmDrawer: [{
581
- type: Input
582
- }], confirmBrowser: [{
583
- type: Input
584
- }], confirmTabs: [{
585
- type: Input
586
- }], dirtySubmitButton: [{
587
- type: Input
588
- }], submit: [{
589
- type: Input
590
- }], successDelay: [{
591
- type: Input
592
- }], errorDelay: [{
593
- type: Input
594
- }], tabGroup: [{
595
- type: Input
596
- }], submitEvent: [{
597
- type: Output,
598
- args: ['fsForm']
599
- }], invalid: [{
600
- type: Output
601
- }], valid: [{
602
- type: Output
603
- }], submitted: [{
604
- type: Output
605
- }], reseted: [{
606
- type: Output
607
- }], cleared: [{
608
- type: Output
609
- }], fsformClass: [{
610
- type: HostBinding,
611
- args: ['class.fs-form']
612
- }], formDialogClose: [{
613
- type: ContentChildren,
614
- args: [FsFormDialogCloseDirective, { descendants: true }]
615
- }], _tabGroups: [{
616
- type: ContentChildren,
617
- args: [MatTabGroup, { descendants: true }]
618
- }] } });
1
+ import { ContentChildren, Directive, ElementRef, EventEmitter, HostBinding, Inject, Input, NgZone, Optional, Output, QueryList, } from '@angular/core';
2
+ import { NgForm } from '@angular/forms';
3
+ import { MatDialogRef } from '@angular/material/dialog';
4
+ import { MatTabGroup } from '@angular/material/tabs';
5
+ import { FsMessage, MessageMode } from '@firestitch/message';
6
+ import { FsPrompt } from '@firestitch/prompt';
7
+ import { guid } from '@firestitch/common';
8
+ import { DrawerRef } from '@firestitch/drawer';
9
+ import { BehaviorSubject, defer, fromEvent, iif, isObservable, of, Subject, throwError } from 'rxjs';
10
+ import { catchError, delay, filter, first, map, mergeMap, startWith, switchMap, take, takeUntil, tap } from 'rxjs/operators';
11
+ import { confirmUnsaved } from '../../helpers/confirm-unsaved';
12
+ import { FsFormDialogCloseDirective } from '../form-dialog-close.directive';
13
+ import { ConfirmResult } from './../../enums/confirm-result';
14
+ import { FsForm } from '../../services/fsform.service';
15
+ import { FormStatus } from './../../enums/form-status';
16
+ import { confirmResultContinue } from '../../helpers/confirm-result-continue';
17
+ import { getFormErrors } from '../../helpers/get-form-errors';
18
+ import * as i0 from "@angular/core";
19
+ import * as i1 from "../../services/fsform.service";
20
+ import * as i2 from "@firestitch/message";
21
+ import * as i3 from "@firestitch/prompt";
22
+ import * as i4 from "@angular/forms";
23
+ import * as i5 from "@angular/material/dialog";
24
+ import * as i6 from "@firestitch/drawer";
25
+ export class FsFormDirective {
26
+ constructor(ngForm, _form, _element, _message, _prompt, _ngZone, _dialogRef, _drawerRef) {
27
+ this.ngForm = ngForm;
28
+ this._form = _form;
29
+ this._element = _element;
30
+ this._message = _message;
31
+ this._prompt = _prompt;
32
+ this._ngZone = _ngZone;
33
+ this._dialogRef = _dialogRef;
34
+ this._drawerRef = _drawerRef;
35
+ this.wrapperSelector = '.fs-form-wrapper,.mat-form-field';
36
+ this.messageSelector = '.fs-form-message,.mat-form-field-subscript-wrapper';
37
+ this.hintSelector = '.fs-form-hint,.mat-form-field-hint-wrapper';
38
+ this.labelSelector = '.fs-form-label,.mat-form-field-label';
39
+ this.autocomplete = false;
40
+ this.shortcuts = true; // Ctrl + s
41
+ this.confirm = true;
42
+ this.confirmDialog = true;
43
+ this.confirmDrawer = true;
44
+ this.confirmBrowser = true;
45
+ this.confirmTabs = true;
46
+ this.dirtySubmitButton = true;
47
+ this.successDelay = 0;
48
+ this.errorDelay = 1000;
49
+ this.submitEvent = new EventEmitter();
50
+ this.invalid = new EventEmitter();
51
+ this.valid = new EventEmitter();
52
+ this.submitted = new EventEmitter();
53
+ this.reseted = new EventEmitter();
54
+ this.cleared = new EventEmitter();
55
+ this.fsformClass = true;
56
+ this._tabGroups = new QueryList();
57
+ this._submitButtons = new QueryList();
58
+ this._dialogBackdropEscape = false;
59
+ this._snapshot = {};
60
+ this._status$ = new BehaviorSubject(FormStatus.Valid);
61
+ this._destroy$ = new Subject();
62
+ }
63
+ get submitting() {
64
+ return this._status$.getValue() === FormStatus.Submitting;
65
+ }
66
+ get completing() {
67
+ return this._status$.getValue() === FormStatus.Completing;
68
+ }
69
+ get _submitEvent() {
70
+ return {
71
+ ngForm: this.ngForm,
72
+ submitter: this._submitter,
73
+ };
74
+ }
75
+ get _formValidState$() {
76
+ this._form.broadcast('valid', this._submitEvent);
77
+ this.submitEvent.emit(this._submitEvent);
78
+ this.valid.emit(this._submitEvent);
79
+ const submittedEvent = {
80
+ ngForm: this.ngForm,
81
+ submitter: this._submitter,
82
+ response: null
83
+ };
84
+ if (!this.submit) {
85
+ return of(submittedEvent);
86
+ }
87
+ const result = this.submit(this._submitEvent);
88
+ if (!isObservable(result)) {
89
+ return of(submittedEvent);
90
+ }
91
+ return result
92
+ .pipe(map((response) => {
93
+ submittedEvent.response = response;
94
+ return submittedEvent;
95
+ }));
96
+ }
97
+ get _formInvalidState$() {
98
+ this._form.broadcast('invalid', this._submitEvent);
99
+ if (this.invalid) {
100
+ this.invalid.emit(this._submitEvent);
101
+ }
102
+ const message = 'Changes not saved. Please review errors highlighted in red.';
103
+ this._message.error(message, { mode: MessageMode.Toast });
104
+ const el = this._element.nativeElement.querySelector('.ng-invalid');
105
+ if (el) {
106
+ el.scrollIntoView({ behavior: 'smooth', block: 'center' });
107
+ }
108
+ return throwError('Form validation error');
109
+ }
110
+ get _submitter() {
111
+ return this._activeSubmitButton
112
+ ? this._activeSubmitButton.name
113
+ : null;
114
+ }
115
+ ngOnInit() {
116
+ this._registerConfirmDialogBackdropEscape();
117
+ this._listenHotKeys();
118
+ this._listenWindowClose();
119
+ this._listenSubmit();
120
+ if (!this.autocomplete) {
121
+ this._registerAutocomplete();
122
+ }
123
+ }
124
+ ngOnChanges(changes) {
125
+ if (changes.confirm) {
126
+ this._updateDirtySubmitButtons();
127
+ }
128
+ }
129
+ ngAfterContentInit() {
130
+ this._registerConfirm();
131
+ this._registerConfirmDialogClose();
132
+ this._registerConfirmDrawerClose();
133
+ this._registerConfirmTabs();
134
+ this._registerDrawerClose();
135
+ this._registerDirtySubmitButton();
136
+ }
137
+ ngOnDestroy() {
138
+ this._destroy$.next();
139
+ this._destroy$.complete();
140
+ }
141
+ createSnapshot() {
142
+ this._snapshot = this.ngForm.value;
143
+ }
144
+ reset() {
145
+ this.ngForm.resetForm();
146
+ Object.keys(this.ngForm.controls)
147
+ .forEach((name) => {
148
+ const control = this.ngForm.controls[name];
149
+ control.reset(this._snapshot[name]);
150
+ });
151
+ this.reseted.emit();
152
+ }
153
+ clear() {
154
+ this.ngForm.resetForm();
155
+ this.cleared.emit();
156
+ }
157
+ dirty() {
158
+ this.ngForm.form.markAsDirty();
159
+ this._updateDirtySubmitButtons();
160
+ }
161
+ triggerSubmit() {
162
+ this.ngForm.ngSubmit.next();
163
+ }
164
+ triggerConfirm() {
165
+ const submitted = this.submitting ? this.submitted.asObservable() : of({});
166
+ return submitted
167
+ .pipe(take(1), mergeMap(() => confirmUnsaved(this, this._prompt)));
168
+ }
169
+ enable() {
170
+ this.ngForm.control.enable();
171
+ this._updateDirtySubmitButtons();
172
+ }
173
+ disable() {
174
+ this.ngForm.control.disable();
175
+ this._submitButtons.forEach((button) => {
176
+ button.disable();
177
+ });
178
+ }
179
+ addSubmitButton(submitButton) {
180
+ this._submitButtons.reset([
181
+ ...this._submitButtons.toArray(),
182
+ submitButton,
183
+ ]);
184
+ }
185
+ removeSubmitButton(submitButton) {
186
+ this._submitButtons.reset([
187
+ ...this._submitButtons.toArray()
188
+ .filter((submitButton_) => (submitButton !== submitButton_)),
189
+ ]);
190
+ }
191
+ _listenSubmit() {
192
+ this.ngForm
193
+ .ngSubmit
194
+ .pipe(tap((event) => {
195
+ event === null || event === void 0 ? void 0 : event.preventDefault();
196
+ }), filter(() => {
197
+ return [FormStatus.Valid, FormStatus.Invalid]
198
+ .includes(this._status$.getValue());
199
+ }), tap(() => this._markControlsAsTouchedAndUpdateValidity()), tap(() => this._broadcastSubmittingEvents()), switchMap(() => this._waitUntilStatusPending()), tap(() => this._setupActiveSubmitButton()), mergeMap(() => {
200
+ return this.ngForm.status === 'INVALID'
201
+ ? this._formInvalidState$
202
+ : this._formValidState$;
203
+ }), catchError((e, source$) => {
204
+ this._handleError(e);
205
+ return source$;
206
+ }), tap((submittedEvent) => {
207
+ this._completeSubmit(true, submittedEvent);
208
+ }), takeUntil(this._destroy$))
209
+ .subscribe(() => { });
210
+ }
211
+ _listenWindowClose() {
212
+ fromEvent(window, 'beforeunload')
213
+ .pipe(takeUntil(this._destroy$))
214
+ .subscribe((event) => {
215
+ if (this.confirm && this.confirmBrowser && this.ngForm.dirty) {
216
+ event.returnValue = false;
217
+ }
218
+ });
219
+ }
220
+ _listenHotKeys() {
221
+ this._ngZone.runOutsideAngular(() => {
222
+ fromEvent(document, 'keydown')
223
+ .pipe(takeUntil(this._destroy$))
224
+ .subscribe((event) => {
225
+ if (this._dialogBackdropEscape && event.code === 'Escape') {
226
+ const dialog = document.getElementById(this._dialogRef.id);
227
+ const paths = event.composedPath();
228
+ if (paths) {
229
+ paths.forEach(item => {
230
+ if (dialog === item) {
231
+ this._ngZone.run(() => {
232
+ this._formClose();
233
+ });
234
+ }
235
+ });
236
+ }
237
+ }
238
+ if ((event.ctrlKey || event.metaKey) && event.code === 'KeyS') {
239
+ event.preventDefault();
240
+ if (this.shortcuts) {
241
+ if (this._elementInForm(document.activeElement)) {
242
+ this.ngForm.ngSubmit.next();
243
+ }
244
+ }
245
+ }
246
+ });
247
+ });
248
+ }
249
+ _formClose() {
250
+ if (this.confirm && this.confirmDialog) {
251
+ this.triggerConfirm()
252
+ .pipe(filter((result) => confirmResultContinue(result)), switchMap((result) => {
253
+ return result === ConfirmResult.Pristine || result === ConfirmResult.Discard
254
+ ? of(null)
255
+ : this.submitted.asObservable();
256
+ }), takeUntil(this._destroy$))
257
+ .subscribe((result) => {
258
+ this._dialogRef.close(result === null || result === void 0 ? void 0 : result.response);
259
+ });
260
+ }
261
+ else {
262
+ this._dialogRef.close(null);
263
+ }
264
+ }
265
+ _registerDialogClose(directive) {
266
+ if (!directive.registered) {
267
+ directive.registered = true;
268
+ directive.clicked$
269
+ .pipe(takeUntil(this._destroy$))
270
+ .subscribe(() => {
271
+ this._formClose();
272
+ });
273
+ }
274
+ }
275
+ _getActiveButton() {
276
+ const activeButton = this._submitButtons.find(button => {
277
+ return button.active;
278
+ });
279
+ return activeButton ? activeButton : this._submitButtons.first;
280
+ }
281
+ _elementInForm(el) {
282
+ if (el.isSameNode(this._element.nativeElement)) {
283
+ return true;
284
+ }
285
+ else if (el.parentElement) {
286
+ return this._elementInForm(el.parentElement);
287
+ }
288
+ return false;
289
+ }
290
+ _completeSubmit(success, submitEvent) {
291
+ if (success) {
292
+ this.ngForm.control.markAsPristine();
293
+ this.createSnapshot();
294
+ this.submitted.emit(submitEvent);
295
+ }
296
+ else {
297
+ this._resetButtons();
298
+ }
299
+ if (this._activeSubmitButton) {
300
+ if (success) {
301
+ this._activeSubmitButton.success();
302
+ }
303
+ else {
304
+ this._activeSubmitButton.error();
305
+ }
306
+ }
307
+ this._status$.next(FormStatus.Submitted);
308
+ if (success) {
309
+ this._status$.next(FormStatus.Success);
310
+ }
311
+ else {
312
+ this._status$.next(FormStatus.Error);
313
+ }
314
+ this._status$.next(FormStatus.Completing);
315
+ const resetDelay = success ? this.successDelay : this.errorDelay;
316
+ of(true)
317
+ .pipe(delay(resetDelay), first(), takeUntil(this._destroy$)).subscribe(() => {
318
+ if (this.ngForm.form.status === 'VALID') {
319
+ this._status$.next(FormStatus.Valid);
320
+ }
321
+ else {
322
+ this._status$.next(FormStatus.Invalid);
323
+ }
324
+ this._resetButtons();
325
+ this._updateDirtySubmitButtons();
326
+ });
327
+ }
328
+ _resetButtons() {
329
+ this._submitButtons.forEach((button) => {
330
+ button.reset();
331
+ });
332
+ }
333
+ _registerConfirm() {
334
+ this.ngForm.form.valueChanges
335
+ .pipe(takeUntil(this._destroy$))
336
+ .subscribe((changes) => {
337
+ if (this.confirm) {
338
+ const existing = Object.keys(this._snapshot);
339
+ Object.keys(changes)
340
+ .forEach((name) => {
341
+ if (existing.indexOf(name) === -1) {
342
+ this._snapshot[name] = changes[name];
343
+ }
344
+ });
345
+ }
346
+ });
347
+ }
348
+ _registerDrawerClose() {
349
+ if (this._drawerRef) {
350
+ this._drawerRef.closeStart$
351
+ .pipe(takeUntil(this._destroy$))
352
+ .subscribe((subscriber) => {
353
+ if (this.submitting) {
354
+ this._status$
355
+ .pipe(filter((status) => status === FormStatus.Success || status === FormStatus.Error), takeUntil(this._destroy$))
356
+ .subscribe((status) => {
357
+ if (status === FormStatus.Success) {
358
+ subscriber.next();
359
+ subscriber.complete();
360
+ }
361
+ else {
362
+ subscriber.error();
363
+ }
364
+ });
365
+ }
366
+ else {
367
+ subscriber.next();
368
+ subscriber.complete();
369
+ }
370
+ });
371
+ }
372
+ }
373
+ _registerConfirmDrawerClose() {
374
+ if (this._drawerRef) {
375
+ this._drawerRef.closeStart$
376
+ .pipe(switchMap((subscriber) => {
377
+ return iif(() => this.confirm && this.confirmDrawer, this.triggerConfirm()
378
+ .pipe(map((result) => confirmResultContinue(result)), tap((result) => {
379
+ if (result) {
380
+ subscriber.next();
381
+ subscriber.complete();
382
+ }
383
+ })), defer(() => {
384
+ subscriber.next();
385
+ subscriber.complete();
386
+ }));
387
+ }), takeUntil(this._destroy$))
388
+ .subscribe();
389
+ }
390
+ }
391
+ _registerConfirmTabs() {
392
+ if (this.tabGroup) {
393
+ this.registerConfirmTabGroup(this.tabGroup);
394
+ }
395
+ this.registerConfirmTabGroups(this._tabGroups.toArray());
396
+ this._tabGroups.changes
397
+ .pipe(takeUntil(this._destroy$))
398
+ .subscribe(() => {
399
+ this.registerConfirmTabGroups(this._tabGroups.toArray());
400
+ });
401
+ }
402
+ registerConfirmTabGroups(tabGroups) {
403
+ tabGroups.forEach((tabGroup) => {
404
+ this.registerConfirmTabGroup(tabGroup);
405
+ });
406
+ }
407
+ registerConfirmTabGroup(tabGroup) {
408
+ const confirmTabGroup = tabGroup;
409
+ if (!confirmTabGroup._originalHandleClick) {
410
+ confirmTabGroup._originalHandleClick = tabGroup._handleClick;
411
+ confirmTabGroup._handlClick$ = new Subject();
412
+ confirmTabGroup._handleClick = (tab, tabHeader, idx) => {
413
+ if (confirmTabGroup._handlClick$.observers.length) {
414
+ confirmTabGroup._handlClick$.next({ tab, tabHeader, idx });
415
+ }
416
+ else {
417
+ confirmTabGroup._originalHandleClick(tab, tabHeader, idx);
418
+ }
419
+ };
420
+ }
421
+ confirmTabGroup._handlClick$
422
+ .pipe(takeUntil(this._destroy$))
423
+ .subscribe((event) => {
424
+ if (!this.submitting) {
425
+ if (this.confirm && this.confirmTabs) {
426
+ this.triggerConfirm()
427
+ .pipe(takeUntil(this._destroy$))
428
+ .subscribe((result) => {
429
+ if (confirmResultContinue(result)) {
430
+ confirmTabGroup.selectedIndex = event.idx;
431
+ }
432
+ });
433
+ }
434
+ else {
435
+ confirmTabGroup._originalHandleClick(event.tab, event.tabHeader, event.idx);
436
+ }
437
+ }
438
+ });
439
+ }
440
+ _registerConfirmDialogClose() {
441
+ if (this._dialogRef) {
442
+ this.formDialogClose.forEach(item => {
443
+ this._registerDialogClose(item);
444
+ });
445
+ this.formDialogClose.changes
446
+ .pipe(takeUntil(this._destroy$))
447
+ .subscribe((e) => {
448
+ e.forEach(item => {
449
+ this._registerDialogClose(item);
450
+ });
451
+ });
452
+ }
453
+ }
454
+ _registerConfirmDialogBackdropEscape() {
455
+ this._dialogBackdropEscape = this._dialogRef && this._dialogRef.disableClose !== true;
456
+ if (this._dialogRef && !this._dialogRef.disableClose) {
457
+ this._dialogRef.disableClose = true;
458
+ this._dialogRef.backdropClick()
459
+ .pipe(takeUntil(this._destroy$))
460
+ .subscribe(() => {
461
+ this._formClose();
462
+ });
463
+ this._destroy$
464
+ .subscribe(() => {
465
+ this._dialogRef.disableClose = false;
466
+ });
467
+ }
468
+ }
469
+ _registerAutocomplete() {
470
+ this._registerControl = this.ngForm.form.registerControl.bind(this.ngForm.form);
471
+ this.ngForm.form.registerControl = (name, control) => {
472
+ const el = this._element.nativeElement.querySelector(`input[name='${name}']`);
473
+ if (el) {
474
+ el.setAttribute('name', name + '_' + guid());
475
+ if (!el.getAttribute('autocomplete')) {
476
+ el.setAttribute('autocomplete', 'none');
477
+ }
478
+ }
479
+ return this._registerControl(name, control);
480
+ };
481
+ }
482
+ _registerDirtySubmitButton() {
483
+ if (!this.ngForm) {
484
+ return;
485
+ }
486
+ this.ngForm.form.valueChanges
487
+ .pipe(takeUntil(this._destroy$))
488
+ .subscribe(() => {
489
+ this._updateDirtySubmitButtons();
490
+ });
491
+ this._submitButtons.changes
492
+ .pipe(takeUntil(this._destroy$))
493
+ .subscribe(() => {
494
+ this._updateDirtySubmitButtons();
495
+ });
496
+ }
497
+ _updateDirtySubmitButtons() {
498
+ this._submitButtons
499
+ .forEach((submitButton) => {
500
+ if (!this.confirm || !this.dirtySubmitButton || this.ngForm.dirty || !submitButton.dirtySubmit) {
501
+ submitButton.enable();
502
+ }
503
+ else {
504
+ submitButton.disable();
505
+ }
506
+ });
507
+ }
508
+ _broadcastSubmittingEvents() {
509
+ this._status$.next(FormStatus.Submitting);
510
+ this._form.broadcast('submit', this.ngForm);
511
+ }
512
+ _markControlsAsTouchedAndUpdateValidity() {
513
+ Object.values(this.ngForm.controls)
514
+ .forEach(control => {
515
+ control.markAsDirty();
516
+ control.markAsTouched();
517
+ control.updateValueAndValidity();
518
+ });
519
+ }
520
+ _setupActiveSubmitButton() {
521
+ this._activeSubmitButton = this._getActiveButton();
522
+ this._resetButtons();
523
+ if (this._activeSubmitButton) {
524
+ this._activeSubmitButton.process();
525
+ }
526
+ }
527
+ _waitUntilStatusPending() {
528
+ return this.ngForm.statusChanges
529
+ .pipe(startWith(this.ngForm.status), first((state) => state !== 'PENDING'));
530
+ }
531
+ _handleError(e) {
532
+ console.log('%c Form Submit ', 'color: white; background-color: #D33F49', 'Error occured');
533
+ console.group('Error Details:');
534
+ console.log('Message: ', e);
535
+ console.log('FormRef: ', this);
536
+ if (this.ngForm.invalid) {
537
+ const errors = getFormErrors(this.ngForm.control, null);
538
+ console.log('Validation Errors: ', errors);
539
+ }
540
+ console.groupEnd();
541
+ this._completeSubmit(false, null);
542
+ }
543
+ }
544
+ FsFormDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsFormDirective, deps: [{ token: NgForm }, { token: i1.FsForm }, { token: i0.ElementRef }, { token: i2.FsMessage }, { token: i3.FsPrompt }, { token: i0.NgZone }, { token: MatDialogRef, optional: true }, { token: DrawerRef, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
545
+ FsFormDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.2.16", type: FsFormDirective, selector: "[fsForm]", inputs: { wrapperSelector: "wrapperSelector", messageSelector: "messageSelector", hintSelector: "hintSelector", labelSelector: "labelSelector", autocomplete: "autocomplete", shortcuts: "shortcuts", confirm: "confirm", confirmDialog: "confirmDialog", confirmDrawer: "confirmDrawer", confirmBrowser: "confirmBrowser", confirmTabs: "confirmTabs", dirtySubmitButton: "dirtySubmitButton", submit: "submit", successDelay: "successDelay", errorDelay: "errorDelay", tabGroup: "tabGroup" }, outputs: { submitEvent: "fsForm", invalid: "invalid", valid: "valid", submitted: "submitted", reseted: "reseted", cleared: "cleared" }, host: { properties: { "class.fs-form": "this.fsformClass" } }, queries: [{ propertyName: "formDialogClose", predicate: FsFormDialogCloseDirective, descendants: true }, { propertyName: "_tabGroups", predicate: MatTabGroup, descendants: true }], usesOnChanges: true, ngImport: i0 });
546
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsFormDirective, decorators: [{
547
+ type: Directive,
548
+ args: [{
549
+ selector: '[fsForm]',
550
+ }]
551
+ }], ctorParameters: function () { return [{ type: i4.NgForm, decorators: [{
552
+ type: Inject,
553
+ args: [NgForm]
554
+ }] }, { type: i1.FsForm }, { type: i0.ElementRef }, { type: i2.FsMessage }, { type: i3.FsPrompt }, { type: i0.NgZone }, { type: i5.MatDialogRef, decorators: [{
555
+ type: Optional
556
+ }, {
557
+ type: Inject,
558
+ args: [MatDialogRef]
559
+ }] }, { type: i6.DrawerRef, decorators: [{
560
+ type: Optional
561
+ }, {
562
+ type: Inject,
563
+ args: [DrawerRef]
564
+ }] }]; }, propDecorators: { wrapperSelector: [{
565
+ type: Input
566
+ }], messageSelector: [{
567
+ type: Input
568
+ }], hintSelector: [{
569
+ type: Input
570
+ }], labelSelector: [{
571
+ type: Input
572
+ }], autocomplete: [{
573
+ type: Input
574
+ }], shortcuts: [{
575
+ type: Input
576
+ }], confirm: [{
577
+ type: Input
578
+ }], confirmDialog: [{
579
+ type: Input
580
+ }], confirmDrawer: [{
581
+ type: Input
582
+ }], confirmBrowser: [{
583
+ type: Input
584
+ }], confirmTabs: [{
585
+ type: Input
586
+ }], dirtySubmitButton: [{
587
+ type: Input
588
+ }], submit: [{
589
+ type: Input
590
+ }], successDelay: [{
591
+ type: Input
592
+ }], errorDelay: [{
593
+ type: Input
594
+ }], tabGroup: [{
595
+ type: Input
596
+ }], submitEvent: [{
597
+ type: Output,
598
+ args: ['fsForm']
599
+ }], invalid: [{
600
+ type: Output
601
+ }], valid: [{
602
+ type: Output
603
+ }], submitted: [{
604
+ type: Output
605
+ }], reseted: [{
606
+ type: Output
607
+ }], cleared: [{
608
+ type: Output
609
+ }], fsformClass: [{
610
+ type: HostBinding,
611
+ args: ['class.fs-form']
612
+ }], formDialogClose: [{
613
+ type: ContentChildren,
614
+ args: [FsFormDialogCloseDirective, { descendants: true }]
615
+ }], _tabGroups: [{
616
+ type: ContentChildren,
617
+ args: [MatTabGroup, { descendants: true }]
618
+ }] } });
619
619
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybS5kaXJlY3RpdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvYXBwL2RpcmVjdGl2ZXMvZm9ybS9mb3JtLmRpcmVjdGl2ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBRUwsZUFBZSxFQUNmLFNBQVMsRUFDVCxVQUFVLEVBQ1YsWUFBWSxFQUNaLFdBQVcsRUFDWCxNQUFNLEVBQ04sS0FBSyxFQUNMLE1BQU0sRUFJTixRQUFRLEVBQ1IsTUFBTSxFQUNOLFNBQVMsR0FFVixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQW1CLE1BQU0sRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRXpELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN4RCxPQUFPLEVBQVUsV0FBVyxFQUFnQixNQUFNLHdCQUF3QixDQUFDO0FBRTNFLE9BQU8sRUFBRSxTQUFTLEVBQUUsV0FBVyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDN0QsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUMxQyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFFL0MsT0FBTyxFQUNMLGVBQWUsRUFDZixLQUFLLEVBQ0wsU0FBUyxFQUNULEdBQUcsRUFDSCxZQUFZLEVBRVosRUFBRSxFQUNGLE9BQU8sRUFDUCxVQUFVLEVBQ1gsTUFBTSxNQUFNLENBQUM7QUFDZCxPQUFPLEVBQ0wsVUFBVSxFQUNWLEtBQUssRUFDTCxNQUFNLEVBQ04sS0FBSyxFQUNMLEdBQUcsRUFDSCxRQUFRLEVBQ1IsU0FBUyxFQUNULFNBQVMsRUFDVCxJQUFJLEVBQ0osU0FBUyxFQUNULEdBQUcsRUFDSixNQUFNLGdCQUFnQixDQUFDO0FBRXhCLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztB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ZTtzQkFEckIsZUFBZTt1QkFBQywwQkFBMEIsRUFBRSxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUU7Z0JBSTFELFVBQVU7c0JBRGpCLGVBQWU7dUJBQUMsV0FBVyxFQUFFLEVBQUUsV0FBVyxFQUFFLElBQUksRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEFmdGVyQ29udGVudEluaXQsXG4gIENvbnRlbnRDaGlsZHJlbixcbiAgRGlyZWN0aXZlLFxuICBFbGVtZW50UmVmLFxuICBFdmVudEVtaXR0ZXIsXG4gIEhvc3RCaW5kaW5nLFxuICBJbmplY3QsXG4gIElucHV0LFxuICBOZ1pvbmUsXG4gIE9uQ2hhbmdlcyxcbiAgT25EZXN0cm95LFxuICBPbkluaXQsXG4gIE9wdGlvbmFsLFxuICBPdXRwdXQsXG4gIFF1ZXJ5TGlzdCxcbiAgU2ltcGxlQ2hhbmdlcyxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBBYnN0cmFjdENvbnRyb2wsIE5nRm9ybSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcblxuaW1wb3J0IHsgTWF0RGlhbG9nUmVmIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZGlhbG9nJztcbmltcG9ydCB7IE1hdFRhYiwgTWF0VGFiR3JvdXAsIE1hdFRhYkhlYWRlciB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3RhYnMnO1xuXG5pbXBvcnQgeyBGc01lc3NhZ2UsIE1lc3NhZ2VNb2RlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvbWVzc2FnZSc7XG5pbXBvcnQgeyBGc1Byb21wdCB9IGZyb20gJ0BmaXJlc3RpdGNoL3Byb21wdCc7XG5pbXBvcnQgeyBndWlkIH0gZnJvbSAnQGZpcmVzdGl0Y2gvY29tbW9uJztcbmltcG9ydCB7IERyYXdlclJlZiB9IGZyb20gJ0BmaXJlc3RpdGNoL2RyYXdlcic7XG5cbmltcG9ydCB7XG4gIEJlaGF2aW9yU3ViamVjdCxcbiAgZGVmZXIsXG4gIGZyb21FdmVudCxcbiAgaWlmLFxuICBpc09ic2VydmFibGUsXG4gIE9ic2VydmFibGUsXG4gIG9mLFxuICBTdWJqZWN0LFxuICB0aHJvd0Vycm9yXG59IGZyb20gJ3J4anMnO1xuaW1wb3J0IHtcbiAgY2F0Y2hFcnJvcixcbiAgZGVsYXksXG4gIGZpbHRlcixcbiAgZmlyc3QsXG4gIG1hcCxcbiAgbWVyZ2VNYXAsXG4gIHN0YXJ0V2l0aCxcbiAgc3dpdGNoTWFwLFxuICB0YWtlLFxuICB0YWtlVW50aWwsXG4gIHRhcFxufSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbmltcG9ydCB7IGNvbmZpcm1VbnNhdmVkIH0gZnJvbSAnLi4vLi4vaGVscGVycy9jb25maXJtLXVuc2F2ZWQnO1xuaW1wb3J0IHsgRnNGb3JtRGlhbG9nQ2xvc2VEaXJlY3RpdmUgfSBmcm9tICcuLi9mb3JtLWRpYWxvZy1jbG9zZS5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgRnNTdWJtaXRCdXR0b25EaXJlY3RpdmUgfSBmcm9tICcuLi9zdWJtaXQtYnV0dG9uLmRpcmVjdGl2ZSc7XG5pbXBvcnQgeyBDb25maXJtQ29uZmlnLCBTdWJtaXR0ZWRFdmVudCwgQ29uZmlybVRhYkdyb3VwIH0gZnJvbSAnLi8uLi8uLi9pbnRlcmZhY2VzJztcbmltcG9ydCB7IENvbmZpcm1SZXN1bHQgfSBmcm9tICcuLy4uLy4uL2VudW1zL2NvbmZpcm0tcmVzdWx0JztcbmltcG9ydCB7IEZzRm9ybSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL2ZzZm9ybS5zZXJ2aWNlJztcbmltcG9ydCB7IFN1Ym1pdEV2ZW50IH0gZnJvbSAnLi8uLi8uLi9pbnRlcmZhY2VzL3N1Ym1pdC1ldmVudCc7XG5pbXBvcnQgeyBGb3JtU3RhdHVzIH0gZnJvbSAnLi8uLi8uLi9lbnVtcy9mb3JtLXN0YXR1cyc7XG5pbXBvcnQgeyBjb25maXJtUmVzdWx0Q29udGludWUgfSBmcm9tICcuLi8uLi9oZWxwZXJzL2NvbmZpcm0tcmVzdWx0LWNvbnRpbnVlJztcbmltcG9ydCB7IGdldEZvcm1FcnJvcnMgfSBmcm9tICcuLi8uLi9oZWxwZXJzL2dldC1mb3JtLWVycm9ycyc7XG5cblxuQERpcmVjdGl2ZSh7XG4gIHNlbGVjdG9yOiAnW2ZzRm9ybV0nLFxufSlcbmV4cG9ydCBjbGFzcyBGc0Zvcm1EaXJlY3RpdmUgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSwgQWZ0ZXJDb250ZW50SW5pdCwgT25DaGFuZ2VzIHtcblxuICBASW5wdXQoKVxuICBwdWJsaWMgd3JhcHBlclNlbGVjdG9yID0gJy5mcy1mb3JtLXdyYXBwZXIsLm1hdC1mb3JtLWZpZWxkJztcblxuICBASW5wdXQoKVxuICBwdWJsaWMgbWVzc2FnZVNlbGVjdG9yID0gJy5mcy1mb3JtLW1lc3NhZ2UsLm1hdC1mb3JtLWZpZWxkLXN1YnNjcmlwdC13cmFwcGVyJztcblxuICBASW5wdXQoKVxuICBwdWJsaWMgaGludFNlbGVjdG9yID0gJy5mcy1mb3JtLWhpbnQsLm1hdC1mb3JtLWZpZWxkLWhpbnQtd3JhcHBlcic7XG5cbiAgQElucHV0KClcbiAgcHVibGljIGxhYmVsU2VsZWN0b3IgPSAnLmZzLWZvcm0tbGFiZWwsLm1hdC1mb3JtLWZpZWxkLWxhYmVsJztcblxuICBASW5wdXQoKVxuICBwdWJsaWMgYXV0b2NvbXBsZXRlID0gZmFsc2U7XG5cbiAgQElucHV0KClcbiAgcHVibGljIHNob3J0Y3V0cyA9IHRydWU7IC8vIEN0cmwgKyBzXG5cbiAgQElucHV0KClcbiAgcHVibGljIGNvbmZpcm06IENvbmZpcm1Db25maWcgfCBib29sZWFuID0gdHJ1ZTtcblxuICBASW5wdXQoKVxuICBwdWJsaWMgY29uZmlybURpYWxvZyA9IHRydWU7XG5cbiAgQElucHV0KClcbiAgcHVibGljIGNvbmZpcm1EcmF3ZXIgPSB0cnVlO1xuXG4gIEBJbnB1dCgpXG4gIHB1YmxpYyBjb25maXJtQnJvd3NlciA9IHRydWU7XG5cbiAgQElucHV0KClcbiAgcHVibGljIGNvbmZpcm1UYWJzID0gdHJ1ZTtcblxuICBASW5wdXQoKVxuICBwdWJsaWMgZGlydHlTdWJtaXRCdXR0b24gPSB0cnVlO1xuXG4gIEBJbnB1dCgpXG4gIHB1YmxpYyBzdWJtaXQ6IChldmVudDogU3VibWl0RXZlbnQpID0+IE9ic2VydmFibGU8YW55PjtcblxuICBASW5wdXQoKVxuICBwdWJsaWMgc3VjY2Vzc0RlbGF5ID0gMDtcblxuICBASW5wdXQoKVxuICBwdWJsaWMgZXJyb3JEZWxheSA9IDEwMDA7XG5cbiAgQElucHV0KClcbiAgcHVibGljIHRhYkdyb3VwOiBNYXRUYWJHcm91cDtcblxuICBAT3V0cHV0KCdmc0Zvcm0nKVxuICBwdWJsaWMgc3VibWl0RXZlbnQ6IEV2ZW50RW1pdHRlcjxTdWJtaXRFdmVudD4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgQE91dHB1dCgpXG4gIHB1YmxpYyBpbnZhbGlkOiBFdmVudEVtaXR0ZXI8U3VibWl0RXZlbnQ+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gIEBPdXRwdXQoKVxuICBwdWJsaWMgdmFsaWQ6IEV2ZW50RW1pdHRlcjxTdWJtaXRFdmVudD4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgQE91dHB1dCgpXG4gIHB1YmxpYyBzdWJtaXR0ZWQ6IEV2ZW50RW1pdHRlcjxTdWJtaXRFdmVudD4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgQE91dHB1dCgpXG4gIHB1YmxpYyByZXNldGVkOiBFdmVudEVtaXR0ZXI8U3VibWl0RXZlbnQ+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gIEBPdXRwdXQoKVxuICBwdWJsaWMgY2xlYXJlZDogRXZlbnRFbWl0dGVyPFN1Ym1pdEV2ZW50PiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICBASG9zdEJpbmRpbmcoJ2NsYXNzLmZzLWZvcm0nKVxuICBwdWJsaWMgZnNmb3JtQ2xhc3MgPSB0cnVlO1xuXG4gIEBDb250ZW50Q2hpbGRyZW4oRnNGb3JtRGlhbG9nQ2xvc2VEaXJlY3RpdmUsIHsgZGVzY2VuZGFudHM6IHRydWUgfSlcbiAgcHVibGljIGZvcm1EaWFsb2dDbG9zZTogUXVlcnlMaXN0PEZzRm9ybURpYWxvZ0Nsb3NlRGlyZWN0aXZlPjtcblxuICBAQ29udGVudENoaWxkcmVuKE1hdFRhYkdyb3VwLCB7IGRlc2NlbmRhbnRzOiB0cnVlIH0pXG4gIHByaXZhdGUgX3RhYkdyb3VwczogUXVlcnlMaXN0PE1hdFRhYkdyb3VwPiA9IG5ldyBRdWVyeUxpc3QoKTtcblxuICBwcml2YXRlIF9zdWJtaXRCdXR0b25zOiBRdWVyeUxpc3Q8RnNTdWJtaXRCdXR0b25EaXJlY3RpdmU+ID0gbmV3IFF1ZXJ5TGlzdCgpO1xuICBwcml2YXRlIF9yZWdpc3RlckNvbnRyb2w7XG4gIHByaXZhdGUgX2FjdGl2ZVN1Ym1pdEJ1dHRvbjogRnNTdWJtaXRCdXR0b25EaXJlY3RpdmU7XG4gIHByaXZhdGUgX2RpYWxvZ0JhY2tkcm9wRXNjYXBlID0gZmFsc2U7XG4gIHByaXZhdGUgX3NuYXBzaG90OiB7IFtrZXk6IHN0cmluZ106IHVua25vd24gfSA9IHt9O1xuICBwcml2YXRlIF9zdGF0dXMkID0gbmV3IEJlaGF2aW9yU3ViamVjdChGb3JtU3RhdHVzLlZhbGlkKTtcbiAgcHJpdmF0ZSBfZGVzdHJveSQgPSBuZXcgU3ViamVjdCgpO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIEBJbmplY3QoTmdGb3JtKVxuICAgIHB1YmxpYyBuZ0Zvcm06IE5nRm9ybSxcbiAgICBwcml2YXRlIF9mb3JtOiBGc0Zvcm0sXG4gICAgcHJpdmF0ZSBfZWxlbWVudDogRWxlbWVudFJlZixcbiAgICBwcml2YXRlIF9tZXNzYWdlOiBGc01lc3NhZ2UsXG4gICAgcHJpdmF0ZSBfcHJvbXB0OiBGc1Byb21wdCxcbiAgICBwcml2YXRlIF9uZ1pvbmU6IE5nWm9uZSxcblxuICAgIEBPcHRpb25hbCgpIEBJbmplY3QoTWF0RGlhbG9nUmVmKVxuICAgIHByaXZhdGUgX2RpYWxvZ1JlZjogTWF0RGlhbG9nUmVmPGFueT4sXG5cbiAgICBAT3B0aW9uYWwoKSBASW5qZWN0KERyYXdlclJlZilcbiAgICBwcml2YXRlIF9kcmF3ZXJSZWY6IERyYXdlclJlZjxhbnk+LFxuICApIHt9XG5cbiAgcHVibGljIGdldCBzdWJtaXR0aW5nKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLl9zdGF0dXMkLmdldFZhbHVlKCkgPT09IEZvcm1TdGF0dXMuU3VibWl0dGluZztcbiAgfVxuXG4gIHB1YmxpYyBnZXQgY29tcGxldGluZygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5fc3RhdHVzJC5nZXRWYWx1ZSgpID09PSBGb3JtU3RhdHVzLkNvbXBsZXRpbmc7XG4gIH1cblxuICBwcml2YXRlIGdldCBfc3VibWl0RXZlbnQoKTogU3VibWl0RXZlbnQge1xuICAgIHJldHVybiB7XG4gICAgICBuZ0Zvcm06IHRoaXMubmdGb3JtLFxuICAgICAgc3VibWl0dGVyOiB0aGlzLl9zdWJtaXR0ZXIsXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0IF9mb3JtVmFsaWRTdGF0ZSQoKTogT2JzZXJ2YWJsZTxTdWJtaXR0ZWRFdmVudD4ge1xuICAgIHRoaXMuX2Zvcm0uYnJvYWRjYXN0KCd2YWxpZCcsIHRoaXMuX3N1Ym1pdEV2ZW50KTtcbiAgICB0aGlzLnN1Ym1pdEV2ZW50LmVtaXQodGhpcy5fc3VibWl0RXZlbnQpO1xuICAgIHRoaXMudmFsaWQuZW1pdCh0aGlzLl9zdWJtaXRFdmVudCk7XG5cbiAgICBjb25zdCBzdWJtaXR0ZWRFdmVudDogU3VibWl0dGVkRXZlbnQgPSB7XG4gICAgICBuZ0Zvcm06IHRoaXMubmdGb3JtLFxuICAgICAgc3VibWl0dGVyOiB0aGlzLl9zdWJtaXR0ZXIsXG4gICAgICByZXNwb25zZTogbnVsbFxuICAgIH07XG5cbiAgICBpZiAoIXRoaXMuc3VibWl0KSB7XG4gICAgICByZXR1cm4gb2Yoc3VibWl0dGVkRXZlbnQpO1xuICAgIH1cblxuICAgIGNvbnN0IHJlc3VsdCA9IHRoaXMuc3VibWl0KHRoaXMuX3N1Ym1pdEV2ZW50KTtcblxuICAgIGlmICghaXNPYnNlcnZhYmxlKHJlc3VsdCkpIHtcbiAgICAgIHJldHVybiBvZihzdWJtaXR0ZWRFdmVudCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdFxuICAgICAgLnBpcGUoXG4gICAgICAgIG1hcCgocmVzcG9uc2UpID0+IHtcbiAgICAgICAgICBzdWJtaXR0ZWRFdmVudC5yZXNwb25zZSA9IHJlc3BvbnNlO1xuXG4gICAgICAgICAgcmV0dXJuIHN1Ym1pdHRlZEV2ZW50O1xuICAgICAgICB9KVxuICAgICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0IF9mb3JtSW52YWxpZFN0YXRlJCgpOiBPYnNlcnZhYmxlPG5ldmVyPiB7XG4gICAgdGhpcy5fZm9ybS5icm9hZGNhc3QoJ2ludmFsaWQnLCB0aGlzLl9zdWJtaXRFdmVudCk7XG5cbiAgICBpZiAodGhpcy5pbnZhbGlkKSB7XG4gICAgICB0aGlzLmludmFsaWQuZW1pdCh0aGlzLl9zdWJtaXRFdmVudCk7XG4gICAgfVxuXG4gICAgY29uc3QgbWVzc2FnZSA9ICdDaGFuZ2VzIG5vdCBzYXZlZC4gUGxlYXNlIHJldmlldyBlcnJvcnMgaGlnaGxpZ2h0ZWQgaW4gcmVkLic7XG4gICAgdGhpcy5fbWVzc2FnZS5lcnJvcihtZXNzYWdlLCB7IG1vZGU6IE1lc3NhZ2VNb2RlLlRvYXN0IH0pO1xuXG4gICAgY29uc3QgZWwgPSB0aGlzLl9lbGVtZW50Lm5hdGl2ZUVsZW1lbnQucXVlcnlTZWxlY3RvcignLm5nLWludmFsaWQnKTtcblxuICAgIGlmIChlbCkge1xuICAgICAgZWwuc2Nyb2xsSW50b1ZpZXcoeyBiZWhhdmlvcjogJ3Ntb290aCcsIGJsb2NrOiAnY2VudGVyJyB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhyb3dFcnJvcignRm9ybSB2YWxpZGF0aW9uIGVycm9yJyk7XG4gIH1cblxuICBwcml2YXRlIGdldCBfc3VibWl0dGVyKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuX2FjdGl2ZVN1Ym1pdEJ1dHRvblxuICAgICAgPyB0aGlzLl9hY3RpdmVTdWJtaXRCdXR0b24ubmFtZVxuICAgICAgOiBudWxsO1xuICB9XG5cbiAgcHVibGljIG5nT25Jbml0KCkge1xuICAgIHRoaXMuX3JlZ2lzdGVyQ29uZmlybURpYWxvZ0JhY2tkcm9wRXNjYXBlKCk7XG4gICAgdGhpcy5fbGlzdGVuSG90S2V5cygpO1xuICAgIHRoaXMuX2xpc3RlbldpbmRvd0Nsb3NlKCk7XG4gICAgdGhpcy5fbGlzdGVuU3VibWl0KCk7XG5cbiAgICBpZiAoIXRoaXMuYXV0b2NvbXBsZXRlKSB7XG4gICAgICB0aGlzLl9yZWdpc3RlckF1dG9jb21wbGV0ZSgpO1xuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgaWYgKGNoYW5nZXMuY29uZmlybSkge1xuICAgICAgdGhpcy5fdXBkYXRlRGlydHlTdWJtaXRCdXR0b25zKCk7XG4gICAgfVxuICB9XG5cbiAgcHVibGljIG5nQWZ0ZXJDb250ZW50SW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLl9yZWdpc3RlckNvbmZpcm0oKTtcbiAgICB0aGlzLl9yZWdpc3RlckNvbmZpcm1EaWFsb2dDbG9zZSgpO1xuICAgIHRoaXMuX3JlZ2lzdGVyQ29uZmlybURyYXdlckNsb3NlKCk7XG4gICAgdGhpcy5fcmVnaXN0ZXJDb25maXJtVGFicygpO1xuICAgIHRoaXMuX3JlZ2lzdGVyRHJhd2VyQ2xvc2UoKTtcbiAgICB0aGlzLl9yZWdpc3RlckRpcnR5U3VibWl0QnV0dG9uKCk7XG4gIH1cblxuICBwdWJsaWMgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5fZGVzdHJveSQubmV4dCgpO1xuICAgIHRoaXMuX2Rlc3Ryb3kkLmNvbXBsZXRlKCk7XG4gIH1cblxuICBwdWJsaWMgY3JlYXRlU25hcHNob3QoKTogdm9pZCB7XG4gICAgdGhpcy5fc25hcHNob3QgPSB0aGlzLm5nRm9ybS52YWx1ZTtcbiAgfVxuXG4gIHB1YmxpYyByZXNldCgpOiB2b2lkIHtcbiAgICB0aGlzLm5nRm9ybS5yZXNldEZvcm0oKTtcblxuICAgIE9iamVjdC5rZXlzKHRoaXMubmdGb3JtLmNvbnRyb2xzKVxuICAgICAgLmZvckVhY2goKG5hbWU6IHN0cmluZykgPT4ge1xuICAgICAgICBjb25zdCBjb250cm9sID0gdGhpcy5uZ0Zvcm0uY29udHJvbHNbbmFtZV07XG4gICAgICAgIGNvbnRyb2wucmVzZXQodGhpcy5fc25hcHNob3RbbmFtZV0pO1xuICAgICAgfSk7XG4gICAgXG4gICAgdGhpcy5yZXNldGVkLmVtaXQoKTtcbiAgfVxuXG4gIHB1YmxpYyBjbGVhcigpOiB2b2lkIHtcbiAgICB0aGlzLm5nRm9ybS5yZXNldEZvcm0oKTtcbiAgICB0aGlzLmNsZWFyZWQuZW1pdCgpO1xuICB9XG5cbiAgcHVibGljIGRpcnR5KCk6IHZvaWQge1xuICAgIHRoaXMubmdGb3JtLmZvcm0ubWFya0FzRGlydHkoKTtcbiAgICB0aGlzLl91cGRhdGVEaXJ0eVN1Ym1pdEJ1dHRvbnMoKTtcbiAgfVxuXG4gIHB1YmxpYyB0cmlnZ2VyU3VibWl0KCk6IHZvaWQge1xuICAgIHRoaXMubmdGb3JtLm5nU3VibWl0Lm5leHQoKTtcbiAgfVxuXG4gIHB1YmxpYyB0cmlnZ2VyQ29uZmlybSgpOiBPYnNlcnZhYmxlPENvbmZpcm1SZXN1bHQ+IHtcbiAgICBjb25zdCBzdWJtaXR0ZWQgPSB0aGlzLnN1Ym1pdHRpbmcgPyB0aGlzLnN1Ym1pdHRlZC5hc09ic2VydmFibGUoKSA6IG9mKHt9KTtcblxuICAgIHJldHVybiBzdWJtaXR0ZWRcbiAgICAgIC5waXBlKFxuICAgICAgICB0YWtlKDEpLFxuICAgICAgICBtZXJnZU1hcCgoKSA9PiBjb25maXJtVW5zYXZlZCh0aGlzLCB0aGlzLl9wcm9tcHQpKSxcbiAgICAgICk7XG4gIH1cblxuICBwdWJsaWMgZW5hYmxlKCk6IHZvaWQge1xuICAgIHRoaXMubmdGb3JtLmNvbnRyb2wuZW5hYmxlKCk7XG5cbiAgICB0aGlzLl91cGRhdGVEaXJ0eVN1Ym1pdEJ1dHRvbnMoKTtcbiAgfVxuXG4gIHB1YmxpYyBkaXNhYmxlKCk6IHZvaWQge1xuICAgIHRoaXMubmdGb3JtLmNvbnRyb2wuZGlzYWJsZSgpO1xuXG4gICAgdGhpcy5fc3VibWl0QnV0dG9ucy5mb3JFYWNoKChidXR0b24pID0+IHtcbiAgICAgIGJ1dHRvbi5kaXNhYmxlKCk7XG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgYWRkU3VibWl0QnV0dG9uKHN1Ym1pdEJ1dHRvbjogRnNTdWJtaXRCdXR0b25EaXJlY3RpdmUpOiB2b2lkIHtcbiAgICB0aGlzLl9zdWJtaXRCdXR0b25zLnJlc2V0KFxuICAgICAgW1xuICAgICAgICAuLi50aGlzLl9zdWJtaXRCdXR0b25zLnRvQXJyYXkoKSxcbiAgICAgICAgc3VibWl0QnV0dG9uLFxuICAgICAgXSk7XG4gIH1cblxuICBwdWJsaWMgcmVtb3ZlU3VibWl0QnV0dG9uKHN1Ym1pdEJ1dHRvbjogRnNTdWJtaXRCdXR0b25EaXJlY3RpdmUpOiB2b2lkIHtcbiAgICB0aGlzLl9zdWJtaXRCdXR0b25zLnJlc2V0KFxuICAgICAgW1xuICAgICAgICAuLi50aGlzLl9zdWJtaXRCdXR0b25zLnRvQXJyYXkoKVxuICAgICAgICAuZmlsdGVyKChzdWJtaXRCdXR0b25fKSA9PiAoc3VibWl0QnV0dG9uICE9PSBzdWJtaXRCdXR0b25fKSksXG4gICAgICBdKTtcbiAgfVxuXG4gIHByaXZhdGUgX2xpc3RlblN1Ym1pdCgpOiB2b2lkIHtcbiAgICB0aGlzLm5nRm9ybVxuICAgICAgLm5nU3VibWl0XG4gICAgICAucGlwZShcbiAgICAgICAgdGFwKChldmVudCkgPT4ge1xuICAgICAgICAgIGV2ZW50Py5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB9KSxcbiAgICAgICAgZmlsdGVyKCgpID0+IHtcbiAgICAgICAgICByZXR1cm4gWyBGb3JtU3RhdHVzLlZhbGlkLCBGb3JtU3RhdHVzLkludmFsaWQgXVxuICAgICAgICAgICAgLmluY2x1ZGVzKHRoaXMuX3N0YXR1cyQuZ2V0VmFsdWUoKSk7XG4gICAgICAgIH0pLFxuICAgICAgICB0YXAoKCkgPT4gdGhpcy5fbWFya0NvbnRyb2xzQXNUb3VjaGVkQW5kVXBkYXRlVmFsaWRpdHkoKSksXG4gICAgICAgIHRhcCgoKSA9PiB0aGlzLl9icm9hZGNhc3RTdWJtaXR0aW5nRXZlbnRzKCkpLFxuICAgICAgICBzd2l0Y2hNYXAoKCkgPT4gdGhpcy5fd2FpdFVudGlsU3RhdHVzUGVuZGluZygpKSxcbiAgICAgICAgdGFwKCgpID0+IHRoaXMuX3NldHVwQWN0aXZlU3VibWl0QnV0dG9uKCkpLFxuICAgICAgICBtZXJnZU1hcCgoKSA9PiB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMubmdGb3JtLnN0YXR1cyA9PT0gJ0lOVkFMSUQnXG4gICAgICAgICAgICA/IHRoaXMuX2Zvcm1JbnZhbGlkU3RhdGUkXG4gICAgICAgICAgICA6IHRoaXMuX2Zvcm1WYWxpZFN0YXRlJDtcbiAgICAgICAgfSksXG4gICAgICAgIGNhdGNoRXJyb3IoKGUsIHNvdXJjZSQpID0+IHtcbiAgICAgICAgICB0aGlzLl9oYW5kbGVFcnJvcihlKTtcblxuICAgICAgICAgIHJldHVybiBzb3VyY2UkO1xuICAgICAgICB9KSxcbiAgICAgICAgdGFwKChzdWJtaXR0ZWRFdmVudDogU3VibWl0dGVkRXZlbnQpID0+IHtcbiAgICAgICAgICB0aGlzLl9jb21wbGV0ZVN1Ym1pdCh0cnVlLCBzdWJtaXR0ZWRFdmVudCk7XG4gICAgICAgIH0pLFxuICAgICAgICB0YWtlVW50aWwodGhpcy5fZGVzdHJveSQpXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHt9KTtcbiAgfVxuXG4gIHByaXZhdGUgX2xpc3RlbldpbmRvd0Nsb3NlKCk6IHZvaWQge1xuICAgIGZyb21FdmVudCh3aW5kb3csICdiZWZvcmV1bmxvYWQnKVxuICAgICAgLnBpcGUoXG4gICAgICAgIHRha2VVbnRpbCh0aGlzLl9kZXN0cm95JCksXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKChldmVudDogRXZlbnQpID0+IHtcbiAgICAgICAgaWYgKHRoaXMuY29uZmlybSAmJiB0aGlzLmNvbmZpcm1Ccm93c2VyICYmIHRoaXMubmdGb3JtLmRpcnR5KSB7XG4gICAgICAgICAgZXZlbnQucmV0dXJuVmFsdWUgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gIH1cblxuICBwcml2YXRlIF9saXN0ZW5Ib3RLZXlzKCk6IHZvaWQge1xuICAgIHRoaXMuX25nWm9uZS5ydW5PdXRzaWRlQW5ndWxhcigoKSA9PiB7XG4gICAgICBmcm9tRXZlbnQoZG9jdW1lbnQsICdrZXlkb3duJylcbiAgICAgICAgLnBpcGUoXG4gICAgICAgICAgdGFrZVVudGlsKHRoaXMuX2Rlc3Ryb3kkKSxcbiAgICAgICAgKVxuICAgICAgICAuc3Vic2NyaWJlKChldmVudDogS2V5Ym9hcmRFdmVudCkgPT4ge1xuICAgICAgICAgIGlmICh0aGlzLl9kaWFsb2dCYWNrZHJvcEVzY2FwZSAmJiBldmVudC5jb2RlID09PSAnRXNjYXBlJykge1xuICAgICAgICAgICAgY29uc3QgZGlhbG9nID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5fZGlhbG9nUmVmLmlkKTtcbiAgICAgICAgICAgIGNvbnN0IHBhdGhzID0gZXZlbnQuY29tcG9zZWRQYXRoKCk7XG5cbiAgICAgICAgICAgIGlmIChwYXRocykge1xuICAgICAgICAgICAgICBwYXRocy5mb3JFYWNoKGl0ZW0gPT4ge1xuICAgICAgICAgICAgICAgIGlmIChkaWFsb2cgPT09IGl0ZW0pIHtcbiAgICAgICAgICAgICAgICAgIHRoaXMuX25nWm9uZS5ydW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl9mb3JtQ2xvc2UoKTtcbiAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKChldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXkpICYmIGV2ZW50LmNvZGUgPT09ICdLZXlTJykge1xuICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICAgICAgaWYgKHRoaXMuc2hvcnRjdXRzKSB7XG4gICAgICAgICAgICAgIGlmICh0aGlzLl9lbGVtZW50SW5Gb3JtKGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5uZ0Zvcm0ubmdTdWJtaXQubmV4dCgpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgX2Zvcm1DbG9zZSgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5jb25maXJtICYmIHRoaXMuY29uZmlybURpYWxvZykge1xuICAgICAgdGhpcy50cmlnZ2VyQ29uZmlybSgpXG4gICAgICAgIC5waXBlKFxuICAgICAgICAgIGZpbHRlcigocmVzdWx0KSA9PiBjb25maXJtUmVzdWx0Q29udGludWUocmVzdWx0KSksXG4gICAgICAgICAgc3dpdGNoTWFwKChyZXN1bHQpID0+IHtcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQgPT09IENvbmZpcm1SZXN1bHQuUHJpc3RpbmUgfHwgcmVzdWx0ID09PSBDb25maXJtUmVzdWx0LkRpc2NhcmRcbiAgICAgICAgICAgICAgPyBvZihudWxsKVxuICAgICAgICAgICAgICA6IHRoaXMuc3VibWl0dGVkLmFzT2JzZXJ2YWJsZSgpO1xuICAgICAgICAgIH0pLFxuICAgICAgICAgIHRha2VVbnRpbCh0aGlzLl9kZXN0cm95JCksXG4gICAgICAgIClcbiAgICAgICAgLnN1YnNjcmliZSgocmVzdWx0OiBTdWJtaXR0ZWRFdmVudCkgPT4ge1xuICAgICAgICAgIHRoaXMuX2RpYWxvZ1JlZi5jbG9zZShyZXN1bHQ/LnJlc3BvbnNlKTtcbiAgICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuX2RpYWxvZ1JlZi5jbG9zZShudWxsKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIF9yZWdpc3RlckRpYWxvZ0Nsb3NlKGRpcmVjdGl2ZTogRnNGb3JtRGlhbG9nQ2xvc2VEaXJlY3RpdmUpOiB2b2lkIHtcbiAgICBpZiAoIWRpcmVjdGl2ZS5yZWdpc3RlcmVkKSB7XG4gICAgICBkaXJlY3RpdmUucmVnaXN0ZXJlZCA9IHRydWU7XG5cbiAgICAgIGRpcmVjdGl2ZS5jbGlja2VkJFxuICAgICAgICAucGlwZShcbiAgICAgICAgICB0YWtlVW50aWwodGhpcy5fZGVzdHJveSQpLFxuICAgICAgICApXG4gICAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgICAgIHRoaXMuX2Zvcm1DbG9zZSgpO1xuICAgICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIF9nZXRBY3RpdmVCdXR0b24oKTogRnNTdWJtaXRCdXR0b25EaXJlY3RpdmUge1xuICAgIGNvbnN0IGFjdGl2ZUJ1dHRvbiA9IHRoaXMuX3N1Ym1pdEJ1dHRvbnMuZmluZChidXR0b24gPT4ge1xuICAgICAgcmV0dXJuIGJ1dHRvbi5hY3RpdmU7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gYWN0aXZlQnV0dG9uID8gYWN0aXZlQnV0dG9uIDogdGhpcy5fc3VibWl0QnV0dG9ucy5maXJzdDtcbiAgfVxuXG4gIHByaXZhdGUgX2VsZW1lbnRJbkZvcm0oZWw6IEVsZW1lbnQpOiBib29sZWFuIHtcblxuICAgIGlmIChlbC5pc1NhbWVOb2RlKHRoaXMuX2VsZW1lbnQubmF0aXZlRWxlbWVudCkpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gZWxzZSBpZiAoZWwucGFyZW50RWxlbWVudCkge1xuICAgICAgcmV0dXJuIHRoaXMuX2VsZW1lbnRJbkZvcm0oZWwucGFyZW50RWxlbWVudCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgcHJpdmF0ZSBfY29tcGxldGVTdWJtaXQoc3VjY2Vzcywgc3VibWl0RXZlbnQ6IFN1Ym1pdHRlZEV2ZW50KTogdm9pZCB7XG4gICAgaWYgKHN1Y2Nlc3MpIHtcbiAgICAgIHRoaXMubmdGb3JtLmNvbnRyb2wubWFya0FzUHJpc3RpbmUoKTtcbiAgICAgIHRoaXMuY3JlYXRlU25hcHNob3QoKTsgIFxuICAgICAgdGhpcy5zdWJtaXR0ZWQuZW1pdChzdWJtaXRFdmVudCk7ICAgIFxuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLl9yZXNldEJ1dHRvbnMoKTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5fYWN0aXZlU3VibWl0QnV0dG9uKSB7XG4gICAgICBpZiAoc3VjY2Vzcykge1xuICAgICAgICB0aGlzLl9hY3RpdmVTdWJtaXRCdXR0b24uc3VjY2VzcygpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5fYWN0aXZlU3VibWl0QnV0dG9uLmVycm9yKCk7XG4gICAgICB9ICAgICAgXG4gICAgfVxuXG4gICAgdGhpcy5fc3RhdHVzJC5uZXh0KEZvcm1TdGF0dXMuU3VibWl0dGVkKTtcblxuICAgIGlmIChzdWNjZXNzKSB7XG4gICAgICB0aGlzLl9zdGF0dXMkLm5leHQoRm9ybVN0YXR1cy5TdWNjZXNzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5fc3RhdHVzJC5uZXh0KEZvcm1TdGF0dXMuRXJyb3IpO1xuICAgIH1cblxuICAgIHRoaXMuX3N0YXR1cyQubmV4dChGb3JtU3RhdHVzLkNvbXBsZXRpbmcpO1xuXG4gICAgY29uc3QgcmVzZXREZWxheSA9IHN1Y2Nlc3MgPyB0aGlzLnN1Y2Nlc3NEZWxheSA6IHRoaXMuZXJyb3JEZWxheTtcblxuICAgIG9mKHRydWUpXG4gICAgLnBpcGUoXG4gICAgICBkZWxheShyZXNldERlbGF5KSxcbiAgICAgIGZpcnN0KCksXG4gICAgICB0YWtlVW50aWwodGhpcy5fZGVzdHJveSQpLFxuICAgICkuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgIGlmICh0aGlzLm5nRm9ybS5mb3JtLnN0YXR1cyA9PT0gJ1ZBTElEJykge1xuICAgICAgICB0aGlzLl9zdGF0dXMkLm5leHQoRm9ybVN0YXR1cy5WYWxpZCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLl9zdGF0dXMkLm5leHQoRm9ybVN0YXR1cy5JbnZhbGlkKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5fcmVzZXRCdXR0b25zKCk7XG4gICAgICB0aGlzLl91cGRhdGVEaXJ0eVN1Ym1pdEJ1dHRvbnMoKTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgX3Jlc2V0QnV0dG9ucygpOiB2b2lkIHtcbiAgICB0aGlzLl9zdWJtaXRCdXR0b25zLmZvckVhY2goKGJ1dHRvbikgPT4ge1xuICAgICAgYnV0dG9uLnJlc2V0KCk7XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIF9yZWdpc3RlckNvbmZpcm0oKTogdm9pZCB7XG4gICAgdGhpcy5uZ0Zvcm0uZm9ybS52YWx1ZUNoYW5nZXNcbiAgICAgIC5waXBlKFxuICAgICAgICB0YWtlVW50aWwodGhpcy5fZGVzdHJveSQpXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKChjaGFuZ2VzKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLmNvbmZpcm0pIHtcbiAgICAgICAgICBjb25zdCBleGlzdGluZyA9IE9iamVjdC5rZXlzKHRoaXMuX3NuYXBzaG90KTtcblxuICAgICAgICAgIE9iamVjdC5rZXlzKGNoYW5nZXMpXG4gICAgICAgICAgICAuZm9yRWFjaCgobmFtZTogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgICAgIGlmIChleGlzdGluZy5pbmRleE9mKG5hbWUpID09PSAtMSkge1xuICAgICAgICAgICAgICAgIHRoaXMuX3NuYXBzaG90W25hbWVdID0gY2hhbmdlc1tuYW1lXTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBfcmVnaXN0ZXJEcmF3ZXJDbG9zZSgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5fZHJhd2VyUmVmKSB7XG4gICAgICB0aGlzLl9kcmF3ZXJSZWYuY2xvc2VTdGFydCRcbiAgICAgIC5waXBlKFxuICAgICAgICB0YWtlVW50aWwodGhpcy5fZGVzdHJveSQpLFxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZSgoc3Vic2NyaWJlcikgPT4ge1xuICAgICAgICBpZiAodGhpcy5zdWJtaXR0aW5nKSB7XG4gICAgICAgICAgdGhpcy5fc3RhdHVzJFxuICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgIGZpbHRlcigoc3RhdHVzKSA9PiBzdGF0dXMgPT09IEZvcm1TdGF0dXMuU3VjY2VzcyB8fCBzdGF0dXMgPT09IEZvcm1TdGF0dXMuRXJyb3IpLFxuICAgICAgICAgICAgICB0YWtlVW50aWwodGhpcy5fZGVzdHJveSQpLFxuICAgICAgICAgICAgKVxuICAgICAgICAgICAgLnN1YnNjcmliZSgoc3RhdHVzKSA9PiB7XG4gICAgICAgICAgICAgIGlmIChzdGF0dXMgPT09IEZvcm1TdGF0dXMuU3VjY2Vzcykge1xuICAgICAgICAgICAgICAgIHN1YnNjcmliZXIubmV4dCgpO1xuICAgICAgICAgICAgICAgIHN1YnNjcmliZXIuY29tcGxldGUoKTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzdWJzY3JpYmVyLmVycm9yKCk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHN1YnNjcmliZXIubmV4dCgpO1xuICAgICAgICAgIHN1YnNjcmliZXIuY29tcGxldGUoKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBfcmVnaXN0ZXJDb25maXJtRHJhd2VyQ2xvc2UoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuX2RyYXdlclJlZikge1xuICAgICAgdGhpcy5fZHJhd2VyUmVmLmNsb3NlU3RhcnQkXG4gICAgICAucGlwZShcbiAgICAgICAgc3dpdGNoTWFwKChzdWJzY3JpYmVyKSA9PiB7XG4gICAgICAgICAgcmV0dXJuIGlpZihcbiAgICAgICAgICAgICgpID0+IHRoaXMuY29uZmlybSAmJiB0aGlzLmNvbmZpcm1EcmF3ZXIsXG4gICAgICAgICAgICB0aGlzLnRyaWdnZXJDb25maXJtKClcbiAgICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgbWFwKChyZXN1bHQpID0+IGNvbmZpcm1SZXN1bHRDb250aW51ZShyZXN1bHQpKSxcbiAgICAgICAgICAgICAgICB0YXAoKHJlc3VsdCkgPT4ge1xuICAgICAgICAgICAgICAgICAgaWYgKHJlc3VsdCkge1xuICAgICAgICAgICAgICAgICAgICBzdWJzY3JpYmVyLm5leHQoKTtcbiAgICAgICAgICAgICAgICAgICAgc3Vic2NyaWJlci5jb21wbGV0ZSgpO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICksXG4gICAgICAgICAgICBkZWZlcigoKSA9PiB7XG4gICAgICAgICAgICAgIHN1YnNjcmliZXIubmV4dCgpO1xuICAgICAgICAgICAgICBzdWJzY3JpYmVyLmNvbXBsZXRlKCk7XG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICApXG4gICAgICAgIH0pLFxuICAgICAgICB0YWtlVW50aWwodGhpcy5fZGVzdHJveSQpLFxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZSgpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgX3JlZ2lzdGVyQ29uZmlybVRhYnMoKTogdm9pZCB7XG4gICAgaWYodGhpcy50YWJHcm91cCkge1xuICAgICAgdGhpcy5yZWdpc3RlckNvbmZpcm1UYWJHcm91cCh0aGlzLnRhYkdyb3VwKTtcbiAgICB9XG5cbiAgICB0aGlzLnJlZ2lzdGVyQ29uZmlybVRhYkdyb3Vwcyh0aGlzLl90YWJHcm91cHMudG9BcnJheSgpKTtcblxuICAgIHRoaXMuX3RhYkdyb3Vwcy5jaGFuZ2VzXG4gICAgLnBpcGUoXG4gICAgICB0YWtlVW50aWwodGhpcy5fZGVzdHJveSQpXG4gICAgKVxuICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgdGhpcy5yZWdpc3RlckNvbmZpcm1UYWJHcm91cHModGhpcy5fdGFiR3JvdXBzLnRvQXJyYXkoKSk7XG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgcmVnaXN0ZXJDb25maXJtVGFiR3JvdXBzKHRhYkdyb3VwczogTWF0VGFiR3JvdXBbXSk6IHZvaWQge1xuICAgIHRhYkdyb3Vwcy5mb3JFYWNoKCh0YWJHcm91cDogTWF0VGFiR3JvdXApID0+IHtcbiAgICAgIHRoaXMucmVnaXN0ZXJDb25maXJtVGFiR3JvdXAodGFiR3JvdXApO1xuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIHJlZ2lzdGVyQ29uZmlybVRhYkdyb3VwKHRhYkdyb3VwOiBNYXRUYWJHcm91cCk6IHZvaWQge1xuICAgIGNvbnN0IGNvbmZpcm1UYWJHcm91cCA9IHRhYkdyb3VwIGFzIENvbmZpcm1UYWJHcm91cDtcbiAgICBpZiAoIWNvbmZpcm1UYWJHcm91cC5fb3JpZ2luYWxIYW5kbGVDbGljaykge1xuICAgICAgY29uZmlybVRhYkdyb3VwLl9vcmlnaW5hbEhhbmRsZUNsaWNrID0gdGFiR3JvdXAuX2hhbmRsZUNsaWNrO1xuICAgICAgY29uZmlybVRhYkdyb3VwLl9oYW5kbENsaWNrJCA9IG5ldyBTdWJqZWN0PHsgdGFiOiBNYXRUYWI7IHRhYkhlYWRlcjogTWF0VGFiSGVhZGVyOyBpZHg6IG51bWJlciB9PigpO1xuICAgICAgY29uZmlybVRhYkdyb3VwLl9oYW5kbGVDbGljayA9ICh0YWI6IE1hdFRhYiwgdGFiSGVhZGVyOiBNYXRUYWJIZWFkZXIsIGlkeDogbnVtYmVyKSA9PiB7XG4gICAgICAgIGlmKGNvbmZpcm1UYWJHcm91cC5faGFuZGxDbGljayQub2JzZXJ2ZXJzLmxlbmd0aCkge1xuICAgICAgICAgIGNvbmZpcm1UYWJHcm91cC5faGFuZGxDbGljayQubmV4dCh7IHRhYiwgdGFiSGVhZGVyLCBpZHh9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25maXJtVGFiR3JvdXAuX29yaWdpbmFsSGFuZGxlQ2xpY2sodGFiLCB0YWJIZWFkZXIsIGlkeCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25maXJtVGFiR3JvdXAuX2hhbmRsQ2xpY2skXG4gICAgLnBpcGUoXG4gICAgICB0YWtlVW50aWwodGhpcy5fZGVzdHJveSQpLFxuICAgIClcbiAgICAuc3Vic2NyaWJlKChldmVudCkgPT4ge1xuICAgICAgaWYgKCF0aGlzLnN1Ym1pdHRpbmcpIHtcbiAgICAgICAgaWYgKHRoaXMuY29uZmlybSAmJiB0aGlzLmNvbmZpcm1UYWJzKSB7XG4gICAgICAgICAgdGhpcy50cmlnZ2VyQ29uZmlybSgpXG4gICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgdGFrZVVudGlsKHRoaXMuX2Rlc3Ryb3kkKSxcbiAgICAgICAgICAgIClcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKHJlc3VsdCkgPT4ge1xuICAgICAgICAgICAgICBpZiAoY29uZmlybVJlc3VsdENvbnRpbnVlKHJlc3VsdCkpIHtcbiAgICAgICAgICAgICAgICBjb25maXJtVGFiR3JvdXAuc2VsZWN0ZWRJbmRleCA9IGV2ZW50LmlkeDtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uZmlybVRhYkdyb3VwLl9vcmlnaW5hbEhhbmRsZUNsaWNrKGV2ZW50LnRhYiwgZXZlbnQudGFiSGVhZGVyLCBldmVudC5pZHgpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIF9yZWdpc3RlckNvbmZpcm1EaWFsb2dDbG9zZSgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5fZGlhbG9nUmVmKSB7XG4gICAgICB0aGlzLmZvcm1EaWFsb2dDbG9zZS5mb3JFYWNoKGl0ZW0gPT4ge1xuICAgICAgICB0aGlzLl9yZWdpc3RlckRpYWxvZ0Nsb3NlKGl0ZW0pO1xuICAgICAgfSk7XG5cbiAgICAgIHRoaXMuZm9ybURpYWxvZ0Nsb3NlLmNoYW5nZXNcbiAgICAgIC5waXBlKFxuICAgICAgICB0YWtlVW50aWwodGhpcy5fZGVzdHJveSQpLFxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZSgoZSkgPT4ge1xuICAgICAgICBlLmZvckVhY2goaXRlbSA9PiB7XG4gICAgICAgICAgdGhpcy5fcmVnaXN0ZXJEaWFsb2dDbG9zZShpdGVtKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIF9yZWdpc3RlckNvbmZpcm1EaWFsb2dCYWNrZHJvcEVzY2FwZSgpOiB2b2lkIHtcbiAgICB0aGlzLl9kaWFsb2dCYWNrZHJvcEVzY2FwZSA9IHRoaXMuX2RpYWxvZ1JlZiAmJiB0aGlzLl9kaWFsb2dSZWYuZGlzYWJsZUNsb3NlICE9PSB0cnVlO1xuXG4gICAgaWYgKHRoaXMuX2RpYWxvZ1JlZiAmJiAhdGhpcy5fZGlhbG9nUmVmLmRpc2FibGVDbG9zZSkge1xuICAgICAgdGhpcy5fZGlhbG9nUmVmLmRpc2FibGVDbG9zZSA9IHRydWU7XG4gICAgICB0aGlzLl9kaWFsb2dSZWYuYmFja2Ryb3BDbGljaygpXG4gICAgICAucGlwZShcbiAgICAgICAgdGFrZVVudGlsKHRoaXMuX2Rlc3Ryb3kkKVxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgIHRoaXMuX2Zvcm1DbG9zZSgpO1xuICAgICAgfSk7XG5cbiAgICAgIHRoaXMuX2Rlc3Ryb3kkXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgICAgdGhpcy5fZGlhbG9nUmVmLmRpc2FibGVDbG9zZSA9IGZhbHNlO1xuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBfcmVnaXN0ZXJBdXRvY29tcGxldGUoKTogdm9pZCB7XG4gICAgdGhpcy5fcmVnaXN0ZXJDb250cm9sID0gdGhpcy5uZ0Zvcm0uZm9ybS5yZWdpc3RlckNvbnRyb2wuYmluZCh0aGlzLm5nRm9ybS5mb3JtKTtcblxuICAgIHRoaXMubmdGb3JtLmZvcm0ucmVnaXN0ZXJDb250cm9sID0gKG5hbWU6IHN0cmluZywgY29udHJvbDogQWJzdHJhY3RDb250cm9sKSA9PiB7XG5cbiAgICAgIGNvbnN0IGVsOiBFbGVtZW50ID0gdGhpcy5fZWxlbWVudC5uYXRpdmVFbGVtZW50LnF1ZXJ5U2VsZWN0b3IoYGlucHV0W25hbWU9JyR7bmFtZX0nXWApO1xuXG4gICAgICBpZiAoZWwpIHtcbiAgICAgICAgZWwuc2V0QXR0cmlidXRlKCduYW1lJywgbmFtZSArICdfJyArIGd1aWQoKSk7XG5cbiAgICAgICAgaWYgKCFlbC5nZXRBdHRyaWJ1dGUoJ2F1dG9jb21wbGV0ZScpKSB7XG4gICAgICAgICAgZWwuc2V0QXR0cmlidXRlKCdhdXRvY29tcGxldGUnLCAnbm9uZScpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzLl9yZWdpc3RlckNvbnRyb2wobmFtZSwgY29udHJvbCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBfcmVnaXN0ZXJEaXJ0eVN1Ym1pdEJ1dHRvbigpOiB2b2lkIHtcblxuICAgIGlmICghdGhpcy5uZ0Zvcm0pIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLm5nRm9ybS5mb3JtLnZhbHVlQ2hhbmdlc1xuICAgIC5waXBlKFxuICAgICAgdGFrZVVudGlsKHRoaXMuX2Rlc3Ryb3kkKSxcbiAgICApXG4gICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICB0aGlzLl91cGRhdGVEaXJ0eVN1Ym1pdEJ1dHRvbnMoKTtcbiAgICB9KTtcblxuICAgIHRoaXMuX3N1Ym1pdEJ1dHRvbnMuY2hhbmdlc1xuICAgIC5waXBlKFxuICAgICAgdGFrZVVudGlsKHRoaXMuX2Rlc3Ryb3kkKSxcbiAgICApXG4gICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICB0aGlzLl91cGRhdGVEaXJ0eVN1Ym1pdEJ1dHRvbnMoKTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgX3VwZGF0ZURpcnR5U3VibWl0QnV0dG9ucygpOiB2b2lkIHtcbiAgICB0aGlzLl9zdWJtaXRCdXR0b25zXG4gICAgLmZvckVhY2goKHN1Ym1pdEJ1dHRvbjogRnNTdWJtaXRCdXR0b25EaXJlY3RpdmUpID0+IHtcbiAgICAgIGlmICghdGhpcy5jb25maXJtIHx8ICF0aGlzLmRpcnR5U3VibWl0QnV0dG9uIHx8IHRoaXMubmdGb3JtLmRpcnR5IHx8ICFzdWJtaXRCdXR0b24uZGlydHlTdWJtaXQpIHtcbiAgICAgICAgICBzdWJtaXRCdXR0b24uZW5hYmxlKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgc3VibWl0QnV0dG9uLmRpc2FibGUoKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gIH1cblxuICBwcml2YXRlIF9icm9hZGNhc3RTdWJtaXR0aW5nRXZlbnRzKCk6IHZvaWQge1xuICAgIHRoaXMuX3N0YXR1cyQubmV4dChGb3JtU3RhdHVzLlN1Ym1pdHRpbmcpO1xuICAgIHRoaXMuX2Zvcm0uYnJvYWRjYXN0KCdzdWJtaXQnLCB0aGlzLm5nRm9ybSk7XG4gIH1cblxuICBwcml2YXRlIF9tYXJrQ29udHJvbHNBc1RvdWNoZWRBbmRVcGRhdGVWYWxpZGl0eSgpOiB2b2lkIHtcbiAgICBPYmplY3QudmFsdWVzKHRoaXMubmdGb3JtLmNvbnRyb2xzKVxuICAgIC5mb3JFYWNoKGNvbnRyb2wgPT4ge1xuICAgICAgY29udHJvbC5tYXJrQXNEaXJ0eSgpO1xuICAgICAgY29udHJvbC5tYXJrQXNUb3VjaGVkKCk7XG4gICAgICBjb250cm9sLnVwZGF0ZVZhbHVlQW5kVmFsaWRpdHkoKTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgX3NldHVwQWN0aXZlU3VibWl0QnV0dG9uKCk6IHZvaWQge1xuICAgIHRoaXMuX2FjdGl2ZVN1Ym1pdEJ1dHRvbiA9IHRoaXMuX2dldEFjdGl2ZUJ1dHRvbigpO1xuICAgIHRoaXMuX3Jlc2V0QnV0dG9ucygpO1xuXG4gICAgaWYgKHRoaXMuX2FjdGl2ZVN1Ym1pdEJ1dHRvbikge1xuICAgICAgdGhpcy5fYWN0aXZlU3VibWl0QnV0dG9uLnByb2Nlc3MoKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIF93YWl0VW50aWxTdGF0dXNQZW5kaW5nKCk6IE9ic2VydmFibGU8c3RyaW5nPiB7XG4gICAgcmV0dXJuIHRoaXMubmdGb3JtLnN0YXR1c0NoYW5nZXNcbiAgICAgIC5waXBlKFxuICAgICAgICBzdGFydFdpdGgodGhpcy5uZ0Zvcm0uc3RhdHVzKSxcbiAgICAgICAgZmlyc3QoKHN0YXRlKSA9PiBzdGF0ZSAhPT0gJ1BFTkRJTkcnKSxcbiAgICAgICk7XG4gIH1cblxuICBwcml2YXRlIF9oYW5kbGVFcnJvcihlOiBTdWJtaXR0ZWRFdmVudCkge1xuICAgIGNvbnNvbGUubG9nKCclYyBGb3JtIFN1Ym1pdCAnLCAgJ2NvbG9yOiB3aGl0ZTsgYmFja2dyb3VuZC1jb2xvcjogI0QzM0Y0OScsICAnRXJyb3Igb2NjdXJlZCcpO1xuXG4gICAgY29uc29sZS5ncm91cCgnRXJyb3IgRGV0YWlsczonKTtcbiAgICBjb25zb2xlLmxvZygnTWVzc2FnZTogJywgZSk7XG4gICAgY29uc29sZS5sb2coJ0Zvcm1SZWY6ICcsIHRoaXMpO1xuXG4gICAgaWYgKHRoaXMubmdGb3JtLmludmFsaWQpIHtcbiAgICAgIGNvbnN0IGVycm9ycyA9IGdldEZvcm1FcnJvcnModGhpcy5uZ0Zvcm0uY29udHJvbCwgbnVsbCk7XG4gICAgICBjb25zb2xlLmxvZygnVmFsaWRhdGlvbiBFcnJvcnM6ICcsIGVycm9ycyk7XG4gICAgfVxuXG4gICAgY29uc29sZS5ncm91cEVuZCgpO1xuXG4gICAgdGhpcy5fY29tcGxldGVTdWJtaXQoZmFsc2UsIG51bGwpO1xuICB9XG5cbn1cbiJdfQ==