ng-configcat-publicapi-ui 3.0.8 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/esm2022/lib/_directives/input-display-normalizer.directive.mjs +38 -0
  2. package/esm2022/lib/_services/form-helper.mjs +104 -0
  3. package/{esm2020 → esm2022}/lib/_services/public-api.service.mjs +6 -6
  4. package/esm2022/lib/_services/setting-list-form-helper.mjs +171 -0
  5. package/esm2022/lib/authorization/authorization.component.mjs +62 -0
  6. package/{esm2020 → esm2022}/lib/base/base-select.component.mjs +4 -4
  7. package/{esm2020 → esm2022}/lib/base/base.component.mjs +5 -5
  8. package/{esm2020 → esm2022}/lib/configuration.mjs +4 -4
  9. package/{esm2020 → esm2022}/lib/dialogs/delete-setting-dialog/delete-setting-dialog.component.mjs +6 -6
  10. package/esm2022/lib/dialogs/expand-dialog/expand-dialog.component.mjs +80 -0
  11. package/esm2022/lib/dialogs/reason-dialog/reason-dialog.component.mjs +36 -0
  12. package/{esm2020 → esm2022}/lib/dialogs/save-snackbar/save-snackbar.component.mjs +5 -5
  13. package/esm2022/lib/ng-configcat-publicapi-ui.module.mjs +179 -0
  14. package/esm2022/lib/selects/config-select/config-select.component.mjs +60 -0
  15. package/esm2022/lib/selects/environment-select/environment-select.component.mjs +47 -0
  16. package/esm2022/lib/selects/product-select/product-select.component.mjs +40 -0
  17. package/esm2022/lib/selects/setting-select/setting-select.component.mjs +47 -0
  18. package/esm2022/lib/setting-item/setting-item.component.mjs +116 -0
  19. package/esm2022/lib/setting-list/setting/rollout-percentage-items/rollout-percentage-items.component.mjs +81 -0
  20. package/esm2022/lib/setting-list/setting/rollout-rules/rollout-rules.component.mjs +293 -0
  21. package/{esm2020 → esm2022}/lib/setting-list/setting/setting.component.mjs +5 -5
  22. package/esm2022/lib/setting-list/setting/value/value.component.mjs +37 -0
  23. package/esm2022/lib/setting-list/setting-list.component.mjs +194 -0
  24. package/{fesm2020 → fesm2022}/ng-configcat-publicapi-ui.mjs +163 -163
  25. package/{fesm2020 → fesm2022}/ng-configcat-publicapi-ui.mjs.map +1 -1
  26. package/lib/_services/setting-list-form-helper.d.ts +1 -1
  27. package/lib/authorization/authorization.component.d.ts +1 -1
  28. package/lib/base/base-select.component.d.ts +1 -1
  29. package/lib/base/base.component.d.ts +1 -1
  30. package/lib/selects/config-select/config-select.component.d.ts +1 -1
  31. package/lib/selects/environment-select/environment-select.component.d.ts +1 -1
  32. package/lib/selects/product-select/product-select.component.d.ts +1 -1
  33. package/lib/selects/setting-select/setting-select.component.d.ts +1 -1
  34. package/lib/setting-item/setting-item.component.d.ts +1 -1
  35. package/lib/setting-list/setting/rollout-percentage-items/rollout-percentage-items.component.d.ts +1 -1
  36. package/lib/setting-list/setting/rollout-rules/rollout-rules.component.d.ts +2 -2
  37. package/lib/setting-list/setting/setting.component.d.ts +1 -1
  38. package/lib/setting-list/setting/value/value.component.d.ts +1 -1
  39. package/lib/setting-list/setting-list.component.d.ts +1 -1
  40. package/package.json +9 -15
  41. package/public-api.scss +0 -1
  42. package/esm2020/lib/_directives/input-display-normalizer.directive.mjs +0 -38
  43. package/esm2020/lib/_services/form-helper.mjs +0 -104
  44. package/esm2020/lib/_services/setting-list-form-helper.mjs +0 -171
  45. package/esm2020/lib/authorization/authorization.component.mjs +0 -62
  46. package/esm2020/lib/dialogs/expand-dialog/expand-dialog.component.mjs +0 -80
  47. package/esm2020/lib/dialogs/reason-dialog/reason-dialog.component.mjs +0 -36
  48. package/esm2020/lib/ng-configcat-publicapi-ui.module.mjs +0 -179
  49. package/esm2020/lib/selects/config-select/config-select.component.mjs +0 -60
  50. package/esm2020/lib/selects/environment-select/environment-select.component.mjs +0 -47
  51. package/esm2020/lib/selects/product-select/product-select.component.mjs +0 -40
  52. package/esm2020/lib/selects/setting-select/setting-select.component.mjs +0 -47
  53. package/esm2020/lib/setting-item/setting-item.component.mjs +0 -116
  54. package/esm2020/lib/setting-list/setting/rollout-percentage-items/rollout-percentage-items.component.mjs +0 -81
  55. package/esm2020/lib/setting-list/setting/rollout-rules/rollout-rules.component.mjs +0 -293
  56. package/esm2020/lib/setting-list/setting/value/value.component.mjs +0 -37
  57. package/esm2020/lib/setting-list/setting-list.component.mjs +0 -194
  58. package/fesm2015/ng-configcat-publicapi-ui.mjs +0 -1786
  59. package/fesm2015/ng-configcat-publicapi-ui.mjs.map +0 -1
  60. /package/{esm2020 → esm2022}/lib/_directives/index.mjs +0 -0
  61. /package/{esm2020 → esm2022}/lib/_models/deleteSettingModel.mjs +0 -0
  62. /package/{esm2020 → esm2022}/lib/_models/index.mjs +0 -0
  63. /package/{esm2020 → esm2022}/lib/_models/settingValuesModel.mjs +0 -0
  64. /package/{esm2020 → esm2022}/lib/_models/updateSettingValuesModel.mjs +0 -0
  65. /package/{esm2020 → esm2022}/lib/_services/index.mjs +0 -0
  66. /package/{esm2020 → esm2022}/lib/_services/platform-helper.mjs +0 -0
  67. /package/{esm2020 → esm2022}/ng-configcat-publicapi-ui.mjs +0 -0
  68. /package/{esm2020 → esm2022}/public-api.mjs +0 -0
@@ -1,194 +0,0 @@
1
- import { Component, Input, Output, EventEmitter } from '@angular/core';
2
- import { forkJoin } from 'rxjs';
3
- import { ReasonDialogComponent } from '../dialogs/reason-dialog/reason-dialog.component';
4
- import { SaveSnackbarComponent } from '../dialogs/save-snackbar/save-snackbar.component';
5
- import * as i0 from "@angular/core";
6
- import * as i1 from "../_services/setting-list-form-helper";
7
- import * as i2 from "@angular/material/snack-bar";
8
- import * as i3 from "@angular/material/dialog";
9
- import * as i4 from "@angular/common";
10
- import * as i5 from "@angular/forms";
11
- import * as i6 from "@angular/material/button";
12
- import * as i7 from "@angular/material/icon";
13
- import * as i8 from "./setting/setting.component";
14
- export class SettingListComponent {
15
- constructor(formHelper, snackBar, dialog) {
16
- this.formHelper = formHelper;
17
- this.snackBar = snackBar;
18
- this.dialog = dialog;
19
- this.dashboardBasePath = 'https://app.configcat.com';
20
- this.canDeleteSetting = false;
21
- this.deleteSettingText = 'Delete setting';
22
- this.showEnvironmentName = false;
23
- this.loadSucceeded = new EventEmitter();
24
- this.deleteSettingRequested = new EventEmitter();
25
- this.formValuesChanged = new EventEmitter();
26
- this.loading = true;
27
- this.submitting = false;
28
- this.showRevertQuestion = false;
29
- this.showFeedBackMessage = false;
30
- this.readOnly = false;
31
- }
32
- ngOnChanges() {
33
- this.reloadSettingValues();
34
- }
35
- ngOnDestroy() {
36
- if (this.formValuesChangedSubscription) {
37
- this.formValuesChangedSubscription.unsubscribe();
38
- this.formValuesChangedSubscription = null;
39
- }
40
- }
41
- reloadSettingValues() {
42
- this.showFeedBackMessage = false;
43
- this.loading = true;
44
- forkJoin({
45
- segments: this.loadSegments(),
46
- settingValues: this.loadSettingValues()
47
- }).subscribe(result => {
48
- this.readOnly = result.settingValues.readOnly;
49
- this.settingValues = result.settingValues;
50
- this.segments = result.segments;
51
- this.createFormGroup();
52
- this.loading = false;
53
- this.loadSucceeded.emit(true);
54
- }, () => {
55
- this.snackBar.open('Ooops. We could not load your Feature Flags and Settings. Please try again or contact us.', 'Dismiss', { duration: 60000, panelClass: 'red-snackbar' });
56
- });
57
- }
58
- createFormGroup() {
59
- this.formGroup = this.formHelper.createSettingValuesFormGroup(this.settingValues);
60
- this.formValuesChangedSubscription = this.formGroup.valueChanges.subscribe(() => {
61
- this.formValuesChanged.emit();
62
- });
63
- }
64
- settingValuesFormArray() {
65
- return this.formGroup.get('settingValues');
66
- }
67
- getSettingValueFormGroups() {
68
- return this.settingValuesFormArray().controls.map(c => c);
69
- }
70
- buildUpdateSettingValuesModel(settingValuesVM) {
71
- return settingValuesVM.map(settingValueVM => {
72
- return {
73
- rolloutRules: settingValueVM.rolloutRules?.map(rolloutRuleVM => ({
74
- comparisonAttribute: rolloutRuleVM.comparisonAttribute,
75
- comparator: rolloutRuleVM.comparator,
76
- comparisonValue: this.formHelper.normalizeComparisonValue(rolloutRuleVM.comparator, rolloutRuleVM.comparisonValue),
77
- segmentComparator: rolloutRuleVM.segmentComparator,
78
- segmentId: rolloutRuleVM.segmentId,
79
- value: rolloutRuleVM.value
80
- })),
81
- rolloutPercentageItems: settingValueVM.rolloutPercentageItems?.map(rolloutPercentageItemVM => ({
82
- percentage: rolloutPercentageItemVM.percentage,
83
- value: rolloutPercentageItemVM.value
84
- })),
85
- value: settingValueVM.value
86
- };
87
- });
88
- }
89
- submit() {
90
- if (!this.formGroup || !this.formGroup.valid) {
91
- this.showFeedBackMessage = true;
92
- this.formGroup.markAsTouched();
93
- return;
94
- }
95
- this.showFeedBackMessage = false;
96
- this.submitting = true;
97
- const updateSettingValuesModel = {
98
- settingValues: this.buildUpdateSettingValuesModel(this.formGroup.controls.settingValues.value),
99
- knownLastUpdatedAt: this.settingValues.lastUpdatedAt,
100
- forced: false
101
- };
102
- if (this.settingValues.reasonRequired) {
103
- const dialogRef = this.dialog.open(ReasonDialogComponent, {
104
- width: '450px'
105
- });
106
- dialogRef.afterClosed()
107
- .subscribe(result => {
108
- if (result && result.button === 'save' && result.reason) {
109
- updateSettingValuesModel.reason = result.reason;
110
- this.updateSettingValues(updateSettingValuesModel);
111
- }
112
- else {
113
- this.submitting = false;
114
- }
115
- });
116
- return;
117
- }
118
- this.updateSettingValues(updateSettingValuesModel);
119
- }
120
- updateSettingValues(updateSettingValuesModel) {
121
- this.onSave(updateSettingValuesModel).subscribe(settingValues => {
122
- this.settingValues = settingValues;
123
- this.createFormGroup();
124
- this.submitting = false;
125
- this.snackBar.openFromComponent(SaveSnackbarComponent, { duration: 5000, panelClass: 'green-snackbar' });
126
- }, (error) => {
127
- if (error.status === 400 && error.error && error.error.Reason && error.error.Reason[0] === 'Reason required') {
128
- const dialogRef = this.dialog.open(ReasonDialogComponent, {
129
- width: '450px'
130
- });
131
- dialogRef.afterClosed()
132
- .subscribe(result => {
133
- if (result && result.button === 'save' && result.reason) {
134
- updateSettingValuesModel.reason = result.reason;
135
- this.updateSettingValues(updateSettingValuesModel);
136
- }
137
- else {
138
- this.submitting = false;
139
- }
140
- });
141
- return;
142
- }
143
- this.formGroup.setErrors({ internalServerError: 'Internal server error' });
144
- this.showFeedBackMessage = true;
145
- });
146
- }
147
- handleRevertYes() {
148
- this.showRevertQuestion = false;
149
- this.reloadSettingValues();
150
- }
151
- handleRevertCancel() {
152
- this.showRevertQuestion = false;
153
- }
154
- onDeleteSettingRequested(setting) {
155
- this.deleteSettingRequested.emit({
156
- setting: setting.setting,
157
- environment: this.settingValues.environment,
158
- config: this.settingValues.config
159
- });
160
- }
161
- }
162
- SettingListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SettingListComponent, deps: [{ token: i1.SettingListFormHelper }, { token: i2.MatSnackBar }, { token: i3.MatDialog }], target: i0.ɵɵFactoryTarget.Component });
163
- SettingListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: SettingListComponent, selector: "configcat-setting-list", inputs: { productId: "productId", environmentId: "environmentId", configId: "configId", dashboardBasePath: "dashboardBasePath", canDeleteSetting: "canDeleteSetting", onSave: "onSave", loadSettingValues: "loadSettingValues", loadSegments: "loadSegments", deleteSettingText: "deleteSettingText", showEnvironmentName: "showEnvironmentName" }, outputs: { loadSucceeded: "loadSucceeded", deleteSettingRequested: "deleteSettingRequested", formValuesChanged: "formValuesChanged" }, usesOnChanges: true, ngImport: i0, template: "<form [formGroup]=\"formGroup\" (ngSubmit)=\"submit()\" *ngIf=\"!loading\">\n <div class=\"wrapper\" *ngFor=\"let settingValueFromGroup of getSettingValueFormGroups(); let i = index\">\n <setting [formGroup]=\"settingValueFromGroup\" [readOnly]=\"readOnly\" [canDeleteSetting]=\"canDeleteSetting\"\n (deleteSettingRequested)=\"onDeleteSettingRequested($event)\" [deleteSettingText]=\"deleteSettingText\"\n [showEnvironmentName]=\"showEnvironmentName\" [segments]=\"segments\" [productId]=\"productId\" [configId]=\"configId\"\n [environmentId]=\"environmentId\" [dashboardBasePath]=\"dashboardBasePath\">\n </setting>\n </div>\n\n <div class=\"save\" *ngIf=\"!readOnly && !submitting && formGroup.dirty\">\n <div class=\"feedback\" *ngIf=\"formGroup.touched && formGroup.invalid && showFeedBackMessage\">\n <div class=\"error\" *ngIf=\"formGroup.errors && formGroup.errors.internalServerError\">\n <span>Something went wrong and we could not save your settings. You can try again or <a\n href=\"https://configcat.com/support\" target=\"_blank\" rel=\"noopener noreferrer\">contact us.</a></span>\n </div>\n <div class=\"error\" *ngIf=\"!formGroup.errors || !formGroup.errors.internalServerError\">\n <span>Oh no! A feature flag has invalid or missing data.</span>\n </div>\n </div>\n <button type=\"button\" mat-stroked-button *ngIf=\"!showRevertQuestion\" (click)=\"showRevertQuestion = true\">\n <mat-icon>history</mat-icon><span>Revert changes</span>\n </button>\n <div *ngIf=\"showRevertQuestion\">\n <span class=\"revert\">Revert to last saved state?</span>\n <button type=\"button\" class=\"yes\" mat-stroked-button (click)=\"handleRevertYes()\">Yes</button>\n <button type=\"button\" mat-stroked-button (click)=\"handleRevertCancel()\">No</button>\n </div>\n <button class=\"save-button\" mat-flat-button color=\"warn\" type=\"submit\" [disabled]=\"submitting\">\n <mat-icon>backup</mat-icon> <span> Save & publish changes</span>\n </button>\n </div>\n</form>", styles: [".wrapper{background-color:#f3f3f3;border:1px solid rgba(0,0,0,.12);margin:1em 0}.show-hide a{cursor:pointer;font-size:.8rem}.save{position:sticky;bottom:0;min-height:38px;padding:.5rem .5rem .5rem 0;background-color:#fff;display:flex;flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:flex-end;z-index:1000}.save .save-button{animation:shadow-pulse 1s 3;margin-left:1rem}.save>*{margin:.3em}.save .revert{margin:0 16px;font-size:14px}.save .yes{margin:0 5px}.error{background-color:#a32b2d;color:#fff;padding:5px;font-size:.9em}.error a{color:#fff;text-decoration:underline}@media (max-width: 700px){.save{padding:.5rem 0}}\n"], dependencies: [{ kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i5.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i5.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i6.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i8.SettingComponent, selector: "setting", inputs: ["dashboardBasePath", "productId", "environmentId", "configId", "formGroup", "readOnly", "canDeleteSetting", "deleteSettingText", "showEnvironmentName", "segments"], outputs: ["deleteSettingRequested"] }] });
164
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SettingListComponent, decorators: [{
165
- type: Component,
166
- args: [{ selector: 'configcat-setting-list', template: "<form [formGroup]=\"formGroup\" (ngSubmit)=\"submit()\" *ngIf=\"!loading\">\n <div class=\"wrapper\" *ngFor=\"let settingValueFromGroup of getSettingValueFormGroups(); let i = index\">\n <setting [formGroup]=\"settingValueFromGroup\" [readOnly]=\"readOnly\" [canDeleteSetting]=\"canDeleteSetting\"\n (deleteSettingRequested)=\"onDeleteSettingRequested($event)\" [deleteSettingText]=\"deleteSettingText\"\n [showEnvironmentName]=\"showEnvironmentName\" [segments]=\"segments\" [productId]=\"productId\" [configId]=\"configId\"\n [environmentId]=\"environmentId\" [dashboardBasePath]=\"dashboardBasePath\">\n </setting>\n </div>\n\n <div class=\"save\" *ngIf=\"!readOnly && !submitting && formGroup.dirty\">\n <div class=\"feedback\" *ngIf=\"formGroup.touched && formGroup.invalid && showFeedBackMessage\">\n <div class=\"error\" *ngIf=\"formGroup.errors && formGroup.errors.internalServerError\">\n <span>Something went wrong and we could not save your settings. You can try again or <a\n href=\"https://configcat.com/support\" target=\"_blank\" rel=\"noopener noreferrer\">contact us.</a></span>\n </div>\n <div class=\"error\" *ngIf=\"!formGroup.errors || !formGroup.errors.internalServerError\">\n <span>Oh no! A feature flag has invalid or missing data.</span>\n </div>\n </div>\n <button type=\"button\" mat-stroked-button *ngIf=\"!showRevertQuestion\" (click)=\"showRevertQuestion = true\">\n <mat-icon>history</mat-icon><span>Revert changes</span>\n </button>\n <div *ngIf=\"showRevertQuestion\">\n <span class=\"revert\">Revert to last saved state?</span>\n <button type=\"button\" class=\"yes\" mat-stroked-button (click)=\"handleRevertYes()\">Yes</button>\n <button type=\"button\" mat-stroked-button (click)=\"handleRevertCancel()\">No</button>\n </div>\n <button class=\"save-button\" mat-flat-button color=\"warn\" type=\"submit\" [disabled]=\"submitting\">\n <mat-icon>backup</mat-icon> <span> Save & publish changes</span>\n </button>\n </div>\n</form>", styles: [".wrapper{background-color:#f3f3f3;border:1px solid rgba(0,0,0,.12);margin:1em 0}.show-hide a{cursor:pointer;font-size:.8rem}.save{position:sticky;bottom:0;min-height:38px;padding:.5rem .5rem .5rem 0;background-color:#fff;display:flex;flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:flex-end;z-index:1000}.save .save-button{animation:shadow-pulse 1s 3;margin-left:1rem}.save>*{margin:.3em}.save .revert{margin:0 16px;font-size:14px}.save .yes{margin:0 5px}.error{background-color:#a32b2d;color:#fff;padding:5px;font-size:.9em}.error a{color:#fff;text-decoration:underline}@media (max-width: 700px){.save{padding:.5rem 0}}\n"] }]
167
- }], ctorParameters: function () { return [{ type: i1.SettingListFormHelper }, { type: i2.MatSnackBar }, { type: i3.MatDialog }]; }, propDecorators: { productId: [{
168
- type: Input
169
- }], environmentId: [{
170
- type: Input
171
- }], configId: [{
172
- type: Input
173
- }], dashboardBasePath: [{
174
- type: Input
175
- }], canDeleteSetting: [{
176
- type: Input
177
- }], onSave: [{
178
- type: Input
179
- }], loadSettingValues: [{
180
- type: Input
181
- }], loadSegments: [{
182
- type: Input
183
- }], deleteSettingText: [{
184
- type: Input
185
- }], showEnvironmentName: [{
186
- type: Input
187
- }], loadSucceeded: [{
188
- type: Output
189
- }], deleteSettingRequested: [{
190
- type: Output
191
- }], formValuesChanged: [{
192
- type: Output
193
- }] } });
194
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2V0dGluZy1saXN0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25nLWNvbmZpZ2NhdC1wdWJsaWNhcGktdWkvc3JjL2xpYi9zZXR0aW5nLWxpc3Qvc2V0dGluZy1saXN0LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25nLWNvbmZpZ2NhdC1wdWJsaWNhcGktdWkvc3JjL2xpYi9zZXR0aW5nLWxpc3Qvc2V0dGluZy1saXN0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQXdCLE1BQU0sZUFBZSxDQUFDO0FBRzdGLE9BQU8sRUFBRSxRQUFRLEVBQTRCLE1BQU0sTUFBTSxDQUFDO0FBRzFELE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLGtEQUFrRCxDQUFDO0FBQ3pGLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLGtEQUFrRCxDQUFDOzs7Ozs7Ozs7O0FBU3pGLE1BQU0sT0FBTyxvQkFBb0I7SUFnQy9CLFlBQW9CLFVBQWlDLEVBQzNDLFFBQXFCLEVBQ3JCLE1BQWlCO1FBRlAsZUFBVSxHQUFWLFVBQVUsQ0FBdUI7UUFDM0MsYUFBUSxHQUFSLFFBQVEsQ0FBYTtRQUNyQixXQUFNLEdBQU4sTUFBTSxDQUFXO1FBN0JsQixzQkFBaUIsR0FBRywyQkFBMkIsQ0FBQztRQUVoRCxxQkFBZ0IsR0FBRyxLQUFLLENBQUM7UUFLekIsc0JBQWlCLEdBQUcsZ0JBQWdCLENBQUM7UUFDckMsd0JBQW1CLEdBQUcsS0FBSyxDQUFDO1FBRTNCLGtCQUFhLEdBQUcsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUNuQywyQkFBc0IsR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBQzVDLHNCQUFpQixHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7UUFJakQsWUFBTyxHQUFH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QUF3Qjs4SkFNekIsU0FBUztzQkFBakIsS0FBSztnQkFDRyxhQUFhO3NCQUFyQixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csaUJBQWlCO3NCQUF6QixLQUFLO2dCQUVHLGdCQUFnQjtzQkFBeEIsS0FBSztnQkFFRyxNQUFNO3NCQUFkLEtBQUs7Z0JBQ0csaUJBQWlCO3NCQUF6QixLQUFLO2dCQUNHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBQ0csaUJBQWlCO3NCQUF6QixLQUFLO2dCQUNHLG1CQUFtQjtzQkFBM0IsS0FBSztnQkFFSSxhQUFhO3NCQUF0QixNQUFNO2dCQUNHLHNCQUFzQjtzQkFBL0IsTUFBTTtnQkFDRyxpQkFBaUI7c0JBQTFCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIElucHV0LCBPdXRwdXQsIEV2ZW50RW1pdHRlciwgT25EZXN0cm95LCBPbkNoYW5nZXMgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFNldHRpbmdWYWx1ZXNNb2RlbCwgVXBkYXRlU2V0dGluZ1ZhbHVlc01vZGVsIH0gZnJvbSAnLi4vX21vZGVscyc7XG5pbXBvcnQgeyBVbnR5cGVkRm9ybUFycmF5LCBVbnR5cGVkRm9ybUdyb3VwIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgZm9ya0pvaW4sIE9ic2VydmFibGUsIFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgTWF0U25hY2tCYXIgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9zbmFjay1iYXInO1xuaW1wb3J0IHsgTWF0RGlhbG9nIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZGlhbG9nJztcbmltcG9ydCB7IFJlYXNvbkRpYWxvZ0NvbXBvbmVudCB9IGZyb20gJy4uL2RpYWxvZ3MvcmVhc29uLWRpYWxvZy9yZWFzb24tZGlhbG9nLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBTYXZlU25hY2tiYXJDb21wb25lbnQgfSBmcm9tICcuLi9kaWFsb2dzL3NhdmUtc25hY2tiYXIvc2F2ZS1zbmFja2Jhci5jb21wb25lbnQnO1xuaW1wb3J0IHsgU2V0dGluZ0xpc3RGb3JtSGVscGVyIH0gZnJvbSAnLi4vX3NlcnZpY2VzL3NldHRpbmctbGlzdC1mb3JtLWhlbHBlcic7XG5pbXBvcnQgeyBSb2xsb3V0UGVyY2VudGFnZUl0ZW1Nb2RlbCwgUm9sbG91dFJ1bGVNb2RlbCwgU2VnbWVudExpc3RNb2RlbCwgU2V0dGluZ01vZGVsLCBVcGRhdGVTZXR0aW5nVmFsdWVNb2RlbCB9IGZyb20gJ25nLWNvbmZpZ2NhdC1wdWJsaWNhcGknO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjb25maWdjYXQtc2V0dGluZy1saXN0JyxcbiAgdGVtcGxhdGVVcmw6ICcuL3NldHRpbmctbGlzdC5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL3NldHRpbmctbGlzdC5jb21wb25lbnQuc2NzcyddXG59KVxuZXhwb3J0IGNsYXNzIFNldHRpbmdMaXN0Q29tcG9uZW50IGltcGxlbWVudHMgT25DaGFuZ2VzLCBPbkRlc3Ryb3kge1xuXG4gIEBJbnB1dCgpIHByb2R1Y3RJZCE6IHN0cmluZztcbiAgQElucHV0KCkgZW52aXJvbm1lbnRJZCE6IHN0cmluZztcbiAgQElucHV0KCkgY29uZmlnSWQhOiBzdHJpbmc7XG4gIEBJbnB1dCgpIGRhc2hib2FyZEJhc2VQYXRoID0gJ2h0dHBzOi8vYXBwLmNvbmZpZ2NhdC5jb20nO1xuXG4gIEBJbnB1dCgpIGNhbkRlbGV0ZVNldHRpbmcgPSBmYWxzZTtcblxuICBASW5wdXQoKSBvblNhdmUhOiAodmFsdWU6IFVwZGF0ZVNldHRpbmdWYWx1ZXNNb2RlbCkgPT4gT2JzZXJ2YWJsZTxTZXR0aW5nVmFsdWVzTW9kZWw+O1xuICBASW5wdXQoKSBsb2FkU2V0dGluZ1ZhbHVlcyE6ICgpID0+IE9ic2VydmFibGU8U2V0dGluZ1ZhbHVlc01vZGVsPjtcbiAgQElucHV0KCkgbG9hZFNlZ21lbnRzITogKCkgPT4gT2JzZXJ2YWJsZTxTZWdtZW50TGlzdE1vZGVsW10+O1xuICBASW5wdXQoKSBkZWxldGVTZXR0aW5nVGV4dCA9ICdEZWxldGUgc2V0dGluZyc7XG4gIEBJbnB1dCgpIHNob3dFbnZpcm9ubWVudE5hbWUgPSBmYWxzZTtcblxuICBAT3V0cHV0KCkgbG9hZFN1Y2NlZWRlZCA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcbiAgQE91dHB1dCgpIGRlbGV0ZVNldHRpbmdSZXF1ZXN0ZWQgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gIEBPdXRwdXQoKSBmb3JtVmFsdWVzQ2hhbmdlZCA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICBmb3JtVmFsdWVzQ2hhbmdlZFN1YnNjcmlwdGlvbiE6IFN1YnNjcmlwdGlvbiB8IG51bGw7XG5cbiAgbG9hZGluZyA9IHRydWU7XG5cbiAgc2V0dGluZ1ZhbHVlcyE6IFNldHRpbmdWYWx1ZXNNb2RlbDtcbiAgc2VnbWVudHMhOiBTZWdtZW50TGlzdE1vZGVsW107XG4gIGZvcm1Hcm91cCE6IFVudHlwZWRGb3JtR3JvdXA7XG5cbiAgc3VibWl0dGluZyA9IGZhbHNlO1xuICBzaG93UmV2ZXJ0UXVlc3Rpb24gPSBmYWxzZTtcbiAgc2hvd0ZlZWRCYWNrTWVzc2FnZSA9IGZhbHNlO1xuICByZWFkT25seSA9IGZhbHNlO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgZm9ybUhlbHBlcjogU2V0dGluZ0xpc3RGb3JtSGVscGVyLFxuICAgIHByaXZhdGUgc25hY2tCYXI6IE1hdFNuYWNrQmFyLFxuICAgIHByaXZhdGUgZGlhbG9nOiBNYXREaWFsb2cpIHsgfVxuXG4gIG5nT25DaGFuZ2VzKCk6IHZvaWQge1xuICAgIHRoaXMucmVsb2FkU2V0dGluZ1ZhbHVlcygpO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgaWYgKHRoaXMuZm9ybVZhbHVlc0NoYW5nZWRTdWJzY3JpcHRpb24pIHtcbiAgICAgIHRoaXMuZm9ybVZhbHVlc0NoYW5nZWRTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICAgIHRoaXMuZm9ybVZhbHVlc0NoYW5nZWRTdWJzY3JpcHRpb24gPSBudWxsO1xuICAgIH1cbiAgfVxuXG4gIHJlbG9hZFNldHRpbmdWYWx1ZXMoKSB7XG4gICAgdGhpcy5zaG93RmVlZEJhY2tNZXNzYWdlID0gZmFsc2U7XG4gICAgdGhpcy5sb2FkaW5nID0gdHJ1ZTtcbiAgICBmb3JrSm9pbih7XG4gICAgICBzZWdtZW50czogdGhpcy5sb2FkU2VnbWVudHMoKSxcbiAgICAgIHNldHRpbmdWYWx1ZXM6IHRoaXMubG9hZFNldHRpbmdWYWx1ZXMoKVxuICAgIH0pLnN1YnNjcmliZShyZXN1bHQgPT4ge1xuICAgICAgdGhpcy5yZWFkT25seSA9IHJlc3VsdC5zZXR0aW5nVmFsdWVzLnJlYWRPbmx5O1xuICAgICAgdGhpcy5zZXR0aW5nVmFsdWVzID0gcmVzdWx0LnNldHRpbmdWYWx1ZXM7XG4gICAgICB0aGlzLnNlZ21lbnRzID0gcmVzdWx0LnNlZ21lbnRzO1xuICAgICAgdGhpcy5jcmVhdGVGb3JtR3JvdXAoKTtcbiAgICAgIHRoaXMubG9hZGluZyA9IGZhbHNlO1xuICAgICAgdGhpcy5sb2FkU3VjY2VlZGVkLmVtaXQodHJ1ZSk7XG4gICAgfSxcbiAgICAgICgpID0+IHtcbiAgICAgICAgdGhpcy5zbmFja0Jhci5vcGVuKCdPb29wcy4gV2UgY291bGQgbm90IGxvYWQgeW91ciBGZWF0dXJlIEZsYWdzIGFuZCBTZXR0aW5ncy4gUGxlYXNlIHRyeSBhZ2FpbiBvciBjb250YWN0IHVzLicsXG4gICAgICAgICAgJ0Rpc21pc3MnLCB7IGR1cmF0aW9uOiA2MDAwMCwgcGFuZWxDbGFzczogJ3JlZC1zbmFja2JhcicgfSk7XG4gICAgICB9KTtcbiAgfVxuXG4gIGNyZWF0ZUZvcm1Hcm91cCgpIHtcbiAgICB0aGlzLmZvcm1Hcm91cCA9IHRoaXMuZm9ybUhlbHBlci5jcmVhdGVTZXR0aW5nVmFsdWVzRm9ybUdyb3VwKHRoaXMuc2V0dGluZ1ZhbHVlcyk7XG4gICAgdGhpcy5mb3JtVmFsdWVzQ2hhbmdlZFN1YnNjcmlwdGlvbiA9IHRoaXMuZm9ybUdyb3VwLnZhbHVlQ2hhbmdlcy5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgdGhpcy5mb3JtVmFsdWVzQ2hhbmdlZC5lbWl0KCk7XG4gICAgfSk7XG4gIH1cblxuICBzZXR0aW5nVmFsdWVzRm9ybUFycmF5KCkge1xuICAgIHJldHVybiB0aGlzLmZvcm1Hcm91cC5nZXQoJ3NldHRpbmdWYWx1ZXMnKSBhcyBVbnR5cGVkRm9ybUFycmF5O1xuICB9XG5cbiAgZ2V0U2V0dGluZ1ZhbHVlRm9ybUdyb3VwcygpIHtcbiAgICByZXR1cm4gdGhpcy5zZXR0aW5nVmFsdWVzRm9ybUFycmF5KCkuY29udHJvbHMubWFwKGMgPT4gYyBhcyBVbnR5cGVkRm9ybUdyb3VwKTtcbiAgfVxuXG4gIHByaXZhdGUgYnVpbGRVcGRhdGVTZXR0aW5nVmFsdWVzTW9kZWwoc2V0dGluZ1ZhbHVlc1ZNOiBVcGRhdGVTZXR0aW5nVmFsdWVNb2RlbFtdKSB7XG4gICAgcmV0dXJuIHNldHRpbmdWYWx1ZXNWTS5tYXAoc2V0dGluZ1ZhbHVlVk0gPT4ge1xuICAgICAgcmV0dXJuIDxVcGRhdGVTZXR0aW5nVmFsdWVNb2RlbD5cbiAgICAgICAge1xuICAgICAgICAgIHJvbGxvdXRSdWxlczogc2V0dGluZ1ZhbHVlVk0ucm9sbG91dFJ1bGVzPy5tYXAocm9sbG91dFJ1bGVWTSA9PlxuICAgICAgICAgICAgPFJvbGxvdXRSdWxlTW9kZWw+e1xuICAgICAgICAgICAgICBjb21wYXJpc29uQXR0cmlidXRlOiByb2xsb3V0UnVsZVZNLmNvbXBhcmlzb25BdHRyaWJ1dGUsXG4gICAgICAgICAgICAgIGNvbXBhcmF0b3I6IHJvbGxvdXRSdWxlVk0uY29tcGFyYXRvcixcbiAgICAgICAgICAgICAgY29tcGFyaXNvblZhbHVlOiB0aGlzLmZvcm1IZWxwZXIubm9ybWFsaXplQ29tcGFyaXNvblZhbHVlKHJvbGxvdXRSdWxlVk0uY29tcGFyYXRvciwgcm9sbG91dFJ1bGVWTS5jb21wYXJpc29uVmFsdWUpLFxuICAgICAgICAgICAgICBzZWdtZW50Q29tcGFyYXRvcjogcm9sbG91dFJ1bGVWTS5zZWdtZW50Q29tcGFyYXRvcixcbiAgICAgICAgICAgICAgc2VnbWVudElkOiByb2xsb3V0UnVsZVZNLnNlZ21lbnRJZCxcbiAgICAgICAgICAgICAgdmFsdWU6IHJvbGxvdXRSdWxlVk0udmFsdWVcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgIHJvbGxvdXRQZXJjZW50YWdlSXRlbXM6IHNldHRpbmdWYWx1ZVZNLnJvbGxvdXRQZXJjZW50YWdlSXRlbXM/Lm1hcChyb2xsb3V0UGVyY2VudGFnZUl0ZW1WTSA9PlxuICAgICAgICAgICAgPFJvbGxvdXRQZXJjZW50YWdlSXRlbU1vZGVsPntcbiAgICAgICAgICAgICAgcGVyY2VudGFnZTogcm9sbG91dFBlcmNlbnRhZ2VJdGVtVk0ucGVyY2VudGFnZSxcbiAgICAgICAgICAgICAgdmFsdWU6IHJvbGxvdXRQZXJjZW50YWdlSXRlbVZNLnZhbHVlXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICB2YWx1ZTogc2V0dGluZ1ZhbHVlVk0udmFsdWVcbiAgICAgICAgfTtcbiAgICB9KTtcbiAgfVxuXG4gIHN1Ym1pdCgpIHtcbiAgICBpZiAoIXRoaXMuZm9ybUdyb3VwIHx8ICF0aGlzLmZvcm1Hcm91cC52YWxpZCkge1xuICAgICAgdGhpcy5zaG93RmVlZEJhY2tNZXNzYWdlID0gdHJ1ZTtcbiAgICAgIHRoaXMuZm9ybUdyb3VwLm1hcmtBc1RvdWNoZWQoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLnNob3dGZWVkQmFja01lc3NhZ2UgPSBmYWxzZTtcbiAgICB0aGlzLnN1Ym1pdHRpbmcgPSB0cnVlO1xuXG4gICAgY29uc3QgdXBkYXRlU2V0dGluZ1ZhbHVlc01vZGVsID0gPFVwZGF0ZVNldHRpbmdWYWx1ZXNNb2RlbD57XG4gICAgICBzZXR0aW5nVmFsdWVzOiB0aGlzLmJ1aWxkVXBkYXRlU2V0dGluZ1ZhbHVlc01vZGVsKHRoaXMuZm9ybUdyb3VwLmNvbnRyb2xzLnNldHRpbmdWYWx1ZXMudmFsdWUpLFxuICAgICAga25vd25MYXN0VXBkYXRlZEF0OiB0aGlzLnNldHRpbmdWYWx1ZXMubGFzdFVwZGF0ZWRBdCxcbiAgICAgIGZvcmNlZDogZmFsc2VcbiAgICB9O1xuXG4gICAgaWYgKHRoaXMuc2V0dGluZ1ZhbHVlcy5yZWFzb25SZXF1aXJlZCkge1xuICAgICAgY29uc3QgZGlhbG9nUmVmID0gdGhpcy5kaWFsb2cub3BlbihSZWFzb25EaWFsb2dDb21wb25lbnQsIHtcbiAgICAgICAgd2lkdGg6ICc0NTBweCdcbiAgICAgIH0pO1xuICAgICAgZGlhbG9nUmVmLmFmdGVyQ2xvc2VkKClcbiAgICAgICAgLnN1YnNjcmliZShyZXN1bHQgPT4ge1xuICAgICAgICAgIGlmIChyZXN1bHQgJiYgcmVzdWx0LmJ1dHRvbiA9PT0gJ3NhdmUnICYmIHJlc3VsdC5yZWFzb24pIHtcblxuICAgICAgICAgICAgdXBkYXRlU2V0dGluZ1ZhbHVlc01vZGVsLnJlYXNvbiA9IHJlc3VsdC5yZWFzb247XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZVNldHRpbmdWYWx1ZXModXBkYXRlU2V0dGluZ1ZhbHVlc01vZGVsKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5zdWJtaXR0aW5nID0gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLnVwZGF0ZVNldHRpbmdWYWx1ZXModXBkYXRlU2V0dGluZ1ZhbHVlc01vZGVsKTtcbiAgfVxuXG4gIHVwZGF0ZVNldHRpbmdWYWx1ZXModXBkYXRlU2V0dGluZ1ZhbHVlc01vZGVsOiBhbnkpIHtcbiAgICB0aGlzLm9uU2F2ZSh1cGRhdGVTZXR0aW5nVmFsdWVzTW9kZWwpLnN1YnNjcmliZShzZXR0aW5nVmFsdWVzID0+IHtcbiAgICAgIHRoaXMuc2V0dGluZ1ZhbHVlcyA9IHNldHRpbmdWYWx1ZXM7XG4gICAgICB0aGlzLmNyZWF0ZUZvcm1Hcm91cCgpO1xuICAgICAgdGhpcy5zdWJtaXR0aW5nID0gZmFsc2U7XG4gICAgICB0aGlzLnNuYWNrQmFyLm9wZW5Gcm9tQ29tcG9uZW50KFNhdmVTbmFja2JhckNvbXBvbmVudCwgeyBkdXJhdGlvbjogNTAwMCwgcGFuZWxDbGFzczogJ2dyZWVuLXNuYWNrYmFyJyB9KTtcbiAgICB9LCAoZXJyb3IpID0+IHtcbiAgICAgIGlmIChlcnJvci5zdGF0dXMgPT09IDQwMCAmJiBlcnJvci5lcnJvciAmJiBlcnJvci5lcnJvci5SZWFzb24gJiYgZXJyb3IuZXJyb3IuUmVhc29uWzBdID09PSAnUmVhc29uIHJlcXVpcmVkJykge1xuICAgICAgICBjb25zdCBkaWFsb2dSZWYgPSB0aGlzLmRpYWxvZy5vcGVuKFJlYXNvbkRpYWxvZ0NvbXBvbmVudCwge1xuICAgICAgICAgIHdpZHRoOiAnNDUwcHgnXG4gICAgICAgIH0pO1xuICAgICAgICBkaWFsb2dSZWYuYWZ0ZXJDbG9zZWQoKVxuICAgICAgICAgIC5zdWJzY3JpYmUocmVzdWx0ID0+IHtcbiAgICAgICAgICAgIGlmIChyZXN1bHQgJiYgcmVzdWx0LmJ1dHRvbiA9PT0gJ3NhdmUnICYmIHJlc3VsdC5yZWFzb24pIHtcbiAgICAgICAgICAgICAgdXBkYXRlU2V0dGluZ1ZhbHVlc01vZGVsLnJlYXNvbiA9IHJlc3VsdC5yZWFzb247XG4gICAgICAgICAgICAgIHRoaXMudXBkYXRlU2V0dGluZ1ZhbHVlcyh1cGRhdGVTZXR0aW5nVmFsdWVzTW9kZWwpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgdGhpcy5zdWJtaXR0aW5nID0gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5mb3JtR3JvdXAuc2V0RXJyb3JzKHsgaW50ZXJuYWxTZXJ2ZXJFcnJvcjogJ0ludGVybmFsIHNlcnZlciBlcnJvcicgfSk7XG4gICAgICB0aGlzLnNob3dGZWVkQmFja01lc3NhZ2UgPSB0cnVlO1xuICAgIH0pO1xuICB9XG5cbiAgaGFuZGxlUmV2ZXJ0WWVzKCkge1xuICAgIHRoaXMuc2hvd1JldmVydFF1ZXN0aW9uID0gZmFsc2U7XG4gICAgdGhpcy5yZWxvYWRTZXR0aW5nVmFsdWVzKCk7XG4gIH1cblxuICBoYW5kbGVSZXZlcnRDYW5jZWwoKSB7XG4gICAgdGhpcy5zaG93UmV2ZXJ0UXVlc3Rpb24gPSBmYWxzZTtcbiAgfVxuXG4gIG9uRGVsZXRlU2V0dGluZ1JlcXVlc3RlZChzZXR0aW5nOiB7IHNldHRpbmc6IFNldHRpbmdNb2RlbCB9KSB7XG4gICAgdGhpcy5kZWxldGVTZXR0aW5nUmVxdWVzdGVkLmVtaXQoe1xuICAgICAgc2V0dGluZzogc2V0dGluZy5zZXR0aW5nLFxuICAgICAgZW52aXJvbm1lbnQ6IHRoaXMuc2V0dGluZ1ZhbHVlcy5lbnZpcm9ubWVudCxcbiAgICAgIGNvbmZpZzogdGhpcy5zZXR0aW5nVmFsdWVzLmNvbmZpZ1xuICAgIH0pO1xuICB9XG59XG4iLCI8Zm9ybSBbZm9ybUdyb3VwXT1cImZvcm1Hcm91cFwiIChuZ1N1Ym1pdCk9XCJzdWJtaXQoKVwiICpuZ0lmPVwiIWxvYWRpbmdcIj5cbiAgPGRpdiBjbGFzcz1cIndyYXBwZXJcIiAqbmdGb3I9XCJsZXQgc2V0dGluZ1ZhbHVlRnJvbUdyb3VwIG9mIGdldFNldHRpbmdWYWx1ZUZvcm1Hcm91cHMoKTsgbGV0IGkgPSBpbmRleFwiPlxuICAgIDxzZXR0aW5nIFtmb3JtR3JvdXBdPVwic2V0dGluZ1ZhbHVlRnJvbUdyb3VwXCIgW3JlYWRPbmx5XT1cInJlYWRPbmx5XCIgW2NhbkRlbGV0ZVNldHRpbmddPVwiY2FuRGVsZXRlU2V0dGluZ1wiXG4gICAgICAoZGVsZXRlU2V0dGluZ1JlcXVlc3RlZCk9XCJvbkRlbGV0ZVNldHRpbmdSZXF1ZXN0ZWQoJGV2ZW50KVwiIFtkZWxldGVTZXR0aW5nVGV4dF09XCJkZWxldGVTZXR0aW5nVGV4dFwiXG4gICAgICBbc2hvd0Vudmlyb25tZW50TmFtZV09XCJzaG93RW52aXJvbm1lbnROYW1lXCIgW3NlZ21lbnRzXT1cInNlZ21lbnRzXCIgW3Byb2R1Y3RJZF09XCJwcm9kdWN0SWRcIiBbY29uZmlnSWRdPVwiY29uZmlnSWRcIlxuICAgICAgW2Vudmlyb25tZW50SWRdPVwiZW52aXJvbm1lbnRJZFwiIFtkYXNoYm9hcmRCYXNlUGF0aF09XCJkYXNoYm9hcmRCYXNlUGF0aFwiPlxuICAgIDwvc2V0dGluZz5cbiAgPC9kaXY+XG5cbiAgPGRpdiBjbGFzcz1cInNhdmVcIiAqbmdJZj1cIiFyZWFkT25seSAmJiAhc3VibWl0dGluZyAmJiBmb3JtR3JvdXAuZGlydHlcIj5cbiAgICA8ZGl2IGNsYXNzPVwiZmVlZGJhY2tcIiAqbmdJZj1cImZvcm1Hcm91cC50b3VjaGVkICYmIGZvcm1Hcm91cC5pbnZhbGlkICYmIHNob3dGZWVkQmFja01lc3NhZ2VcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJlcnJvclwiICpuZ0lmPVwiZm9ybUdyb3VwLmVycm9ycyAmJiBmb3JtR3JvdXAuZXJyb3JzLmludGVybmFsU2VydmVyRXJyb3JcIj5cbiAgICAgICAgPHNwYW4+U29tZXRoaW5nIHdlbnQgd3JvbmcgYW5kIHdlIGNvdWxkIG5vdCBzYXZlIHlvdXIgc2V0dGluZ3MuIFlvdSBjYW4gdHJ5IGFnYWluIG9yIDxhXG4gICAgICAgICAgICBocmVmPVwiaHR0cHM6Ly9jb25maWdjYXQuY29tL3N1cHBvcnRcIiB0YXJnZXQ9XCJfYmxhbmtcIiByZWw9XCJub29wZW5lciBub3JlZmVycmVyXCI+Y29udGFjdCB1cy48L2E+PC9zcGFuPlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwiZXJyb3JcIiAqbmdJZj1cIiFmb3JtR3JvdXAuZXJyb3JzIHx8ICFmb3JtR3JvdXAuZXJyb3JzLmludGVybmFsU2VydmVyRXJyb3JcIj5cbiAgICAgICAgPHNwYW4+T2ggbm8hIEEgZmVhdHVyZSBmbGFnIGhhcyBpbnZhbGlkIG9yIG1pc3NpbmcgZGF0YS48L3NwYW4+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBtYXQtc3Ryb2tlZC1idXR0b24gKm5nSWY9XCIhc2hvd1JldmVydFF1ZXN0aW9uXCIgKGNsaWNrKT1cInNob3dSZXZlcnRRdWVzdGlvbiA9IHRydWVcIj5cbiAgICAgIDxtYXQtaWNvbj5oaXN0b3J5PC9tYXQtaWNvbj48c3Bhbj5SZXZlcnQgY2hhbmdlczwvc3Bhbj5cbiAgICA8L2J1dHRvbj5cbiAgICA8ZGl2ICpuZ0lmPVwic2hvd1JldmVydFF1ZXN0aW9uXCI+XG4gICAgICA8c3BhbiBjbGFzcz1cInJldmVydFwiPlJldmVydCB0byBsYXN0IHNhdmVkIHN0YXRlPzwvc3Bhbj5cbiAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwieWVzXCIgbWF0LXN0cm9rZWQtYnV0dG9uIChjbGljayk9XCJoYW5kbGVSZXZlcnRZZXMoKVwiPlllczwvYnV0dG9uPlxuICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgbWF0LXN0cm9rZWQtYnV0dG9uIChjbGljayk9XCJoYW5kbGVSZXZlcnRDYW5jZWwoKVwiPk5vPC9idXR0b24+XG4gICAgPC9kaXY+XG4gICAgPGJ1dHRvbiBjbGFzcz1cInNhdmUtYnV0dG9uXCIgbWF0LWZsYXQtYnV0dG9uIGNvbG9yPVwid2FyblwiIHR5cGU9XCJzdWJtaXRcIiBbZGlzYWJsZWRdPVwic3VibWl0dGluZ1wiPlxuICAgICAgPG1hdC1pY29uPmJhY2t1cDwvbWF0LWljb24+IDxzcGFuPiBTYXZlICYgcHVibGlzaCBjaGFuZ2VzPC9zcGFuPlxuICAgIDwvYnV0dG9uPlxuICA8L2Rpdj5cbjwvZm9ybT4iXX0=