@posiwise/smart-crm 0.0.53 → 0.0.55

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 (69) hide show
  1. package/fesm2022/posiwise-smart-crm.mjs +244 -246
  2. package/fesm2022/posiwise-smart-crm.mjs.map +1 -1
  3. package/lib/private/components/smart-crm-accounts/smart-crm-accounts.component.d.ts +1 -0
  4. package/lib/private/components/smart-crm-insight/smart-crm-account-insight/smart-crm-account-insight.component.d.ts +1 -1
  5. package/lib/private/components/smart-crm-opportunities/smart-crm-opportunities-list/smart-crm-opportunities-list.component.d.ts +1 -0
  6. package/package.json +3 -5
  7. package/esm2022/index.mjs +0 -52
  8. package/esm2022/lib/private/components/smart-crm-accounts/smart-crm-account-details/smart-crm-account-details.component.mjs +0 -210
  9. package/esm2022/lib/private/components/smart-crm-accounts/smart-crm-account-files/smart-crm-account-files.component.mjs +0 -191
  10. package/esm2022/lib/private/components/smart-crm-accounts/smart-crm-account-info/smart-crm-account-info.component.mjs +0 -612
  11. package/esm2022/lib/private/components/smart-crm-accounts/smart-crm-account-invoices/smart-crm-account-invoices.component.mjs +0 -71
  12. package/esm2022/lib/private/components/smart-crm-accounts/smart-crm-accounts.component.mjs +0 -361
  13. package/esm2022/lib/private/components/smart-crm-actions/smart-crm-actions.component.mjs +0 -267
  14. package/esm2022/lib/private/components/smart-crm-competition/smart-crm-competition/smart-crm-competition.component.mjs +0 -12
  15. package/esm2022/lib/private/components/smart-crm-configuration/smart-crm-actions/smart-crm-actions-details/smart-crm-actions-details.component.mjs +0 -103
  16. package/esm2022/lib/private/components/smart-crm-configuration/smart-crm-actions/smart-crm-actions.component.mjs +0 -126
  17. package/esm2022/lib/private/components/smart-crm-configuration/smart-crm-configuration.component.mjs +0 -35
  18. package/esm2022/lib/private/components/smart-crm-configuration/smart-crm-opportunity-categories/smart-crm-opportunity-categories-details/smart-crm-opportunity-categories-details.component.mjs +0 -88
  19. package/esm2022/lib/private/components/smart-crm-configuration/smart-crm-opportunity-categories/smart-crm-opportunity-categories.component.mjs +0 -120
  20. package/esm2022/lib/private/components/smart-crm-configuration/smart-crm-source/smart-crm-source-details/smart-crm-source-details.component.mjs +0 -79
  21. package/esm2022/lib/private/components/smart-crm-configuration/smart-crm-source/smart-crm-source.component.mjs +0 -107
  22. package/esm2022/lib/private/components/smart-crm-configuration/smart-crm-stages/smart-crm-stage-details/smart-crm-stage-details.component.mjs +0 -97
  23. package/esm2022/lib/private/components/smart-crm-configuration/smart-crm-stages/smart-crm-stages.component.mjs +0 -156
  24. package/esm2022/lib/private/components/smart-crm-configuration/smart-crm-widgets/smart-crm-widgets-details/smart-crm-widgets-details.component.mjs +0 -99
  25. package/esm2022/lib/private/components/smart-crm-configuration/smart-crm-widgets/smart-crm-widgets.component.mjs +0 -125
  26. package/esm2022/lib/private/components/smart-crm-contacts/smart-crm-contact-details/smart-crm-contact-details.component.mjs +0 -197
  27. package/esm2022/lib/private/components/smart-crm-contacts/smart-crm-contact-info/smart-crm-contact-info.component.mjs +0 -481
  28. package/esm2022/lib/private/components/smart-crm-contacts/smart-crm-contacts.component.mjs +0 -301
  29. package/esm2022/lib/private/components/smart-crm-customer/smart-crm-customer-success/smart-crm-customer-success.component.mjs +0 -12
  30. package/esm2022/lib/private/components/smart-crm-insight/smart-crm-account-insight/smart-crm-account-insight.component.mjs +0 -314
  31. package/esm2022/lib/private/components/smart-crm-insight/smart-crm-analysis-insight/smart-crm-analysis.component.mjs +0 -104
  32. package/esm2022/lib/private/components/smart-crm-insight/smart-crm-contact-insight/smart-crm-contact-insight.component.mjs +0 -105
  33. package/esm2022/lib/private/components/smart-crm-insight/smart-crm-insight.component.mjs +0 -27
  34. package/esm2022/lib/private/components/smart-crm-insight/smart-crm-marketing-insight/smart-crm-marketing-insight.component.mjs +0 -80
  35. package/esm2022/lib/private/components/smart-crm-insight/smart-crm-opportunities-insight/smart-crm-opportunities-insight.component.mjs +0 -160
  36. package/esm2022/lib/private/components/smart-crm-leads/smart-crm-leads-details/smart-crm-leads-details.component.mjs +0 -227
  37. package/esm2022/lib/private/components/smart-crm-leads/smart-crm-leads.component.mjs +0 -146
  38. package/esm2022/lib/private/components/smart-crm-marketing/smart-crm-marketing-list/smart-crm-marketing-contacts/smart-crm-marketing-contacts.component.mjs +0 -79
  39. package/esm2022/lib/private/components/smart-crm-marketing/smart-crm-marketing-list/smart-crm-marketing-details/smart-crm-marketing-details.component.mjs +0 -269
  40. package/esm2022/lib/private/components/smart-crm-marketing/smart-crm-marketing-list/smart-crm-marketing-list.component.mjs +0 -157
  41. package/esm2022/lib/private/components/smart-crm-marketing/smart-crm-marketing-list/smart-crm-marketing-view-details/smart-crm-marketing-view-details.component.mjs +0 -60
  42. package/esm2022/lib/private/components/smart-crm-marketing/smart-crm-marketing.component.mjs +0 -18
  43. package/esm2022/lib/private/components/smart-crm-media/smart-crm-social-media/smart-crm-social-media.component.mjs +0 -12
  44. package/esm2022/lib/private/components/smart-crm-opportunities/smart-crm-board/smart-crm-board.component.mjs +0 -236
  45. package/esm2022/lib/private/components/smart-crm-opportunities/smart-crm-opportunities-list/smart-crm-opportunities-details/smart-crm-opportunities-details.component.mjs +0 -376
  46. package/esm2022/lib/private/components/smart-crm-opportunities/smart-crm-opportunities-list/smart-crm-opportunities-info/smart-crm-opportunities-info.component.mjs +0 -483
  47. package/esm2022/lib/private/components/smart-crm-opportunities/smart-crm-opportunities-list/smart-crm-opportunities-list.component.mjs +0 -256
  48. package/esm2022/lib/private/components/smart-crm-opportunities/smart-crm-opportunities.component.mjs +0 -14
  49. package/esm2022/lib/private/components/smart-crm-tabs/smart-crm-tabs.component.mjs +0 -99
  50. package/esm2022/lib/private/smart-crm-private.module.mjs +0 -356
  51. package/esm2022/lib/private/smart-crm-private.routing.module.mjs +0 -318
  52. package/esm2022/lib/public/components/smart-crm-newsletter-confirmation/smart-crm-newsletter-confirmation.component.mjs +0 -56
  53. package/esm2022/lib/public/components/smart-crm-newsletter-unsubscribe/smart-crm-newsletter-unsubscribe.component.mjs +0 -57
  54. package/esm2022/lib/public/components/smart-crm-signup/smart-crm-signup.component.mjs +0 -38
  55. package/esm2022/lib/public/smart-crm-public.module.mjs +0 -46
  56. package/esm2022/lib/public/smart-crm-public.routing.module.mjs +0 -44
  57. package/esm2022/lib/shared/interface/crm-account.interface.mjs +0 -2
  58. package/esm2022/lib/shared/interface/crm-action.interface.mjs +0 -2
  59. package/esm2022/lib/shared/interface/crm-contact.interface.mjs +0 -2
  60. package/esm2022/lib/shared/interface/crm-lead.interface.mjs +0 -2
  61. package/esm2022/lib/shared/interface/crm-newsletter.interface.mjs +0 -2
  62. package/esm2022/lib/shared/interface/crm-opportunity.interface.mjs +0 -2
  63. package/esm2022/lib/shared/interface/crm-source.interface.mjs +0 -2
  64. package/esm2022/lib/shared/interface/crm-stages.interface.mjs +0 -2
  65. package/esm2022/lib/shared/interface/crm-widget.interface.mjs +0 -2
  66. package/esm2022/lib/shared/interface/smart-crm-module.interface.mjs +0 -2
  67. package/esm2022/lib/shared/models/smart-crm.model.mjs +0 -191
  68. package/esm2022/lib/shared/routers/routers.mjs +0 -24
  69. package/esm2022/posiwise-smart-crm.mjs +0 -5
@@ -1,314 +0,0 @@
1
- import { Component, Injector } from '@angular/core';
2
- import { AppBaseComponent } from '@posiwise/app-base-component';
3
- import { CrmService } from '@posiwise/smart-crm-shared';
4
- import { ROUTERS } from '../../../../shared/routers/routers';
5
- import * as i0 from "@angular/core";
6
- import * as i1 from "@posiwise/smart-crm-shared";
7
- import * as i2 from "@angular/common";
8
- import * as i3 from "@ng-bootstrap/ng-bootstrap";
9
- import * as i4 from "@posiwise/directives";
10
- import * as i5 from "angular-plotly.js";
11
- import * as i6 from "@angular/router";
12
- import * as i7 from "primeng/table";
13
- import * as i8 from "primeng/api";
14
- import * as i9 from "primeng/tooltip";
15
- import * as i10 from "primeng/progressspinner";
16
- import * as i11 from "@posiwise/shared-components";
17
- import * as i12 from "@posiwise/pipes";
18
- import * as i13 from "@jsverse/transloco";
19
- export class SmartCrmAccountInsightComponent extends AppBaseComponent {
20
- constructor(crmService, injector) {
21
- super(injector);
22
- this.crmService = crmService;
23
- this.signUpLastNinetyDaysLoaded = false;
24
- this.accountLastActivitiesLoaded = false;
25
- this.churnedAccountLoaded = false;
26
- this.activeOpportunitiesLoaded = false;
27
- this.accountAtRiskDetailsLoaded = false;
28
- this.contactRenewalLoaded = false;
29
- this.creditCardExpiringDetailsLoaded = false;
30
- this.accountGeographyLoaded = false;
31
- this.accountInsightLoaded = false;
32
- this.magicMomentLoaded = false;
33
- // Totals for MRR columns
34
- this.activeOpportunitiesTotal = { total_mrr: 0 };
35
- this.accountAtRiskTotal = { total_mrr: 0 };
36
- this.contractRenewalTotal = { total_mrr: 0 };
37
- this.creditCardExpiringTotal = { total_mrr: 0 };
38
- this.magicMomentTotal = { total_mrr: 0 };
39
- this.signedUpLastNinetyDaysTotal = { total_mrr: 0 };
40
- this.churnedAccountsTotal = { total_mrr: 0 };
41
- this.routers = ROUTERS;
42
- }
43
- ngOnInit() {
44
- this.getUserSubscription().subscribe(response => {
45
- this.subscription = response;
46
- if (this.subscription?.id) {
47
- this.hasAccess = this.hasAdminAccess(this.subscription.id);
48
- this.getUserInfo();
49
- }
50
- });
51
- }
52
- getUserInfo() {
53
- this.userStore().subscribe(user => {
54
- if (user) {
55
- this.user = user;
56
- this.userId = user.id;
57
- if (this.permissionService.isGranted('Pages.Beta') ||
58
- this.permissionService.isSuperAdmin()) {
59
- this.getSignedUpLastNinetyDays();
60
- this.getActiveOpportunities();
61
- this.getChurnedAccounts();
62
- this.getAccountLastActivities();
63
- this.getAccountAtRiskDetails();
64
- this.getContactRenewal();
65
- this.getCreditCardExpiringDetails();
66
- this.getMagicMoment();
67
- this.getAccountGeography();
68
- this.getAccountInsights();
69
- }
70
- }
71
- });
72
- }
73
- /** Function to call signed up last 90 days details */
74
- getSignedUpLastNinetyDays() {
75
- this.crmService
76
- .getCrmAnalytics(this.subscription?.id, 'accounts_signed_up_last_90_days')
77
- .subscribe(response => {
78
- // API now returns { items: [], totals: {} } instead of array
79
- const items = response?.items || response;
80
- if (typeof items === 'object' && Object.keys(items).length === 0) {
81
- this.signedUpLastThirtyDays = [];
82
- }
83
- else {
84
- this.signedUpLastThirtyDays = Array.isArray(items) ? items : [];
85
- }
86
- // Extract totals from API response
87
- if (response?.totals) {
88
- this.signedUpLastNinetyDaysTotal = {
89
- total_mrr: response.totals.expected_mrr_usd || response.totals.monthly_amount || 0
90
- };
91
- }
92
- })
93
- .add(() => {
94
- this.signUpLastNinetyDaysLoaded = true;
95
- });
96
- }
97
- getAccountLastActivities() {
98
- this.crmService
99
- .getCrmAnalytics(this.subscription?.id, 'accounts_last_activities')
100
- .subscribe(response => {
101
- // API now returns { items: [], totals: {} } instead of array
102
- const items = response?.items || response;
103
- if (typeof items === 'object' && Object.keys(items).length === 0) {
104
- this.accountLastActivities = [];
105
- }
106
- else {
107
- this.accountLastActivities = Array.isArray(items) ? items : [];
108
- this.actionNames = this.accountLastActivities?.map((action) => {
109
- return action?.crm_action?.name;
110
- });
111
- }
112
- })
113
- .add(() => {
114
- this.accountLastActivitiesLoaded = true;
115
- });
116
- }
117
- getChurnedAccounts() {
118
- this.crmService
119
- .getCrmAnalytics(this.subscription?.id, 'accounts_accounts_churned')
120
- .subscribe(response => {
121
- // API now returns { items: [], totals: {} } instead of array
122
- const items = response?.items || response;
123
- if (typeof items === 'object' && Object.keys(items).length === 0) {
124
- this.churnedAccounts = [];
125
- }
126
- else {
127
- this.churnedAccounts = Array.isArray(items) ? items : [];
128
- }
129
- // Extract totals from API response
130
- if (response?.totals) {
131
- this.churnedAccountsTotal = {
132
- total_mrr: response.totals.expected_mrr_usd || response.totals.monthly_amount || 0
133
- };
134
- }
135
- })
136
- .add(() => {
137
- this.churnedAccountLoaded = true;
138
- });
139
- }
140
- /** Function to call Active Opportunities details */
141
- getActiveOpportunities() {
142
- this.crmService
143
- .getCrmAnalytics(this.subscription?.id, 'accounts_active_opportunities')
144
- .subscribe(response => {
145
- // API now returns { items: [], totals: {} } instead of array
146
- const items = response?.items || response;
147
- if (typeof items === 'object' && Object.keys(items).length === 0) {
148
- this.activeOpportunities = [];
149
- }
150
- else {
151
- this.activeOpportunities = Array.isArray(items) ? items : [];
152
- }
153
- // Extract totals from API response
154
- if (response?.totals) {
155
- this.activeOpportunitiesTotal = {
156
- total_mrr: response.totals.expected_mrr_usd ||
157
- response.totals.expected_close_value ||
158
- 0
159
- };
160
- }
161
- })
162
- .add(() => {
163
- this.activeOpportunitiesLoaded = true;
164
- });
165
- }
166
- getMagicMoment() {
167
- this.crmService
168
- .getCrmAnalytics(this.subscription?.id, 'magic_moment')
169
- .subscribe(response => {
170
- // API now returns { items: [], totals: {} } instead of array
171
- const items = response?.items || response;
172
- if (typeof items === 'object' && Object.keys(items).length === 0) {
173
- this.magicMoment = [];
174
- }
175
- else {
176
- this.magicMoment = Array.isArray(items) ? items : [];
177
- }
178
- // Extract totals from API response
179
- if (response?.totals) {
180
- this.magicMomentTotal = {
181
- total_mrr: response.totals.expected_mrr_usd || response.totals.monthly_amount || 0
182
- };
183
- }
184
- })
185
- .add(() => {
186
- this.magicMomentLoaded = true;
187
- });
188
- }
189
- getCreditCardExpiringDetails() {
190
- this.crmService
191
- .getCrmAnalytics(this.subscription?.id, 'credit_card_expiring')
192
- .subscribe(response => {
193
- // API now returns { items: [], totals: {} } instead of array
194
- const items = response?.items || response;
195
- if (typeof items === 'object' && Object.keys(items).length === 0) {
196
- this.creditCardExpiring = [];
197
- }
198
- else {
199
- this.creditCardExpiring = Array.isArray(items) ? items : [];
200
- }
201
- // Extract totals from API response
202
- if (response?.totals) {
203
- this.creditCardExpiringTotal = {
204
- total_mrr: response.totals.expected_mrr_usd || response.totals.monthly_amount || 0
205
- };
206
- }
207
- })
208
- .add(() => {
209
- this.creditCardExpiringDetailsLoaded = true;
210
- });
211
- }
212
- /** Function to call Account At Risk details */
213
- getAccountAtRiskDetails() {
214
- this.crmService
215
- .getCrmAnalytics(this.subscription?.id, 'accounts_accounts_at_risk')
216
- .subscribe(response => {
217
- // API now returns { items: [], totals: {} } instead of array
218
- const items = response?.items || response;
219
- if (typeof items === 'object' && Object.keys(items).length === 0) {
220
- this.accountAtRisk = [];
221
- }
222
- else {
223
- this.accountAtRisk = Array.isArray(items) ? items : [];
224
- }
225
- // Extract totals from API response
226
- if (response?.totals) {
227
- this.accountAtRiskTotal = {
228
- total_mrr: response.totals.expected_mrr_usd || response.totals.monthly_amount || 0
229
- };
230
- }
231
- })
232
- .add(() => {
233
- this.accountAtRiskDetailsLoaded = true;
234
- });
235
- }
236
- /** Function to call Contract renewal details */
237
- getContactRenewal() {
238
- this.crmService
239
- .getCrmAnalytics(this.subscription?.id, 'accounts_contract_renewal')
240
- .subscribe(response => {
241
- // API now returns { items: [], totals: {} } instead of array
242
- const items = response?.items || response;
243
- if (typeof items === 'object' && Object.keys(items).length === 0) {
244
- this.ContractRenewal = [];
245
- }
246
- else {
247
- this.ContractRenewal = Array.isArray(items) ? items : [];
248
- }
249
- // Extract totals from API response
250
- if (response?.totals) {
251
- this.contractRenewalTotal = {
252
- total_mrr: response.totals.expected_mrr_usd || response.totals.monthly_amount || 0
253
- };
254
- }
255
- })
256
- .add(() => {
257
- this.contactRenewalLoaded = true;
258
- });
259
- }
260
- getAccountInsights() {
261
- this.crmService
262
- .getCrmAnalytics(this.subscription?.id, 'accounts_insights')
263
- .subscribe(response => {
264
- // API now returns { items: [], totals: {} } instead of array
265
- const items = response?.items || response;
266
- if (typeof items === 'object' && Object.keys(items).length === 0) {
267
- this.accountInsight = [];
268
- }
269
- else {
270
- this.accountInsight = Array.isArray(items) ? items : [];
271
- }
272
- })
273
- .add(() => {
274
- this.accountInsightLoaded = true;
275
- });
276
- }
277
- getAccountGeography() {
278
- this.crmService
279
- .getCrmAnalytics(this.subscription?.id, 'accounts_geography')
280
- .subscribe(response => {
281
- // API now returns { items: [], totals: {} } instead of array/object
282
- const items = response?.items || response;
283
- if (typeof items === 'object' && Object.keys(items).length === 0) {
284
- this.accountGeography = { data: [], layout: {} };
285
- }
286
- else {
287
- this.accountGeography = items;
288
- }
289
- })
290
- .add(() => {
291
- this.accountGeographyLoaded = true;
292
- });
293
- }
294
- checkPermission(permission) {
295
- return this.permissionService.evaluatePermissions(permission);
296
- }
297
- getMainCurrencyForTable(items) {
298
- if (items && items.length > 0) {
299
- const firstItem = items[0];
300
- return firstItem?.main_currency || firstItem?.currency || 'USD';
301
- }
302
- return 'USD';
303
- }
304
- ngOnDestroy() {
305
- super.ngOnDestroy();
306
- }
307
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: SmartCrmAccountInsightComponent, deps: [{ token: i1.CrmService }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Component }); }
308
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.11", type: SmartCrmAccountInsightComponent, selector: "pw-smart-crm-account-insight", usesInheritance: true, ngImport: i0, template: "<div class=\"row\">\n <ng-container class=\"mt-5\">\n\n <!-- Signed up last 90 days -->\n <div class=\"col-12 col-md-6 mb-3 analytics\">\n <h5 class=\"accordion-heading\">Signed up Last 90 Days</h5>\n <div class=\"w-100 text-center mt-3\">\n <ng-template [ngIf]=\"!signUpLastNinetyDaysLoaded\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </ng-template>\n </div>\n <div class=\"primeng-datatable-container table-responsive\"\n *ngIf=\"signedUpLastThirtyDays?.length\">\n <p-table class=\"table\"\n #dt\n [value]=\"signedUpLastThirtyDays\"\n [paginator]=\"true\"\n [rows]=\"20\"\n [totalRecords]=\"signedUpLastThirtyDays.length\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\">{{ 'Crm.Summary.Account' | transloco }}</th>\n <th scope=\"true\" class=\"mrr-header\">{{ 'Crm.AccountMessage.MRR' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.SignUpAt' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\"\n let-signUp\n let-i=\"rowIndex\">\n <!-- Totals row at the top (first row) -->\n <ng-container *ngIf=\"i === 0 && signedUpLastThirtyDays?.length\">\n <tr class=\"totals-row\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ signedUpLastNinetyDaysTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n </tr>\n </ng-container>\n <!-- Regular data row -->\n <tr>\n <td data-head=\"Account\">\n <a [routerLink]=\"['/' + subscription?.slug + routers.accountInfo, signUp.crm_account_id]\" class=\"name-link\">\n <span [ngbTooltip]=\"signUp.crm_account_name\">{{ signUp?.crm_account_name | textTruncate:20 }}</span>\n </a>\n </td>\n <td data-head=\"MRR\" class=\"expected-mrr\">\n {{ signUp.expected_mrr / 100 | currency: (signUp.currency || signUp.main_currency) }}\n </td>\n <td data-head=\"SignUpAt\">\n {{ signUp.signed_up_at | dateFormat }}\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n <tr *ngIf=\"signedUpLastThirtyDays?.length\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ signedUpLastNinetyDaysTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n </tr>\n </ng-template>\n </p-table>\n <span class=\"total-records-count\" *ngIf=\"signedUpLastThirtyDays.length!== 0\">{{ 'Label.Total' | transloco }}: {{ signedUpLastThirtyDays.length }}</span>\n </div>\n <div *ngIf=\"signedUpLastThirtyDays?.length === 0\">\n <pw-no-data [withImage]=\"true\" [message]=\"'Crm.Summary.NoInsightMessage' | transloco\"> </pw-no-data>\n </div>\n </div>\n\n <!-- Churned Last 90 days -->\n <div class=\"col-12 col-md-6 mb-3 analytics\">\n <h5 class=\"accordion-heading\">Churned Last 90 Days</h5>\n <div class=\"w-100 text-center mt-3\">\n <ng-template [ngIf]=\"!churnedAccountLoaded\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </ng-template>\n </div>\n <div class=\"primeng-datatable-container table-responsive\" *ngIf=\"churnedAccounts?.length\">\n <p-table class=\"table\" #dt [value]=\"churnedAccounts\" [paginator]=\"true\" [rows]=\"20\"\n [totalRecords]=\"churnedAccounts.length\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Account' | transloco }}</th>\n <th scope=\"true\" class=\"mrr-header\">{{ 'Crm.AccountMessage.MRR' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Quarter' | transloco }}</th>\n <th scope=\"true\"> {{ 'Crm.AccountMessage.Month' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.SignUpAt' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.UnsubscribedAt' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-account let-i=\"rowIndex\">\n <!-- Totals row at the top (first row) -->\n <ng-container *ngIf=\"i === 0 && churnedAccounts?.length\">\n <tr class=\"totals-row\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ churnedAccountsTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n <td></td>\n <td></td>\n </tr>\n </ng-container>\n <!-- Regular data row -->\n <tr>\n <td data-head=\"Account\">\n <a [routerLink]=\"['/' + subscription?.slug + routers.accountInfo, account.crm_account_id]\"\n class=\"name-link\">\n <span [ngbTooltip]=\"account.crm_account_name\">{{ account.crm_account_name | textTruncate:20 }}</span>\n </a>\n </td>\n <td data-head=\"MRR\" class=\"expected-mrr\"> {{ account.expected_mrr / 100 | currency: ( account.main_currency || account.currency) }} </td>\n <td data-head=\"Quarter\" [ngClass]=\"{'month-quarter-text fw-bold': account.sessions_last_quarter > 15}\">{{ account.sessions_last_quarter }}</td>\n <td data-head=\"Month\" [ngClass]=\"{'month-quarter-text fw-bold': account.sessions_last_month > 5}\">{{ account.sessions_last_month }}</td>\n <td data-head=\"SignUpAt\"> {{ account.signed_up_at | dateFormat }} </td>\n <td data-head=\"UnsubscribedAt\" [ngClass]=\"{'text-danger': account.unsubscribed_at | isPastDate}\">\n {{ account.unsubscribed_at | dateFormat }}\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n <tr *ngIf=\"churnedAccounts?.length\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ churnedAccountsTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n <td></td>\n <td></td>\n </tr>\n </ng-template>\n </p-table>\n <span class=\"total-records-count\" *ngIf=\"churnedAccounts?.length !== 0\">{{ 'Label.Total' | transloco }}: {{\n churnedAccounts.length }}</span>\n </div>\n <div *ngIf=\"churnedAccounts?.length === 0 && churnedAccountLoaded\">\n <pw-no-data [withImage]=\"true\" [message]=\"'Crm.Summary.NoInsightMessage' | transloco\"> </pw-no-data>\n </div>\n </div>\n\n <!-- Active Opportunities -->\n <div class=\"col-12 col-md-6 mb-3 analytics\">\n <h5 class=\"accordion-heading\">Active Opportunities</h5>\n <div class=\"w-100 text-center mt-3\">\n <ng-template [ngIf]=\"!activeOpportunitiesLoaded\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </ng-template>\n </div>\n <div class=\"primeng-datatable-container table-responsive\"\n *ngIf=\"activeOpportunities?.length\">\n <p-table class=\"table\"\n #dt\n [value]=\"activeOpportunities\"\n [paginator]=\"true\"\n [rows]=\"20\"\n\n [totalRecords]=\"activeOpportunities.length\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\">{{ 'Crm.Summary.Account' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.Summary.Title' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.Summary.OneTimeAmount' | transloco }}</th>\n <th scope=\"true\" class=\"mrr-header\">{{ 'Crm.AccountMessage.MRR' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.Summary.WinChance' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\"\n let-opportunities\n let-i=\"rowIndex\">\n <!-- Totals row at the top (first row) -->\n <ng-container *ngIf=\"i === 0 && activeOpportunities?.length\">\n <tr class=\"totals-row\">\n <td></td>\n <td></td>\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ activeOpportunitiesTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n </tr>\n </ng-container>\n <!-- Regular data row -->\n <tr>\n <td data-head=\"Account\">\n <a [routerLink]=\"['/' + subscription?.slug + routers.accountInfo, opportunities.crm_account?.id]\" class=\"name-link\">\n <span [ngbTooltip]=\"opportunities.crm_account?.name\">{{ opportunities.crm_account?.name | textTruncate:20 }}</span>\n </a>\n </td>\n <td data-head=\"Title\">\n <a [ngbTooltip]=\"opportunities?.title\" *ngIf=\"\n hasAccess ||\n opportunities?.owner_id === userId ||\n checkPermission('Pages.Product.CRM.Role.Admin')\n \" [routerLink]=\"[\n '/' + subscription?.slug + routers.opportunityInfo,\n opportunities.id\n ]\">\n <span>{{ opportunities?.title | textTruncate: 20 }} </span>\n </a>\n </td>\n <td data-head=\"One Time Amount\"> {{ opportunities.one_time_amount / 100 | currency: (opportunities.main_currency || opportunities.currency) }} </td>\n <td data-head=\"Monthly Amount\" class=\"expected-mrr\"> {{ opportunities.monthly_amount / 100 | currency: (opportunities.main_currency || opportunities.currency) }} </td>\n <td data-head=\"Win Chance\"> {{ opportunities.win_chances / 100 | percent }} <span class=\"text-danger\"\n *ngIf=\"opportunities.cancelled\">!Cancelled!</span>\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n <tr *ngIf=\"activeOpportunities?.length\">\n <td></td>\n <td></td>\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ activeOpportunitiesTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n </tr>\n </ng-template>\n </p-table>\n <span class=\"total-records-count\" *ngIf=\"activeOpportunities.length !== 0\">{{ 'Label.Total' | transloco }}: {{ activeOpportunities.length }}</span>\n </div>\n <div *ngIf=\"activeOpportunities?.length === 0\">\n <pw-no-data [withImage]=\"true\" [message]=\"'Crm.Summary.NoInsightMessage' | transloco\"> </pw-no-data>\n </div>\n </div>\n\n <!-- Last Activities -->\n <div class=\"col-12 col-md-6 mb-3 analytics\">\n <h5 class=\"accordion-heading\">Latest Activities</h5>\n <div class=\"w-100 text-center mt-3\">\n <ng-template [ngIf]=\"!accountLastActivitiesLoaded\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </ng-template>\n </div>\n <div class=\"primeng-datatable-container table-responsive\"\n *ngIf=\"accountLastActivities?.length\">\n <p-table class=\"table\"\n #dt\n [value]=\"accountLastActivities\"\n [paginator]=\"true\"\n [rows]=\"20\"\n [totalRecords]=\"accountLastActivities.length\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Owner' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Account' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Contact' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Action' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.When' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-activities>\n <tr>\n <td data-head=\"Owner\"> {{ activities.owner?.first_name.charAt(0) }}. {{ activities.owner?.last_name }} </td>\n <td data-head=\"Account\">\n <a [routerLink]=\"['/' + subscription?.slug + routers.accountInfo, activities.crm_account_id]\" class=\"name-link\">\n <span [ngbTooltip]=\"activities.crm_account?.name\">{{ activities.crm_account?.name }}</span>\n </a>\n </td>\n <td data-head=\"Contact\">\n <a [routerLink]=\"['/' + subscription?.slug + routers.contactInfo, activities.crm_contact_id]\" class=\"name-link\">\n <span [ngbTooltip]=\"activities.crm_contact ? activities.crm_contact.first_name + ' ' + activities.crm_contact.last_name : ''\">{{ (activities.crm_contact?.first_name + ' ' + activities.crm_contact?.last_name) | textTruncate:20 }}</span>\n </a>\n </td>\n <td data-head=\"Action\">\n <span [ngbTooltip]=\"activities.comment\" [appDynamicBadge]=\"{\n itemsArray: actionNames,\n item: activities.crm_action?.name\n }\"\n color=\"blue-grey\"\n class=\"badge\">{{ activities.crm_action?.name }}</span>\n </td>\n <td data-head=\"When\">{{ activities.when | date:'dd-MMM-YYYY' }}</td>\n </tr>\n </ng-template>\n </p-table>\n <span class=\"total-records-count\" *ngIf=\"accountLastActivities.length !== 0\">{{ 'Label.Total' | transloco }}: {{ accountLastActivities.length }}</span>\n </div>\n <div *ngIf=\"accountLastActivities?.length === 0 && accountLastActivitiesLoaded\">\n <pw-no-data [withImage]=\"true\" [message]=\"'Crm.Summary.NoInsightMessage' | transloco\"> </pw-no-data>\n </div>\n </div>\n\n <!-- Accounts at risk -->\n <div class=\"col-12 col-md-6 mb-3 analytics\">\n <h5 class=\"accordion-heading\">Accounts at Risk</h5>\n <div class=\"w-100 text-center mt-3\">\n <ng-template [ngIf]=\"!accountAtRiskDetailsLoaded\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </ng-template>\n </div>\n <div class=\"primeng-datatable-container table-responsive\"\n *ngIf=\"accountAtRisk?.length\">\n <p-table class=\"table\"\n #dt\n [value]=\"accountAtRisk\"\n [paginator]=\"true\"\n [rows]=\"20\"\n [totalRecords]=\"accountAtRisk.length\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\">{{ 'Crm.Summary.Account' | transloco }}</th>\n <th scope=\"true\" class=\"mrr-header\">{{ 'Crm.AccountMessage.MRR' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Quarter' | transloco }}</th>\n <th scope=\"true\"> {{ 'Crm.AccountMessage.Month' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.SignUpAt' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\"\n let-account\n let-i=\"rowIndex\">\n <!-- Totals row at the top (first row) -->\n <ng-container *ngIf=\"i === 0 && accountAtRisk?.length\">\n <tr class=\"totals-row\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ accountAtRiskTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n <td></td>\n </tr>\n </ng-container>\n <!-- Regular data row -->\n <tr>\n <td data-head=\"Account\">\n <a [routerLink]=\"['/' + subscription?.slug + routers.accountInfo, account.crm_account_id]\" class=\"name-link\">\n <span [ngbTooltip]=\"account.crm_account_name\">{{ account?.crm_account_name | textTruncate:20 }}</span>\n </a>\n </td>\n <td data-head=\"MRR\" class=\"expected-mrr\">\n {{ account.expected_mrr / 100 | currency: (account.main_currency || account.currency) }}\n </td>\n <td data-head=\"Quarter\" [ngClass]=\"{'month-quarter-text fw-bold': account.sessions_last_quarter > 15}\">{{ account.sessions_last_quarter }}</td>\n <td data-head=\"Month\" [ngClass]=\"{'month-quarter-text fw-bold': account.sessions_last_month > 5}\">{{ account.sessions_last_month }}</td>\n <td data-head=\"SignUpAt\">\n {{ account.signed_up_at | dateFormat }}\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n <tr *ngIf=\"accountAtRisk?.length\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ accountAtRiskTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n <td></td>\n </tr>\n </ng-template>\n </p-table>\n <span class=\"total-records-count\" *ngIf=\"accountAtRisk.length !== 0\">{{ 'Label.Total' | transloco }}: {{ accountAtRisk.length }}</span>\n </div>\n <div *ngIf=\"accountAtRisk?.length === 0\">\n <pw-no-data [withImage]=\"true\" [message]=\"'Crm.Summary.NoInsightMessage' | transloco\"> </pw-no-data>\n </div>\n </div>\n\n <!-- Contract renewal -->\n <div class=\"col-12 col-md-6 mb-3 analytics\">\n <h5 class=\"accordion-heading\">Accounts at 1-Year Mark</h5>\n <div class=\"w-100 text-center mt-3\">\n <ng-template [ngIf]=\"!contactRenewalLoaded\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </ng-template>\n </div>\n <div class=\"primeng-datatable-container table-responsive\"\n *ngIf=\"ContractRenewal?.length\">\n <p-table class=\"table\"\n #dt\n [value]=\"ContractRenewal\"\n [paginator]=\"true\"\n [rows]=\"20\"\n [totalRecords]=\"ContractRenewal.length\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Account' | transloco }}</th>\n <th scope=\"true\" class=\"mrr-header\">{{ 'Crm.AccountMessage.MRR' | transloco }}</th>\n\n <th scope=\"true\">{{ 'Crm.AccountMessage.Quarter' | transloco }}</th>\n <th scope=\"true\"> {{ 'Crm.AccountMessage.Month' | transloco }}</th>\n\n <th scope=\"true\">{{ 'Crm.AccountMessage.SignUpAt' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.CCExpAt' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\"\n let-account\n let-i=\"rowIndex\">\n <!-- Totals row at the top (first row) -->\n <ng-container *ngIf=\"i === 0 && ContractRenewal?.length\">\n <tr class=\"totals-row\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ contractRenewalTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n <td></td>\n <td></td>\n </tr>\n </ng-container>\n <!-- Regular data row -->\n <tr>\n <td data-head=\"Account\">\n <a [routerLink]=\"['/' + subscription?.slug + routers.accountInfo, account.crm_account_id]\" class=\"name-link\">\n <span [ngbTooltip]=\"account.crm_account_name\">{{ account.crm_account_name | textTruncate:20 }}</span>\n </a>\n </td>\n <td data-head=\"MRR\" class=\"expected-mrr\">\n {{ account.expected_mrr / 100 | currency: (account.main_currency || account.currency) }}\n </td>\n <td data-head=\"Quarter\" [ngClass]=\"{'month-quarter-text fw-bold': account.sessions_last_quarter > 15}\">{{ account.sessions_last_quarter }}</td>\n <td data-head=\"Month\" [ngClass]=\"{'month-quarter-text fw-bold': account.sessions_last_month > 5}\">{{ account.sessions_last_month }}</td>\n <td data-head=\"SignUpAt\">\n {{ account.signed_up_at | dateFormat }}\n </td>\n <td data-head=\"ExpAt\" [ngClass]=\"{'text-danger': account.cc_expiring_at | isPastDate}\">\n {{ account.cc_expiring_at | dateFormat }}\n <span *ngIf=\"account.cc_expiring_at | isPastDate\" class=\"tooltip-wrap\" [appendTo]=\"'body'\" [pTooltip]=\"'Admin.Insight.Tooltip.ExpAtMessage' | transloco\" tooltipPosition=\"top\">\n <i class=\"fas fa-info-circle ml-1\"></i>\n </span>\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n <tr *ngIf=\"ContractRenewal?.length\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ contractRenewalTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n <td></td>\n <td></td>\n </tr>\n </ng-template>\n </p-table>\n <span class=\"total-records-count\" *ngIf=\"ContractRenewal.length !== 0\">{{ 'Label.Total' | transloco }}: {{ ContractRenewal.length }}</span>\n </div>\n <div *ngIf=\"ContractRenewal?.length === 0\">\n <pw-no-data [withImage]=\"true\" [message]=\"'Crm.Summary.NoInsightMessage' | transloco\"> </pw-no-data>\n </div>\n </div>\n\n <!-- Credit Cards Expiring -->\n <div class=\"col-12 col-md-6 mb-3 analytics\">\n <h5 class=\"accordion-heading\">Accounts with Expiring Credit Cards</h5>\n <div class=\"w-100 text-center mt-3\">\n <ng-template [ngIf]=\"!creditCardExpiringDetailsLoaded\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </ng-template>\n </div>\n <div class=\"primeng-datatable-container table-responsive\"\n *ngIf=\"creditCardExpiring?.length\">\n <p-table class=\"table\"\n #dt\n [value]=\"creditCardExpiring\"\n [paginator]=\"true\"\n [rows]=\"20\"\n [totalRecords]=\"creditCardExpiring.length\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Account' | transloco }}</th>\n <th scope=\"true\" class=\"mrr-header\">{{ 'Crm.AccountMessage.MRR' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.SignUpAt' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.CCExpAt' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\"\n let-account\n let-i=\"rowIndex\">\n <!-- Totals row at the top (first row) -->\n <ng-container *ngIf=\"i === 0 && creditCardExpiring?.length\">\n <tr class=\"totals-row\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ creditCardExpiringTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n </tr>\n </ng-container>\n <!-- Regular data row -->\n <tr>\n <td data-head=\"Account\">\n <a [routerLink]=\"['/' + subscription?.slug + routers.accountInfo, account.crm_account_id]\" class=\"name-link\">\n <span [ngbTooltip]=\"account.crm_account_name\">{{ account.crm_account_name | textTruncate:20 }}</span>\n </a>\n </td>\n <td data-head=\"MRR\" class=\"expected-mrr\">\n {{ account.expected_mrr / 100 | currency: account.currency }}\n </td>\n <td data-head=\"SignUpAt\">\n {{ account.signed_up_at | dateFormat }}\n </td>\n <td data-head=\"ExpAt\" [ngClass]=\"{'text-danger': account.cc_expiring_at | isPastDate}\">\n {{ account.cc_expiring_at | dateFormat }}\n <span *ngIf=\"account.cc_expiring_at | isPastDate\" class=\"tooltip-wrap\" [appendTo]=\"'body'\" [pTooltip]=\"'Admin.Insight.Tooltip.ExpAtMessage' | transloco\" tooltipPosition=\"top\">\n <i class=\"fas fa-info-circle ml-1\"></i>\n </span>\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n <tr *ngIf=\"creditCardExpiring?.length\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ creditCardExpiringTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n </tr>\n </ng-template>\n </p-table>\n <span class=\"total-records-count\" *ngIf=\"creditCardExpiring.length !== 0\">{{ 'Label.Total' | transloco }}: {{ creditCardExpiring.length }}</span>\n </div>\n <div *ngIf=\"creditCardExpiring?.length === 0\">\n <pw-no-data [withImage]=\"true\" [message]=\"'Crm.Summary.NoInsightMessage' | transloco\"> </pw-no-data>\n </div>\n </div>\n\n <!-- Magic Moment -->\n <div class=\"col-12 col-md-6 mb-3 analytics\">\n <h5 class=\"accordion-heading\">Accounts with Magic Moment</h5>\n <div class=\"w-100 text-center mt-3\">\n <ng-template [ngIf]=\"!magicMomentLoaded\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </ng-template>\n </div>\n <div class=\"primeng-datatable-container table-responsive\"\n *ngIf=\"magicMoment?.length\">\n <p-table class=\"table\"\n #dt\n [value]=\"magicMoment\"\n [paginator]=\"true\"\n [rows]=\"20\"\n [totalRecords]=\"magicMoment.length\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\">{{ 'Crm.Summary.Account' | transloco }}</th>\n <th scope=\"true\" class=\"mrr-header\">{{ 'Crm.AccountMessage.MRR' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Quarter' | transloco }}</th>\n <th scope=\"true\"> {{ 'Crm.AccountMessage.Month' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.SignUpAt' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\"\n let-account\n let-i=\"rowIndex\">\n <!-- Totals row at the top (first row) -->\n <ng-container *ngIf=\"i === 0 && magicMoment?.length\">\n <tr class=\"totals-row\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ magicMomentTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n <td></td>\n </tr>\n </ng-container>\n <!-- Regular data row -->\n <tr>\n <td data-head=\"Account\">\n <a [routerLink]=\"['/' + subscription?.slug + routers.accountInfo, account.crm_account_id]\" class=\"name-link\">\n <span [ngbTooltip]=\"account.crm_account_name\">{{ account?.crm_account_name | textTruncate:20 }}</span>\n </a>\n </td>\n <td data-head=\"MRR\" class=\"expected-mrr\">\n {{ account.expected_mrr / 100 | currency: account.currency }}\n </td>\n <td data-head=\"Quarter\" [ngClass]=\"{'month-quarter-text fw-bold': account.sessions_last_quarter > 15}\">{{ account.sessions_last_quarter }}</td>\n <td data-head=\"Month\" [ngClass]=\"{'month-quarter-text fw-bold': account.sessions_last_month > 5}\">{{ account.sessions_last_month }}</td>\n <td data-head=\"SignUpAt\">\n {{ account.signed_up_at | dateFormat }}\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n <tr *ngIf=\"magicMoment?.length\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ magicMomentTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n <td></td>\n </tr>\n </ng-template>\n </p-table>\n <span class=\"total-records-count\" *ngIf=\"magicMoment.length !==0 \">{{ 'Label.Total' | transloco }}: {{ magicMoment.length }}</span>\n </div>\n <div *ngIf=\"magicMoment?.length === 0\">\n <pw-no-data [withImage]=\"true\" [message]=\"'Crm.Summary.NoInsightMessage' | transloco\"> </pw-no-data>\n </div>\n </div>\n\n <!-- Accounts Geography -->\n <div class=\"col-12 col-md-6 mb-3 analytics\">\n <h5 class=\"accordion-heading\">Accounts Location</h5>\n <div class=\"w-100 text-center mt-3\">\n <ng-template [ngIf]=\"!accountGeographyLoaded\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </ng-template>\n </div>\n <div>\n <ng-template [ngIf]=\"accountGeographyLoaded && accountGeography?.data?.length\">\n <plotly-plot [data]=\"accountGeography?.data\"\n [layout]=\"accountGeography?.layout\" [useResizeHandler]=\"accountGeographyLoaded ? true : false\" [config]=\"accountGeography?.config\"\n >\n </plotly-plot>\n </ng-template>\n </div>\n <div *ngIf=\"accountGeographyLoaded && !accountGeography?.data?.length\">\n <pw-no-data [withImage]=\"true\" [message]=\"'Crm.ContactMessage.NoInsightMessage' | transloco\">\n </pw-no-data>\n </div>\n </div>\n </ng-container>\n</div>\n", dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "directive", type: i4.DynamicBadgeDirective, selector: "[appDynamicBadge]", inputs: ["appDynamicBadge", "color", "colorByName", "dataName"] }, { kind: "component", type: i5.PlotlyComponent, selector: "plotly-plot", inputs: ["data", "layout", "config", "frames", "style", "theme", "divId", "revision", "className", "debug", "useResizeHandler", "updateOnLayoutChange", "updateOnDataChange", "updateOnlyWithRevision"], outputs: ["initialized", "update", "purge", "error", "afterExport", "afterPlot", "animated", "animatingFrame", "animationInterrupted", "autoSize", "beforeExport", "beforeHover", "buttonClicked", "click", "plotlyClick", "clickAnnotation", "deselect", "doubleClick", "framework", "hover", "legendClick", "legendDoubleClick", "react", "relayout", "relayouting", "restyle", "redraw", "selected", "selecting", "sliderChange", "sliderEnd", "sliderStart", "sunburstclick", "transitioning", "transitionInterrupted", "unhover", "treemapclick", "webglcontextlost"] }, { kind: "directive", type: i6.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: i7.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "style", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "scrollDirection", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "responsive", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "autoLayout", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll", "virtualRowHeight"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i8.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i9.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "component", type: i10.ProgressSpinner, selector: "p-progressSpinner", inputs: ["styleClass", "style", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "component", type: i11.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }, { kind: "pipe", type: i2.PercentPipe, name: "percent" }, { kind: "pipe", type: i2.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i2.DatePipe, name: "date" }, { kind: "pipe", type: i12.DateFormatPipe, name: "dateFormat" }, { kind: "pipe", type: i12.TextTruncatePipe, name: "textTruncate" }, { kind: "pipe", type: i12.IsPastDatePipe, name: "isPastDate" }, { kind: "pipe", type: i13.TranslocoPipe, name: "transloco" }] }); }
309
- }
310
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: SmartCrmAccountInsightComponent, decorators: [{
311
- type: Component,
312
- args: [{ selector: 'pw-smart-crm-account-insight', template: "<div class=\"row\">\n <ng-container class=\"mt-5\">\n\n <!-- Signed up last 90 days -->\n <div class=\"col-12 col-md-6 mb-3 analytics\">\n <h5 class=\"accordion-heading\">Signed up Last 90 Days</h5>\n <div class=\"w-100 text-center mt-3\">\n <ng-template [ngIf]=\"!signUpLastNinetyDaysLoaded\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </ng-template>\n </div>\n <div class=\"primeng-datatable-container table-responsive\"\n *ngIf=\"signedUpLastThirtyDays?.length\">\n <p-table class=\"table\"\n #dt\n [value]=\"signedUpLastThirtyDays\"\n [paginator]=\"true\"\n [rows]=\"20\"\n [totalRecords]=\"signedUpLastThirtyDays.length\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\">{{ 'Crm.Summary.Account' | transloco }}</th>\n <th scope=\"true\" class=\"mrr-header\">{{ 'Crm.AccountMessage.MRR' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.SignUpAt' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\"\n let-signUp\n let-i=\"rowIndex\">\n <!-- Totals row at the top (first row) -->\n <ng-container *ngIf=\"i === 0 && signedUpLastThirtyDays?.length\">\n <tr class=\"totals-row\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ signedUpLastNinetyDaysTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n </tr>\n </ng-container>\n <!-- Regular data row -->\n <tr>\n <td data-head=\"Account\">\n <a [routerLink]=\"['/' + subscription?.slug + routers.accountInfo, signUp.crm_account_id]\" class=\"name-link\">\n <span [ngbTooltip]=\"signUp.crm_account_name\">{{ signUp?.crm_account_name | textTruncate:20 }}</span>\n </a>\n </td>\n <td data-head=\"MRR\" class=\"expected-mrr\">\n {{ signUp.expected_mrr / 100 | currency: (signUp.currency || signUp.main_currency) }}\n </td>\n <td data-head=\"SignUpAt\">\n {{ signUp.signed_up_at | dateFormat }}\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n <tr *ngIf=\"signedUpLastThirtyDays?.length\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ signedUpLastNinetyDaysTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n </tr>\n </ng-template>\n </p-table>\n <span class=\"total-records-count\" *ngIf=\"signedUpLastThirtyDays.length!== 0\">{{ 'Label.Total' | transloco }}: {{ signedUpLastThirtyDays.length }}</span>\n </div>\n <div *ngIf=\"signedUpLastThirtyDays?.length === 0\">\n <pw-no-data [withImage]=\"true\" [message]=\"'Crm.Summary.NoInsightMessage' | transloco\"> </pw-no-data>\n </div>\n </div>\n\n <!-- Churned Last 90 days -->\n <div class=\"col-12 col-md-6 mb-3 analytics\">\n <h5 class=\"accordion-heading\">Churned Last 90 Days</h5>\n <div class=\"w-100 text-center mt-3\">\n <ng-template [ngIf]=\"!churnedAccountLoaded\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </ng-template>\n </div>\n <div class=\"primeng-datatable-container table-responsive\" *ngIf=\"churnedAccounts?.length\">\n <p-table class=\"table\" #dt [value]=\"churnedAccounts\" [paginator]=\"true\" [rows]=\"20\"\n [totalRecords]=\"churnedAccounts.length\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Account' | transloco }}</th>\n <th scope=\"true\" class=\"mrr-header\">{{ 'Crm.AccountMessage.MRR' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Quarter' | transloco }}</th>\n <th scope=\"true\"> {{ 'Crm.AccountMessage.Month' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.SignUpAt' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.UnsubscribedAt' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-account let-i=\"rowIndex\">\n <!-- Totals row at the top (first row) -->\n <ng-container *ngIf=\"i === 0 && churnedAccounts?.length\">\n <tr class=\"totals-row\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ churnedAccountsTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n <td></td>\n <td></td>\n </tr>\n </ng-container>\n <!-- Regular data row -->\n <tr>\n <td data-head=\"Account\">\n <a [routerLink]=\"['/' + subscription?.slug + routers.accountInfo, account.crm_account_id]\"\n class=\"name-link\">\n <span [ngbTooltip]=\"account.crm_account_name\">{{ account.crm_account_name | textTruncate:20 }}</span>\n </a>\n </td>\n <td data-head=\"MRR\" class=\"expected-mrr\"> {{ account.expected_mrr / 100 | currency: ( account.main_currency || account.currency) }} </td>\n <td data-head=\"Quarter\" [ngClass]=\"{'month-quarter-text fw-bold': account.sessions_last_quarter > 15}\">{{ account.sessions_last_quarter }}</td>\n <td data-head=\"Month\" [ngClass]=\"{'month-quarter-text fw-bold': account.sessions_last_month > 5}\">{{ account.sessions_last_month }}</td>\n <td data-head=\"SignUpAt\"> {{ account.signed_up_at | dateFormat }} </td>\n <td data-head=\"UnsubscribedAt\" [ngClass]=\"{'text-danger': account.unsubscribed_at | isPastDate}\">\n {{ account.unsubscribed_at | dateFormat }}\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n <tr *ngIf=\"churnedAccounts?.length\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ churnedAccountsTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n <td></td>\n <td></td>\n </tr>\n </ng-template>\n </p-table>\n <span class=\"total-records-count\" *ngIf=\"churnedAccounts?.length !== 0\">{{ 'Label.Total' | transloco }}: {{\n churnedAccounts.length }}</span>\n </div>\n <div *ngIf=\"churnedAccounts?.length === 0 && churnedAccountLoaded\">\n <pw-no-data [withImage]=\"true\" [message]=\"'Crm.Summary.NoInsightMessage' | transloco\"> </pw-no-data>\n </div>\n </div>\n\n <!-- Active Opportunities -->\n <div class=\"col-12 col-md-6 mb-3 analytics\">\n <h5 class=\"accordion-heading\">Active Opportunities</h5>\n <div class=\"w-100 text-center mt-3\">\n <ng-template [ngIf]=\"!activeOpportunitiesLoaded\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </ng-template>\n </div>\n <div class=\"primeng-datatable-container table-responsive\"\n *ngIf=\"activeOpportunities?.length\">\n <p-table class=\"table\"\n #dt\n [value]=\"activeOpportunities\"\n [paginator]=\"true\"\n [rows]=\"20\"\n\n [totalRecords]=\"activeOpportunities.length\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\">{{ 'Crm.Summary.Account' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.Summary.Title' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.Summary.OneTimeAmount' | transloco }}</th>\n <th scope=\"true\" class=\"mrr-header\">{{ 'Crm.AccountMessage.MRR' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.Summary.WinChance' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\"\n let-opportunities\n let-i=\"rowIndex\">\n <!-- Totals row at the top (first row) -->\n <ng-container *ngIf=\"i === 0 && activeOpportunities?.length\">\n <tr class=\"totals-row\">\n <td></td>\n <td></td>\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ activeOpportunitiesTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n </tr>\n </ng-container>\n <!-- Regular data row -->\n <tr>\n <td data-head=\"Account\">\n <a [routerLink]=\"['/' + subscription?.slug + routers.accountInfo, opportunities.crm_account?.id]\" class=\"name-link\">\n <span [ngbTooltip]=\"opportunities.crm_account?.name\">{{ opportunities.crm_account?.name | textTruncate:20 }}</span>\n </a>\n </td>\n <td data-head=\"Title\">\n <a [ngbTooltip]=\"opportunities?.title\" *ngIf=\"\n hasAccess ||\n opportunities?.owner_id === userId ||\n checkPermission('Pages.Product.CRM.Role.Admin')\n \" [routerLink]=\"[\n '/' + subscription?.slug + routers.opportunityInfo,\n opportunities.id\n ]\">\n <span>{{ opportunities?.title | textTruncate: 20 }} </span>\n </a>\n </td>\n <td data-head=\"One Time Amount\"> {{ opportunities.one_time_amount / 100 | currency: (opportunities.main_currency || opportunities.currency) }} </td>\n <td data-head=\"Monthly Amount\" class=\"expected-mrr\"> {{ opportunities.monthly_amount / 100 | currency: (opportunities.main_currency || opportunities.currency) }} </td>\n <td data-head=\"Win Chance\"> {{ opportunities.win_chances / 100 | percent }} <span class=\"text-danger\"\n *ngIf=\"opportunities.cancelled\">!Cancelled!</span>\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n <tr *ngIf=\"activeOpportunities?.length\">\n <td></td>\n <td></td>\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ activeOpportunitiesTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n </tr>\n </ng-template>\n </p-table>\n <span class=\"total-records-count\" *ngIf=\"activeOpportunities.length !== 0\">{{ 'Label.Total' | transloco }}: {{ activeOpportunities.length }}</span>\n </div>\n <div *ngIf=\"activeOpportunities?.length === 0\">\n <pw-no-data [withImage]=\"true\" [message]=\"'Crm.Summary.NoInsightMessage' | transloco\"> </pw-no-data>\n </div>\n </div>\n\n <!-- Last Activities -->\n <div class=\"col-12 col-md-6 mb-3 analytics\">\n <h5 class=\"accordion-heading\">Latest Activities</h5>\n <div class=\"w-100 text-center mt-3\">\n <ng-template [ngIf]=\"!accountLastActivitiesLoaded\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </ng-template>\n </div>\n <div class=\"primeng-datatable-container table-responsive\"\n *ngIf=\"accountLastActivities?.length\">\n <p-table class=\"table\"\n #dt\n [value]=\"accountLastActivities\"\n [paginator]=\"true\"\n [rows]=\"20\"\n [totalRecords]=\"accountLastActivities.length\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Owner' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Account' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Contact' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Action' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.When' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\" let-activities>\n <tr>\n <td data-head=\"Owner\"> {{ activities.owner?.first_name.charAt(0) }}. {{ activities.owner?.last_name }} </td>\n <td data-head=\"Account\">\n <a [routerLink]=\"['/' + subscription?.slug + routers.accountInfo, activities.crm_account_id]\" class=\"name-link\">\n <span [ngbTooltip]=\"activities.crm_account?.name\">{{ activities.crm_account?.name }}</span>\n </a>\n </td>\n <td data-head=\"Contact\">\n <a [routerLink]=\"['/' + subscription?.slug + routers.contactInfo, activities.crm_contact_id]\" class=\"name-link\">\n <span [ngbTooltip]=\"activities.crm_contact ? activities.crm_contact.first_name + ' ' + activities.crm_contact.last_name : ''\">{{ (activities.crm_contact?.first_name + ' ' + activities.crm_contact?.last_name) | textTruncate:20 }}</span>\n </a>\n </td>\n <td data-head=\"Action\">\n <span [ngbTooltip]=\"activities.comment\" [appDynamicBadge]=\"{\n itemsArray: actionNames,\n item: activities.crm_action?.name\n }\"\n color=\"blue-grey\"\n class=\"badge\">{{ activities.crm_action?.name }}</span>\n </td>\n <td data-head=\"When\">{{ activities.when | date:'dd-MMM-YYYY' }}</td>\n </tr>\n </ng-template>\n </p-table>\n <span class=\"total-records-count\" *ngIf=\"accountLastActivities.length !== 0\">{{ 'Label.Total' | transloco }}: {{ accountLastActivities.length }}</span>\n </div>\n <div *ngIf=\"accountLastActivities?.length === 0 && accountLastActivitiesLoaded\">\n <pw-no-data [withImage]=\"true\" [message]=\"'Crm.Summary.NoInsightMessage' | transloco\"> </pw-no-data>\n </div>\n </div>\n\n <!-- Accounts at risk -->\n <div class=\"col-12 col-md-6 mb-3 analytics\">\n <h5 class=\"accordion-heading\">Accounts at Risk</h5>\n <div class=\"w-100 text-center mt-3\">\n <ng-template [ngIf]=\"!accountAtRiskDetailsLoaded\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </ng-template>\n </div>\n <div class=\"primeng-datatable-container table-responsive\"\n *ngIf=\"accountAtRisk?.length\">\n <p-table class=\"table\"\n #dt\n [value]=\"accountAtRisk\"\n [paginator]=\"true\"\n [rows]=\"20\"\n [totalRecords]=\"accountAtRisk.length\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\">{{ 'Crm.Summary.Account' | transloco }}</th>\n <th scope=\"true\" class=\"mrr-header\">{{ 'Crm.AccountMessage.MRR' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Quarter' | transloco }}</th>\n <th scope=\"true\"> {{ 'Crm.AccountMessage.Month' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.SignUpAt' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\"\n let-account\n let-i=\"rowIndex\">\n <!-- Totals row at the top (first row) -->\n <ng-container *ngIf=\"i === 0 && accountAtRisk?.length\">\n <tr class=\"totals-row\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ accountAtRiskTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n <td></td>\n </tr>\n </ng-container>\n <!-- Regular data row -->\n <tr>\n <td data-head=\"Account\">\n <a [routerLink]=\"['/' + subscription?.slug + routers.accountInfo, account.crm_account_id]\" class=\"name-link\">\n <span [ngbTooltip]=\"account.crm_account_name\">{{ account?.crm_account_name | textTruncate:20 }}</span>\n </a>\n </td>\n <td data-head=\"MRR\" class=\"expected-mrr\">\n {{ account.expected_mrr / 100 | currency: (account.main_currency || account.currency) }}\n </td>\n <td data-head=\"Quarter\" [ngClass]=\"{'month-quarter-text fw-bold': account.sessions_last_quarter > 15}\">{{ account.sessions_last_quarter }}</td>\n <td data-head=\"Month\" [ngClass]=\"{'month-quarter-text fw-bold': account.sessions_last_month > 5}\">{{ account.sessions_last_month }}</td>\n <td data-head=\"SignUpAt\">\n {{ account.signed_up_at | dateFormat }}\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n <tr *ngIf=\"accountAtRisk?.length\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ accountAtRiskTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n <td></td>\n </tr>\n </ng-template>\n </p-table>\n <span class=\"total-records-count\" *ngIf=\"accountAtRisk.length !== 0\">{{ 'Label.Total' | transloco }}: {{ accountAtRisk.length }}</span>\n </div>\n <div *ngIf=\"accountAtRisk?.length === 0\">\n <pw-no-data [withImage]=\"true\" [message]=\"'Crm.Summary.NoInsightMessage' | transloco\"> </pw-no-data>\n </div>\n </div>\n\n <!-- Contract renewal -->\n <div class=\"col-12 col-md-6 mb-3 analytics\">\n <h5 class=\"accordion-heading\">Accounts at 1-Year Mark</h5>\n <div class=\"w-100 text-center mt-3\">\n <ng-template [ngIf]=\"!contactRenewalLoaded\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </ng-template>\n </div>\n <div class=\"primeng-datatable-container table-responsive\"\n *ngIf=\"ContractRenewal?.length\">\n <p-table class=\"table\"\n #dt\n [value]=\"ContractRenewal\"\n [paginator]=\"true\"\n [rows]=\"20\"\n [totalRecords]=\"ContractRenewal.length\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Account' | transloco }}</th>\n <th scope=\"true\" class=\"mrr-header\">{{ 'Crm.AccountMessage.MRR' | transloco }}</th>\n\n <th scope=\"true\">{{ 'Crm.AccountMessage.Quarter' | transloco }}</th>\n <th scope=\"true\"> {{ 'Crm.AccountMessage.Month' | transloco }}</th>\n\n <th scope=\"true\">{{ 'Crm.AccountMessage.SignUpAt' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.CCExpAt' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\"\n let-account\n let-i=\"rowIndex\">\n <!-- Totals row at the top (first row) -->\n <ng-container *ngIf=\"i === 0 && ContractRenewal?.length\">\n <tr class=\"totals-row\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ contractRenewalTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n <td></td>\n <td></td>\n </tr>\n </ng-container>\n <!-- Regular data row -->\n <tr>\n <td data-head=\"Account\">\n <a [routerLink]=\"['/' + subscription?.slug + routers.accountInfo, account.crm_account_id]\" class=\"name-link\">\n <span [ngbTooltip]=\"account.crm_account_name\">{{ account.crm_account_name | textTruncate:20 }}</span>\n </a>\n </td>\n <td data-head=\"MRR\" class=\"expected-mrr\">\n {{ account.expected_mrr / 100 | currency: (account.main_currency || account.currency) }}\n </td>\n <td data-head=\"Quarter\" [ngClass]=\"{'month-quarter-text fw-bold': account.sessions_last_quarter > 15}\">{{ account.sessions_last_quarter }}</td>\n <td data-head=\"Month\" [ngClass]=\"{'month-quarter-text fw-bold': account.sessions_last_month > 5}\">{{ account.sessions_last_month }}</td>\n <td data-head=\"SignUpAt\">\n {{ account.signed_up_at | dateFormat }}\n </td>\n <td data-head=\"ExpAt\" [ngClass]=\"{'text-danger': account.cc_expiring_at | isPastDate}\">\n {{ account.cc_expiring_at | dateFormat }}\n <span *ngIf=\"account.cc_expiring_at | isPastDate\" class=\"tooltip-wrap\" [appendTo]=\"'body'\" [pTooltip]=\"'Admin.Insight.Tooltip.ExpAtMessage' | transloco\" tooltipPosition=\"top\">\n <i class=\"fas fa-info-circle ml-1\"></i>\n </span>\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n <tr *ngIf=\"ContractRenewal?.length\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ contractRenewalTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n <td></td>\n <td></td>\n </tr>\n </ng-template>\n </p-table>\n <span class=\"total-records-count\" *ngIf=\"ContractRenewal.length !== 0\">{{ 'Label.Total' | transloco }}: {{ ContractRenewal.length }}</span>\n </div>\n <div *ngIf=\"ContractRenewal?.length === 0\">\n <pw-no-data [withImage]=\"true\" [message]=\"'Crm.Summary.NoInsightMessage' | transloco\"> </pw-no-data>\n </div>\n </div>\n\n <!-- Credit Cards Expiring -->\n <div class=\"col-12 col-md-6 mb-3 analytics\">\n <h5 class=\"accordion-heading\">Accounts with Expiring Credit Cards</h5>\n <div class=\"w-100 text-center mt-3\">\n <ng-template [ngIf]=\"!creditCardExpiringDetailsLoaded\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </ng-template>\n </div>\n <div class=\"primeng-datatable-container table-responsive\"\n *ngIf=\"creditCardExpiring?.length\">\n <p-table class=\"table\"\n #dt\n [value]=\"creditCardExpiring\"\n [paginator]=\"true\"\n [rows]=\"20\"\n [totalRecords]=\"creditCardExpiring.length\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Account' | transloco }}</th>\n <th scope=\"true\" class=\"mrr-header\">{{ 'Crm.AccountMessage.MRR' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.SignUpAt' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.CCExpAt' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\"\n let-account\n let-i=\"rowIndex\">\n <!-- Totals row at the top (first row) -->\n <ng-container *ngIf=\"i === 0 && creditCardExpiring?.length\">\n <tr class=\"totals-row\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ creditCardExpiringTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n </tr>\n </ng-container>\n <!-- Regular data row -->\n <tr>\n <td data-head=\"Account\">\n <a [routerLink]=\"['/' + subscription?.slug + routers.accountInfo, account.crm_account_id]\" class=\"name-link\">\n <span [ngbTooltip]=\"account.crm_account_name\">{{ account.crm_account_name | textTruncate:20 }}</span>\n </a>\n </td>\n <td data-head=\"MRR\" class=\"expected-mrr\">\n {{ account.expected_mrr / 100 | currency: account.currency }}\n </td>\n <td data-head=\"SignUpAt\">\n {{ account.signed_up_at | dateFormat }}\n </td>\n <td data-head=\"ExpAt\" [ngClass]=\"{'text-danger': account.cc_expiring_at | isPastDate}\">\n {{ account.cc_expiring_at | dateFormat }}\n <span *ngIf=\"account.cc_expiring_at | isPastDate\" class=\"tooltip-wrap\" [appendTo]=\"'body'\" [pTooltip]=\"'Admin.Insight.Tooltip.ExpAtMessage' | transloco\" tooltipPosition=\"top\">\n <i class=\"fas fa-info-circle ml-1\"></i>\n </span>\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n <tr *ngIf=\"creditCardExpiring?.length\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ creditCardExpiringTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n </tr>\n </ng-template>\n </p-table>\n <span class=\"total-records-count\" *ngIf=\"creditCardExpiring.length !== 0\">{{ 'Label.Total' | transloco }}: {{ creditCardExpiring.length }}</span>\n </div>\n <div *ngIf=\"creditCardExpiring?.length === 0\">\n <pw-no-data [withImage]=\"true\" [message]=\"'Crm.Summary.NoInsightMessage' | transloco\"> </pw-no-data>\n </div>\n </div>\n\n <!-- Magic Moment -->\n <div class=\"col-12 col-md-6 mb-3 analytics\">\n <h5 class=\"accordion-heading\">Accounts with Magic Moment</h5>\n <div class=\"w-100 text-center mt-3\">\n <ng-template [ngIf]=\"!magicMomentLoaded\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </ng-template>\n </div>\n <div class=\"primeng-datatable-container table-responsive\"\n *ngIf=\"magicMoment?.length\">\n <p-table class=\"table\"\n #dt\n [value]=\"magicMoment\"\n [paginator]=\"true\"\n [rows]=\"20\"\n [totalRecords]=\"magicMoment.length\">\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"true\">{{ 'Crm.Summary.Account' | transloco }}</th>\n <th scope=\"true\" class=\"mrr-header\">{{ 'Crm.AccountMessage.MRR' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.Quarter' | transloco }}</th>\n <th scope=\"true\"> {{ 'Crm.AccountMessage.Month' | transloco }}</th>\n <th scope=\"true\">{{ 'Crm.AccountMessage.SignUpAt' | transloco }}</th>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"body\"\n let-account\n let-i=\"rowIndex\">\n <!-- Totals row at the top (first row) -->\n <ng-container *ngIf=\"i === 0 && magicMoment?.length\">\n <tr class=\"totals-row\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ magicMomentTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n <td></td>\n </tr>\n </ng-container>\n <!-- Regular data row -->\n <tr>\n <td data-head=\"Account\">\n <a [routerLink]=\"['/' + subscription?.slug + routers.accountInfo, account.crm_account_id]\" class=\"name-link\">\n <span [ngbTooltip]=\"account.crm_account_name\">{{ account?.crm_account_name | textTruncate:20 }}</span>\n </a>\n </td>\n <td data-head=\"MRR\" class=\"expected-mrr\">\n {{ account.expected_mrr / 100 | currency: account.currency }}\n </td>\n <td data-head=\"Quarter\" [ngClass]=\"{'month-quarter-text fw-bold': account.sessions_last_quarter > 15}\">{{ account.sessions_last_quarter }}</td>\n <td data-head=\"Month\" [ngClass]=\"{'month-quarter-text fw-bold': account.sessions_last_month > 5}\">{{ account.sessions_last_month }}</td>\n <td data-head=\"SignUpAt\">\n {{ account.signed_up_at | dateFormat }}\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"footer\">\n <tr *ngIf=\"magicMoment?.length\">\n <td></td>\n <td class=\"fw-bold expected-mrr\">\n <strong>{{ magicMomentTotal?.total_mrr / 100 | currency: 'USD' }}</strong>\n </td>\n <td></td>\n <td></td>\n <td></td>\n </tr>\n </ng-template>\n </p-table>\n <span class=\"total-records-count\" *ngIf=\"magicMoment.length !==0 \">{{ 'Label.Total' | transloco }}: {{ magicMoment.length }}</span>\n </div>\n <div *ngIf=\"magicMoment?.length === 0\">\n <pw-no-data [withImage]=\"true\" [message]=\"'Crm.Summary.NoInsightMessage' | transloco\"> </pw-no-data>\n </div>\n </div>\n\n <!-- Accounts Geography -->\n <div class=\"col-12 col-md-6 mb-3 analytics\">\n <h5 class=\"accordion-heading\">Accounts Location</h5>\n <div class=\"w-100 text-center mt-3\">\n <ng-template [ngIf]=\"!accountGeographyLoaded\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </ng-template>\n </div>\n <div>\n <ng-template [ngIf]=\"accountGeographyLoaded && accountGeography?.data?.length\">\n <plotly-plot [data]=\"accountGeography?.data\"\n [layout]=\"accountGeography?.layout\" [useResizeHandler]=\"accountGeographyLoaded ? true : false\" [config]=\"accountGeography?.config\"\n >\n </plotly-plot>\n </ng-template>\n </div>\n <div *ngIf=\"accountGeographyLoaded && !accountGeography?.data?.length\">\n <pw-no-data [withImage]=\"true\" [message]=\"'Crm.ContactMessage.NoInsightMessage' | transloco\">\n </pw-no-data>\n </div>\n </div>\n </ng-container>\n</div>\n" }]
313
- }], ctorParameters: () => [{ type: i1.CrmService }, { type: i0.Injector }] });
314
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnQtY3JtLWFjY291bnQtaW5zaWdodC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9saWJzL3NtYXJ0LWNybS9zcmMvbGliL3ByaXZhdGUvY29tcG9uZW50cy9zbWFydC1jcm0taW5zaWdodC9zbWFydC1jcm0tYWNjb3VudC1pbnNpZ2h0L3NtYXJ0LWNybS1hY2NvdW50LWluc2lnaHQuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vbGlicy9zbWFydC1jcm0vc3JjL2xpYi9wcml2YXRlL2NvbXBvbmVudHMvc21hcnQtY3JtLWluc2lnaHQvc21hcnQtY3JtLWFjY291bnQtaW5zaWdodC9zbWFydC1jcm0tYWNjb3VudC1pbnNpZ2h0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUFxQixNQUFNLGVBQWUsQ0FBQztBQUV2RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQU9oRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFeEQsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLG9DQUFvQyxDQUFDOzs7Ozs7Ozs7Ozs7Ozs7QUFNN0QsTUFBTSxPQUFPLCtCQUFnQyxTQUFRLGdCQUFnQjtJQXlDakUsWUFDcUIsVUFBc0IsRUFDdkMsUUFBa0I7UUFFbEIsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBSEMsZUFBVSxHQUFWLFVBQVUsQ0FBWTtRQXpCM0MsK0JBQTBCLEdBQUcsS0FBSyxDQUFDO1FBQ25DLGdDQUEyQixHQUFHLEtBQUssQ0FBQztRQUNwQyx5QkFBb0IsR0FBRyxLQUFLLENBQUM7UUFDN0IsOEJBQXlCLEdBQUcsS0FBSyxDQUFDO1FBQ2xDLCtCQUEwQixHQUFHLEtBQUssQ0FBQztRQUNuQyx5QkFBb0IsR0FBRyxL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QUNJLDhCQUE4QiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5qZWN0b3IsIE9uRGVzdHJveSwgT25Jbml0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbmltcG9ydCB7IEFwcEJhc2VDb21wb25lbnQgfSBmcm9tICdAcG9zaXdpc2UvYXBwLWJhc2UtY29tcG9uZW50JztcbmltcG9ydCB7XG4gICAgYWN0aXZlT3Bwb3J0dW5pdGllcyxcbiAgICBzaWduZWRVcExhc3RUaGlydHlEYXlzLFxuICAgIFN1YnNjcmlwdGlvbixcbiAgICBVc2VyXG59IGZyb20gJ0Bwb3Npd2lzZS9jb21tb24tdXRpbGl0aWVzJztcbmltcG9ydCB7IENybVNlcnZpY2UgfSBmcm9tICdAcG9zaXdpc2Uvc21hcnQtY3JtLXNoYXJlZCc7XG5cbmltcG9ydCB7IFJPVVRFUlMgfSBmcm9tICcuLi8uLi8uLi8uLi9zaGFyZWQvcm91dGVycy9yb3V0ZXJzJztcblxuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6ICdwdy1zbWFydC1jcm0tYWNjb3VudC1pbnNpZ2h0JyxcbiAgICB0ZW1wbGF0ZVVybDogJy4vc21hcnQtY3JtLWFjY291bnQtaW5zaWdodC5jb21wb25lbnQuaHRtbCdcbn0pXG5leHBvcnQgY2xhc3MgU21hcnRDcm1BY2NvdW50SW5zaWdodENvbXBvbmVudCBleHRlbmRzIEFwcEJhc2VDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSB7XG4gICAgc3Vic2NyaXB0aW9uOiBTdWJzY3JpcHRpb247XG4gICAgdXNlcklkOiBudW1iZXI7XG4gICAgdXNlcjogVXNlcjtcbiAgICBoYXNBY2Nlc3M6IGJvb2xlYW47XG5cbiAgICBzaWduZWRVcExhc3RUaGlydHlEYXlzOiBzaWduZWRVcExhc3RUaGlydHlEYXlzW107XG4gICAgYWN0aXZlT3Bwb3J0dW5pdGllczogYWN0aXZlT3Bwb3J0dW5pdGllc1tdO1xuICAgIGFjY291bnRBdFJpc2s7XG4gICAgQ29udHJhY3RSZW5ld2FsO1xuICAgIGFjY291bnRJbnNpZ2h0O1xuICAgIGFjY291bnRHZW9ncmFwaHk6IHsgZGF0YTogW107IGxheW91dDogb2JqZWN0IH07XG4gICAgY2h1cm5lZEFjY291bnRzO1xuICAgIGFjY291bnRMYXN0QWN0aXZpdGllcztcbiAgICBjcmVkaXRDYXJkRXhwaXJpbmc7XG4gICAgbWFnaWNNb21lbnQ7XG5cbiAgICBzaWduVXBMYXN0TmluZXR5RGF5c0xvYWRlZCA9IGZhbHNlO1xuICAgIGFjY291bnRMYXN0QWN0aXZpdGllc0xvYWRlZCA9IGZhbHNlO1xuICAgIGNodXJuZWRBY2NvdW50TG9hZGVkID0gZmFsc2U7XG4gICAgYWN0aXZlT3Bwb3J0dW5pdGllc0xvYWRlZCA9IGZhbHNlO1xuICAgIGFjY291bnRBdFJpc2tEZXRhaWxzTG9hZGVkID0gZmFsc2U7XG4gICAgY29udGFjdFJlbmV3YWxMb2FkZWQgPSBmYWxzZTtcbiAgICBjcmVkaXRDYXJkRXhwaXJpbmdEZXRhaWxzTG9hZGVkID0gZmFsc2U7XG4gICAgYWNjb3VudEdlb2dyYXBoeUxvYWRlZCA9IGZhbHNlO1xuICAgIGFjY291bnRJbnNpZ2h0TG9hZGVkID0gZmFsc2U7XG4gICAgbWFnaWNNb21lbnRMb2FkZWQgPSBmYWxzZTtcblxuICAgIGFjdGlvbk5hbWVzO1xuXG4gICAgLy8gVG90YWxzIGZvciBNUlIgY29sdW1uc1xuICAgIGFjdGl2ZU9wcG9ydHVuaXRpZXNUb3RhbCA9IHsgdG90YWxfbXJyOiAwIH07XG4gICAgYWNjb3VudEF0Umlza1RvdGFsID0geyB0b3RhbF9tcnI6IDAgfTtcbiAgICBjb250cmFjdFJlbmV3YWxUb3RhbCA9IHsgdG90YWxfbXJyOiAwIH07XG4gICAgY3JlZGl0Q2FyZEV4cGlyaW5nVG90YWwgPSB7IHRvdGFsX21ycjogMCB9O1xuICAgIG1hZ2ljTW9tZW50VG90YWwgPSB7IHRvdGFsX21ycjogMCB9O1xuICAgIHNpZ25lZFVwTGFzdE5pbmV0eURheXNUb3RhbCA9IHsgdG90YWxfbXJyOiAwIH07XG4gICAgY2h1cm5lZEFjY291bnRzVG90YWwgPSB7IHRvdGFsX21ycjogMCB9O1xuXG4gICAgcm91dGVycyA9IFJPVVRFUlM7XG5cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSBjcm1TZXJ2aWNlOiBDcm1TZXJ2aWNlLFxuICAgICAgICBpbmplY3RvcjogSW5qZWN0b3JcbiAgICApIHtcbiAgICAgICAgc3VwZXIoaW5qZWN0b3IpO1xuICAgIH1cblxuICAgIG5nT25Jbml0KCk6IHZvaWQge1xuICAgICAgICB0aGlzLmdldFVzZXJTdWJzY3JpcHRpb24oKS5zdWJzY3JpYmUocmVzcG9uc2UgPT4ge1xuICAgICAgICAgICAgdGhpcy5zdWJzY3JpcHRpb24gPSByZXNwb25zZTtcbiAgICAgICAgICAgIGlmICh0aGlzLnN1YnNjcmlwdGlvbj8uaWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmhhc0FjY2VzcyA9IHRoaXMuaGFzQWRtaW5BY2Nlc3ModGhpcy5zdWJzY3JpcHRpb24uaWQpO1xuICAgICAgICAgICAgICAgIHRoaXMuZ2V0VXNlckluZm8oKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRVc2VySW5mbygpIHtcbiAgICAgICAgdGhpcy51c2VyU3RvcmUoKS5zdWJzY3JpYmUodXNlciA9PiB7XG4gICAgICAgICAgICBpZiAodXNlcikge1xuICAgICAgICAgICAgICAgIHRoaXMudXNlciA9IHVzZXI7XG4gICAgICAgICAgICAgICAgdGhpcy51c2VySWQgPSB1c2VyLmlkO1xuICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wZXJtaXNzaW9uU2VydmljZS5pc0dyYW50ZWQoJ1BhZ2VzLkJldGEnKSB8fFxuICAgICAgICAgICAgICAgICAgICB0aGlzLnBlcm1pc3Npb25TZXJ2aWNlLmlzU3VwZXJBZG1pbigpXG4gICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZ2V0U2lnbmVkVXBMYXN0TmluZXR5RGF5cygpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmdldEFjdGl2ZU9wcG9ydHVuaXRpZXMoKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5nZXRDaHVybmVkQWNjb3VudHMoKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5nZXRBY2NvdW50TGFzdEFjdGl2aXRpZXMoKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5nZXRBY2NvdW50QXRSaXNrRGV0YWlscygpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmdldENvbnRhY3RSZW5ld2FsKCk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZ2V0Q3JlZGl0Q2FyZEV4cGlyaW5nRGV0YWlscygpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmdldE1hZ2ljTW9tZW50KCk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZ2V0QWNjb3VudEdlb2dyYXBoeSgpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmdldEFjY291bnRJbnNpZ2h0cygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqIEZ1bmN0aW9uIHRvIGNhbGwgc2lnbmVkIHVwIGxhc3QgOTAgZGF5cyBkZXRhaWxzICovXG4gICAgcHJpdmF0ZSBnZXRTaWduZWRVcExhc3ROaW5ldHlEYXlzKCkge1xuICAgICAgICB0aGlzLmNybVNlcnZpY2VcbiAgICAgICAgICAgIC5nZXRDcm1BbmFseXRpY3ModGhpcy5zdWJzY3JpcHRpb24/LmlkLCAnYWNjb3VudHNfc2lnbmVkX3VwX2xhc3RfOTBfZGF5cycpXG4gICAgICAgICAgICAuc3Vic2NyaWJlKHJlc3BvbnNlID0+IHtcbiAgICAgICAgICAgICAgICAvLyBBUEkgbm93IHJldHVybnMgeyBpdGVtczogW10sIHRvdGFsczoge30gfSBpbnN0ZWFkIG9mIGFycmF5XG4gICAgICAgICAgICAgICAgY29uc3QgaXRlbXMgPSByZXNwb25zZT8uaXRlbXMgfHwgcmVzcG9uc2U7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBpdGVtcyA9PT0gJ29iamVjdCcgJiYgT2JqZWN0LmtleXMoaXRlbXMpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnNpZ25lZFVwTGFzdFRoaXJ0eURheXMgPSBbXTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnNpZ25lZFVwTGFzdFRoaXJ0eURheXMgPSBBcnJheS5pc0FycmF5KGl0ZW1zKSA/IGl0ZW1zIDogW107XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIEV4dHJhY3QgdG90YWxzIGZyb20gQVBJIHJlc3BvbnNlXG4gICAgICAgICAgICAgICAgaWYgKHJlc3BvbnNlPy50b3RhbHMpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zaWduZWRVcExhc3ROaW5ldHlEYXlzVG90YWwgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0b3RhbF9tcnI6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2UudG90YWxzLmV4cGVjdGVkX21ycl91c2QgfHwgcmVzcG9uc2UudG90YWxzLm1vbnRobHlfYW1vdW50IHx8IDBcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLmFkZCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5zaWduVXBMYXN0TmluZXR5RGF5c0xvYWRlZCA9IHRydWU7XG4gICAgICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdldEFjY291bnRMYXN0QWN0aXZpdGllcygpIHtcbiAgICAgICAgdGhpcy5jcm1TZXJ2aWNlXG4gICAgICAgICAgICAuZ2V0Q3JtQW5hbHl0aWNzKHRoaXMuc3Vic2NyaXB0aW9uPy5pZCwgJ2FjY291bnRzX2xhc3RfYWN0aXZpdGllcycpXG4gICAgICAgICAgICAuc3Vic2NyaWJlKHJlc3BvbnNlID0+IHtcbiAgICAgICAgICAgICAgICAvLyBBUEkgbm93IHJldHVybnMgeyBpdGVtczogW10sIHRvdGFsczoge30gfSBpbnN0ZWFkIG9mIGFycmF5XG4gICAgICAgICAgICAgICAgY29uc3QgaXRlbXMgPSByZXNwb25zZT8uaXRlbXMgfHwgcmVzcG9uc2U7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBpdGVtcyA9PT0gJ29iamVjdCcgJiYgT2JqZWN0LmtleXMoaXRlbXMpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmFjY291bnRMYXN0QWN0aXZpdGllcyA9IFtdO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYWNjb3VudExhc3RBY3Rpdml0aWVzID0gQXJyYXkuaXNBcnJheShpdGVtcykgPyBpdGVtcyA6IFtdO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmFjdGlvbk5hbWVzID0gdGhpcy5hY2NvdW50TGFzdEFjdGl2aXRpZXM/Lm1hcChcbiAgICAgICAgICAgICAgICAgICAgICAgIChhY3Rpb246IHsgY3JtX2FjdGlvbj86IHsgbmFtZT86IHN0cmluZyB9IH0pID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gYWN0aW9uPy5jcm1fYWN0aW9uPy5uYW1lO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuYWRkKCgpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmFjY291bnRMYXN0QWN0aXZpdGllc0xvYWRlZCA9IHRydWU7XG4gICAgICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdldENodXJuZWRBY2NvdW50cygpIHtcbiAgICAgICAgdGhpcy5jcm1TZXJ2aWNlXG4gICAgICAgICAgICAuZ2V0Q3JtQW5hbHl0aWNzKHRoaXMuc3Vic2NyaXB0aW9uPy5pZCwgJ2FjY291bnRzX2FjY291bnRzX2NodXJuZWQnKVxuICAgICAgICAgICAgLnN1YnNjcmliZShyZXNwb25zZSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gQVBJIG5vdyByZXR1cm5zIHsgaXRlbXM6IFtdLCB0b3RhbHM6IHt9IH0gaW5zdGVhZCBvZiBhcnJheVxuICAgICAgICAgICAgICAgIGNvbnN0IGl0ZW1zID0gcmVzcG9uc2U/Lml0ZW1zIHx8IHJlc3BvbnNlO1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgaXRlbXMgPT09ICdvYmplY3QnICYmIE9iamVjdC5rZXlzKGl0ZW1zKS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jaHVybmVkQWNjb3VudHMgPSBbXTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNodXJuZWRBY2NvdW50cyA9IEFycmF5LmlzQXJyYXkoaXRlbXMpID8gaXRlbXMgOiBbXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gRXh0cmFjdCB0b3RhbHMgZnJvbSBBUEkgcmVzcG9uc2VcbiAgICAgICAgICAgICAgICBpZiAocmVzcG9uc2U/LnRvdGFscykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNodXJuZWRBY2NvdW50c1RvdGFsID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxfbXJyOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlLnRvdGFscy5leHBlY3RlZF9tcnJfdXNkIHx8IHJlc3BvbnNlLnRvdGFscy5tb250aGx5X2Ftb3VudCB8fCAwXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5hZGQoKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuY2h1cm5lZEFjY291bnRMb2FkZWQgPSB0cnVlO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqIEZ1bmN0aW9uIHRvIGNhbGwgQWN0aXZlIE9wcG9ydHVuaXRpZXMgZGV0YWlscyAqL1xuICAgIHByaXZhdGUgZ2V0QWN0aXZlT3Bwb3J0dW5pdGllcygpIHtcbiAgICAgICAgdGhpcy5jcm1TZXJ2aWNlXG4gICAgICAgICAgICAuZ2V0Q3JtQW5hbHl0aWNzKHRoaXMuc3Vic2NyaXB0aW9uPy5pZCwgJ2FjY291bnRzX2FjdGl2ZV9vcHBvcnR1bml0aWVzJylcbiAgICAgICAgICAgIC5zdWJzY3JpYmUocmVzcG9uc2UgPT4ge1xuICAgICAgICAgICAgICAgIC8vIEFQSSBub3cgcmV0dXJucyB7IGl0ZW1zOiBbXSwgdG90YWxzOiB7fSB9IGluc3RlYWQgb2YgYXJyYXlcbiAgICAgICAgICAgICAgICBjb25zdCBpdGVtcyA9IHJlc3BvbnNlPy5pdGVtcyB8fCByZXNwb25zZTtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGl0ZW1zID09PSAnb2JqZWN0JyAmJiBPYmplY3Qua2V5cyhpdGVtcykubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYWN0aXZlT3Bwb3J0dW5pdGllcyA9IFtdO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYWN0aXZlT3Bwb3J0dW5pdGllcyA9IEFycmF5LmlzQXJyYXkoaXRlbXMpID8gaXRlbXMgOiBbXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gRXh0cmFjdCB0b3RhbHMgZnJvbSBBUEkgcmVzcG9uc2VcbiAgICAgICAgICAgICAgICBpZiAocmVzcG9uc2U/LnRvdGFscykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmFjdGl2ZU9wcG9ydHVuaXRpZXNUb3RhbCA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFsX21ycjpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNwb25zZS50b3RhbHMuZXhwZWN0ZWRfbXJyX3VzZCB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlLnRvdGFscy5leHBlY3RlZF9jbG9zZV92YWx1ZSB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDBcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLmFkZCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5hY3RpdmVPcHBvcnR1bml0aWVzTG9hZGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0TWFnaWNNb21lbnQoKSB7XG4gICAgICAgIHRoaXMuY3JtU2VydmljZVxuICAgICAgICAgICAgLmdldENybUFuYWx5dGljcyh0aGlzLnN1YnNjcmlwdGlvbj8uaWQsICdtYWdpY19tb21lbnQnKVxuICAgICAgICAgICAgLnN1YnNjcmliZShyZXNwb25zZSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gQVBJIG5vdyByZXR1cm5zIHsgaXRlbXM6IFtdLCB0b3RhbHM6IHt9IH0gaW5zdGVhZCBvZiBhcnJheVxuICAgICAgICAgICAgICAgIGNvbnN0IGl0ZW1zID0gcmVzcG9uc2U/Lml0ZW1zIHx8IHJlc3BvbnNlO1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgaXRlbXMgPT09ICdvYmplY3QnICYmIE9iamVjdC5rZXlzKGl0ZW1zKS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5tYWdpY01vbWVudCA9IFtdO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubWFnaWNNb21lbnQgPSBBcnJheS5pc0FycmF5KGl0ZW1zKSA/IGl0ZW1zIDogW107XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIEV4dHJhY3QgdG90YWxzIGZyb20gQVBJIHJlc3BvbnNlXG4gICAgICAgICAgICAgICAgaWYgKHJlc3BvbnNlPy50b3RhbHMpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5tYWdpY01vbWVudFRvdGFsID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxfbXJyOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlLnRvdGFscy5leHBlY3RlZF9tcnJfdXNkIHx8IHJlc3BvbnNlLnRvdGFscy5tb250aGx5X2Ftb3VudCB8fCAwXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5hZGQoKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMubWFnaWNNb21lbnRMb2FkZWQgPSB0cnVlO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRDcmVkaXRDYXJkRXhwaXJpbmdEZXRhaWxzKCkge1xuICAgICAgICB0aGlzLmNybVNlcnZpY2VcbiAgICAgICAgICAgIC5nZXRDcm1BbmFseXRpY3ModGhpcy5zdWJzY3JpcHRpb24/LmlkLCAnY3JlZGl0X2NhcmRfZXhwaXJpbmcnKVxuICAgICAgICAgICAgLnN1YnNjcmliZShyZXNwb25zZSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gQVBJIG5vdyByZXR1cm5zIHsgaXRlbXM6IFtdLCB0b3RhbHM6IHt9IH0gaW5zdGVhZCBvZiBhcnJheVxuICAgICAgICAgICAgICAgIGNvbnN0IGl0ZW1zID0gcmVzcG9uc2U/Lml0ZW1zIHx8IHJlc3BvbnNlO1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgaXRlbXMgPT09ICdvYmplY3QnICYmIE9iamVjdC5rZXlzKGl0ZW1zKS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jcmVkaXRDYXJkRXhwaXJpbmcgPSBbXTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNyZWRpdENhcmRFeHBpcmluZyA9IEFycmF5LmlzQXJyYXkoaXRlbXMpID8gaXRlbXMgOiBbXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gRXh0cmFjdCB0b3RhbHMgZnJvbSBBUEkgcmVzcG9uc2VcbiAgICAgICAgICAgICAgICBpZiAocmVzcG9uc2U/LnRvdGFscykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNyZWRpdENhcmRFeHBpcmluZ1RvdGFsID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxfbXJyOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlLnRvdGFscy5leHBlY3RlZF9tcnJfdXNkIHx8IHJlc3BvbnNlLnRvdGFscy5tb250aGx5X2Ftb3VudCB8fCAwXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5hZGQoKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuY3JlZGl0Q2FyZEV4cGlyaW5nRGV0YWlsc0xvYWRlZCA9IHRydWU7XG4gICAgICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKiogRnVuY3Rpb24gdG8gY2FsbCBBY2NvdW50IEF0IFJpc2sgZGV0YWlscyAqL1xuICAgIHByaXZhdGUgZ2V0QWNjb3VudEF0Umlza0RldGFpbHMoKSB7XG4gICAgICAgIHRoaXMuY3JtU2VydmljZVxuICAgICAgICAgICAgLmdldENybUFuYWx5dGljcyh0aGlzLnN1YnNjcmlwdGlvbj8uaWQsICdhY2NvdW50c19hY2NvdW50c19hdF9yaXNrJylcbiAgICAgICAgICAgIC5zdWJzY3JpYmUocmVzcG9uc2UgPT4ge1xuICAgICAgICAgICAgICAgIC8vIEFQSSBub3cgcmV0dXJucyB7IGl0ZW1zOiBbXSwgdG90YWxzOiB7fSB9IGluc3RlYWQgb2YgYXJyYXlcbiAgICAgICAgICAgICAgICBjb25zdCBpdGVtcyA9IHJlc3BvbnNlPy5pdGVtcyB8fCByZXNwb25zZTtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGl0ZW1zID09PSAnb2JqZWN0JyAmJiBPYmplY3Qua2V5cyhpdGVtcykubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYWNjb3VudEF0UmlzayA9IFtdO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYWNjb3VudEF0UmlzayA9IEFycmF5LmlzQXJyYXkoaXRlbXMpID8gaXRlbXMgOiBbXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gRXh0cmFjdCB0b3RhbHMgZnJvbSBBUEkgcmVzcG9uc2VcbiAgICAgICAgICAgICAgICBpZiAocmVzcG9uc2U/LnRvdGFscykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmFjY291bnRBdFJpc2tUb3RhbCA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFsX21ycjpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNwb25zZS50b3RhbHMuZXhwZWN0ZWRfbXJyX3VzZCB8fCByZXNwb25zZS50b3RhbHMubW9udGhseV9hbW91bnQgfHwgMFxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuYWRkKCgpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmFjY291bnRBdFJpc2tEZXRhaWxzTG9hZGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKiBGdW5jdGlvbiB0byBjYWxsIENvbnRyYWN0IHJlbmV3YWwgZGV0YWlscyAqL1xuICAgIHByaXZhdGUgZ2V0Q29udGFjdFJlbmV3YWwoKSB7XG4gICAgICAgIHRoaXMuY3JtU2VydmljZVxuICAgICAgICAgICAgLmdldENybUFuYWx5dGljcyh0aGlzLnN1YnNjcmlwdGlvbj8uaWQsICdhY2NvdW50c19jb250cmFjdF9yZW5ld2FsJylcbiAgICAgICAgICAgIC5zdWJzY3JpYmUocmVzcG9uc2UgPT4ge1xuICAgICAgICAgICAgICAgIC8vIEFQSSBub3cgcmV0dXJucyB7IGl0ZW1zOiBbXSwgdG90YWxzOiB7fSB9IGluc3RlYWQgb2YgYXJyYXlcbiAgICAgICAgICAgICAgICBjb25zdCBpdGVtcyA9IHJlc3BvbnNlPy5pdGVtcyB8fCByZXNwb25zZTtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGl0ZW1zID09PSAnb2JqZWN0JyAmJiBPYmplY3Qua2V5cyhpdGVtcykubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuQ29udHJhY3RSZW5ld2FsID0gW107XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5Db250cmFjdFJlbmV3YWwgPSBBcnJheS5pc0FycmF5KGl0ZW1zKSA/IGl0ZW1zIDogW107XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIEV4dHJhY3QgdG90YWxzIGZyb20gQVBJIHJlc3BvbnNlXG4gICAgICAgICAgICAgICAgaWYgKHJlc3BvbnNlPy50b3RhbHMpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb250cmFjdFJlbmV3YWxUb3RhbCA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFsX21ycjpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNwb25zZS50b3RhbHMuZXhwZWN0ZWRfbXJyX3VzZCB8fCByZXNwb25zZS50b3RhbHMubW9udGhseV9hbW91bnQgfHwgMFxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuYWRkKCgpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmNvbnRhY3RSZW5ld2FsTG9hZGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0QWNjb3VudEluc2lnaHRzKCkge1xuICAgICAgICB0aGlzLmNybVNlcnZpY2VcbiAgICAgICAgICAgIC5nZXRDcm1BbmFseXRpY3ModGhpcy5zdWJzY3JpcHRpb24/LmlkLCAnYWNjb3VudHNfaW5zaWdodHMnKVxuICAgICAgICAgICAgLnN1YnNjcmliZShyZXNwb25zZSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gQVBJIG5vdyByZXR1cm5zIHsgaXRlbXM6IFtdLCB0b3RhbHM6IHt9IH0gaW5zdGVhZCBvZiBhcnJheVxuICAgICAgICAgICAgICAgIGNvbnN0IGl0ZW1zID0gcmVzcG9uc2U/Lml0ZW1zIHx8IHJlc3BvbnNlO1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgaXRlbXMgPT09ICdvYmplY3QnICYmIE9iamVjdC5rZXlzKGl0ZW1zKS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5hY2NvdW50SW5zaWdodCA9IFtdO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYWNjb3VudEluc2lnaHQgPSBBcnJheS5pc0FycmF5KGl0ZW1zKSA/IGl0ZW1zIDogW107XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5hZGQoKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuYWNjb3VudEluc2lnaHRMb2FkZWQgPSB0cnVlO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRBY2NvdW50R2VvZ3JhcGh5KCkge1xuICAgICAgICB0aGlzLmNybVNlcnZpY2VcbiAgICAgICAgICAgIC5nZXRDcm1BbmFseXRpY3ModGhpcy5zdWJzY3JpcHRpb24/LmlkLCAnYWNjb3VudHNfZ2VvZ3JhcGh5JylcbiAgICAgICAgICAgIC5zdWJzY3JpYmUocmVzcG9uc2UgPT4ge1xuICAgICAgICAgICAgICAgIC8vIEFQSSBub3cgcmV0dXJucyB7IGl0ZW1zOiBbXSwgdG90YWxzOiB7fSB9IGluc3RlYWQgb2YgYXJyYXkvb2JqZWN0XG4gICAgICAgICAgICAgICAgY29uc3QgaXRlbXMgPSByZXNwb25zZT8uaXRlbXMgfHwgcmVzcG9uc2U7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBpdGVtcyA9PT0gJ29iamVjdCcgJiYgT2JqZWN0LmtleXMoaXRlbXMpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmFjY291bnRHZW9ncmFwaHkgPSB7IGRhdGE6IFtdLCBsYXlvdXQ6IHt9IH07XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5hY2NvdW50R2VvZ3JhcGh5ID0gaXRlbXM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5hZGQoKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuYWNjb3VudEdlb2dyYXBoeUxvYWRlZCA9IHRydWU7XG4gICAgICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBjaGVja1Blcm1pc3Npb24ocGVybWlzc2lvbjogc3RyaW5nKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnBlcm1pc3Npb25TZXJ2aWNlLmV2YWx1YXRlUGVybWlzc2lvbnMocGVybWlzc2lvbik7XG4gICAgfVxuXG4gICAgZ2V0TWFpbkN1cnJlbmN5Rm9yVGFibGUoaXRlbXM6IHVua25vd25bXSk6IHN0cmluZyB7XG4gICAgICAgIGlmIChpdGVtcyAmJiBpdGVtcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBjb25zdCBmaXJzdEl0ZW0gPSBpdGVtc1swXSBhcyB7IG1haW5fY3VycmVuY3k/OiBzdHJpbmc7IGN1cnJlbmN5Pzogc3RyaW5nIH07XG4gICAgICAgICAgICByZXR1cm4gZmlyc3RJdGVtPy5tYWluX2N1cnJlbmN5IHx8IGZpcnN0SXRlbT8uY3VycmVuY3kgfHwgJ1VTRCc7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICdVU0QnO1xuICAgIH1cblxuICAgIG92ZXJyaWRlIG5nT25EZXN0cm95KCkge1xuICAgICAgICBzdXBlci5uZ09uRGVzdHJveSgpO1xuICAgIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJyb3dcIj5cbiAgPG5nLWNvbnRhaW5lciBjbGFzcz1cIm10LTVcIj5cblxuICAgIDwhLS0gU2lnbmVkIHVwIGxhc3QgOTAgZGF5cyAtLT5cbiAgICA8ZGl2IGNsYXNzPVwiY29sLTEyIGNvbC1tZC02IG1iLTMgYW5hbHl0aWNzXCI+XG4gICAgICA8aDUgY2xhc3M9XCJhY2NvcmRpb24taGVhZGluZ1wiPlNpZ25lZCB1cCBMYXN0IDkwIERheXM8L2g1PlxuICAgICAgPGRpdiBjbGFzcz1cInctMTAwIHRleHQtY2VudGVyIG10LTNcIj5cbiAgICAgICAgPG5nLXRlbXBsYXRlIFtuZ0lmXT1cIiFzaWduVXBMYXN0TmluZXR5RGF5c0xvYWRlZFwiPlxuICAgICAgICAgIDxwLXByb2dyZXNzU3Bpbm5lciBzdHJva2VXaWR0aD1cIjJcIj4gPC9wLXByb2dyZXNzU3Bpbm5lcj5cbiAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiBjbGFzcz1cInByaW1lbmctZGF0YXRhYmxlLWNvbnRhaW5lciB0YWJsZS1yZXNwb25zaXZlXCJcbiAgICAgICAgKm5nSWY9XCJzaWduZWRVcExhc3RUaGlydHlEYXlzPy5sZW5ndGhcIj5cbiAgICAgICAgPHAtdGFibGUgY2xhc3M9XCJ0YWJsZVwiXG4gICAgICAgICAgI2R0XG4gICAgICAgICAgW3ZhbHVlXT1cInNpZ25lZFVwTGFzdFRoaXJ0eURheXNcIlxuICAgICAgICAgIFtwYWdpbmF0b3JdPVwidHJ1ZVwiXG4gICAgICAgICAgW3Jvd3NdPVwiMjBcIlxuICAgICAgICAgIFt0b3RhbFJlY29yZHNdPVwic2lnbmVkVXBMYXN0VGhpcnR5RGF5cy5sZW5ndGhcIj5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiaGVhZGVyXCI+XG4gICAgICAgICAgICA8dHI+XG4gICAgICAgICAgICAgIDx0aCBzY29wZT1cInRydWVcIj57eyAnQ3JtLlN1bW1hcnkuQWNjb3VudCcgfCB0cmFuc2xvY28gfX08L3RoPlxuICAgICAgICAgICAgICA8dGggc2NvcGU9XCJ0cnVlXCIgY2xhc3M9XCJtcnItaGVhZGVyXCI+e3sgJ0NybS5BY2NvdW50TWVzc2FnZS5NUlInIHwgdHJhbnNsb2NvIH19PC90aD5cbiAgICAgICAgICAgICAgPHRoIHNjb3BlPVwidHJ1ZVwiPnt7ICdDcm0uQWNjb3VudE1lc3NhZ2UuU2lnblVwQXQnIHwgdHJhbnNsb2NvIH19PC90aD5cbiAgICAgICAgICAgIDwvdHI+XG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiYm9keVwiXG4gICAgICAgICAgICBsZXQtc2lnblVwXG4gICAgICAgICAgICBsZXQtaT1cInJvd0luZGV4XCI+XG4gICAgICAgICAgICA8IS0tIFRvdGFscyByb3cgYXQgdGhlIHRvcCAoZmlyc3Qgcm93KSAtLT5cbiAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJpID09PSAwICYmIHNpZ25lZFVwTGFzdFRoaXJ0eURheXM/Lmxlbmd0aFwiPlxuICAgICAgICAgICAgICA8dHIgY2xhc3M9XCJ0b3RhbHMtcm93XCI+XG4gICAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICAgICAgPHRkIGNsYXNzPVwiZnctYm9sZCBleHBlY3RlZC1tcnJcIj5cbiAgICAgICAgICAgICAgICAgIDxzdHJvbmc+e3sgc2lnbmVkVXBMYXN0TmluZXR5RGF5c1RvdGFsPy50b3RhbF9tcnIgLyAxMDAgfCBjdXJyZW5jeTogJ1VTRCcgfX08L3N0cm9uZz5cbiAgICAgICAgICAgICAgICA8L3RkPlxuICAgICAgICAgICAgICAgIDx0ZD48L3RkPlxuICAgICAgICAgICAgICA8L3RyPlxuICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICA8IS0tIFJlZ3VsYXIgZGF0YSByb3cgLS0+XG4gICAgICAgICAgICA8dHI+XG4gICAgICAgICAgICAgIDx0ZCBkYXRhLWhlYWQ9XCJBY2NvdW50XCI+XG4gICAgICAgICAgICAgICAgPGEgW3JvdXRlckxpbmtdPVwiWycvJyArIHN1YnNjcmlwdGlvbj8uc2x1ZyArIHJvdXRlcnMuYWNjb3VudEluZm8sIHNpZ25VcC5jcm1fYWNjb3VudF9pZF1cIiBjbGFzcz1cIm5hbWUtbGlua1wiPlxuICAgICAgICAgICAgICAgICAgPHNwYW4gW25nYlRvb2x0aXBdPVwic2lnblVwLmNybV9hY2NvdW50X25hbWVcIj57eyBzaWduVXA/LmNybV9hY2NvdW50X25hbWUgfCB0ZXh0VHJ1bmNhdGU6MjAgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgICA8L3RkPlxuICAgICAgICAgICAgICA8dGQgZGF0YS1oZWFkPVwiTVJSXCIgY2xhc3M9XCJleHBlY3RlZC1tcnJcIj5cbiAgICAgICAgICAgICAgICB7eyBzaWduVXAuZXhwZWN0ZWRfbXJyIC8gMTAwIHwgY3VycmVuY3k6IChzaWduVXAuY3VycmVuY3kgfHwgc2lnblVwLm1haW5fY3VycmVuY3kpIH19XG4gICAgICAgICAgICAgIDwvdGQ+XG4gICAgICAgICAgICAgIDx0ZCBkYXRhLWhlYWQ9XCJTaWduVXBBdFwiPlxuICAgICAgICAgICAgICAgIHt7IHNpZ25VcC5zaWduZWRfdXBfYXQgfCBkYXRlRm9ybWF0IH19XG4gICAgICAgICAgICAgIDwvdGQ+XG4gICAgICAgICAgICA8L3RyPlxuICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgICAgPG5nLXRlbXBsYXRlIHBUZW1wbGF0ZT1cImZvb3RlclwiPlxuICAgICAgICAgICAgPHRyICpuZ0lmPVwic2lnbmVkVXBMYXN0VGhpcnR5RGF5cz8ubGVuZ3RoXCI+XG4gICAgICAgICAgICAgIDx0ZD48L3RkPlxuICAgICAgICAgICAgICA8dGQgY2xhc3M9XCJmdy1ib2xkIGV4cGVjdGVkLW1yclwiPlxuICAgICAgICAgICAgICAgIDxzdHJvbmc+e3sgc2lnbmVkVXBMYXN0TmluZXR5RGF5c1RvdGFsPy50b3RhbF9tcnIgLyAxMDAgfCBjdXJyZW5jeTogJ1VTRCcgfX08L3N0cm9uZz5cbiAgICAgICAgICAgICAgPC90ZD5cbiAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICA8L3RyPlxuICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgIDwvcC10YWJsZT5cbiAgICAgICAgPHNwYW4gY2xhc3M9XCJ0b3RhbC1yZWNvcmRzLWNvdW50XCIgKm5nSWY9XCJzaWduZWRVcExhc3RUaGlydHlEYXlzLmxlbmd0aCE9PSAwXCI+e3sgJ0xhYmVsLlRvdGFsJyB8IHRyYW5zbG9jbyB9fToge3sgc2lnbmVkVXBMYXN0VGhpcnR5RGF5cy5sZW5ndGggfX08L3NwYW4+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXYgKm5nSWY9XCJzaWduZWRVcExhc3RUaGlydHlEYXlzPy5sZW5ndGggPT09IDBcIj5cbiAgICAgICAgPHB3LW5vLWRhdGEgW3dpdGhJbWFnZV09XCJ0cnVlXCIgW21lc3NhZ2VdPVwiJ0NybS5TdW1tYXJ5Lk5vSW5zaWdodE1lc3NhZ2UnIHwgdHJhbnNsb2NvXCI+IDwvcHctbm8tZGF0YT5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPCEtLSBDaHVybmVkIExhc3QgOTAgZGF5cyAtLT5cbiAgICA8ZGl2IGNsYXNzPVwiY29sLTEyIGNvbC1tZC02IG1iLTMgYW5hbHl0aWNzXCI+XG4gICAgICA8aDUgY2xhc3M9XCJhY2NvcmRpb24taGVhZGluZ1wiPkNodXJuZWQgTGFzdCA5MCBEYXlzPC9oNT5cbiAgICAgIDxkaXYgY2xhc3M9XCJ3LTEwMCB0ZXh0LWNlbnRlciBtdC0zXCI+XG4gICAgICAgIDxuZy10ZW1wbGF0ZSBbbmdJZl09XCIhY2h1cm5lZEFjY291bnRMb2FkZWRcIj5cbiAgICAgICAgICA8cC1wcm9ncmVzc1NwaW5uZXIgc3Ryb2tlV2lkdGg9XCIyXCI+IDwvcC1wcm9ncmVzc1NwaW5uZXI+XG4gICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3M9XCJwcmltZW5nLWRhdGF0YWJsZS1jb250YWluZXIgdGFibGUtcmVzcG9uc2l2ZVwiICpuZ0lmPVwiY2h1cm5lZEFjY291bnRzPy5sZW5ndGhcIj5cbiAgICAgICAgPHAtdGFibGUgY2xhc3M9XCJ0YWJsZVwiICNkdCBbdmFsdWVdPVwiY2h1cm5lZEFjY291bnRzXCIgW3BhZ2luYXRvcl09XCJ0cnVlXCIgW3Jvd3NdPVwiMjBcIlxuICAgICAgICAgIFt0b3RhbFJlY29yZHNdPVwiY2h1cm5lZEFjY291bnRzLmxlbmd0aFwiPlxuICAgICAgICAgIDxuZy10ZW1wbGF0ZSBwVGVtcGxhdGU9XCJoZWFkZXJcIj5cbiAgICAgICAgICAgIDx0cj5cbiAgICAgICAgICAgICAgPHRoIHNjb3BlPVwidHJ1ZVwiPnt7ICdDcm0uQWNjb3VudE1lc3NhZ2UuQWNjb3VudCcgfCB0cmFuc2xvY28gfX08L3RoPlxuICAgICAgICAgICAgICA8dGggc2NvcGU9XCJ0cnVlXCIgY2xhc3M9XCJtcnItaGVhZGVyXCI+e3sgJ0NybS5BY2NvdW50TWVzc2FnZS5NUlInIHwgdHJhbnNsb2NvIH19PC90aD5cbiAgICAgICAgICAgICAgPHRoIHNjb3BlPVwidHJ1ZVwiPnt7ICdDcm0uQWNjb3VudE1lc3NhZ2UuUXVhcnRlcicgfCB0cmFuc2xvY28gfX08L3RoPlxuICAgICAgICAgICAgICA8dGggc2NvcGU9XCJ0cnVlXCI+IHt7ICdDcm0uQWNjb3VudE1lc3NhZ2UuTW9udGgnIHwgdHJhbnNsb2NvIH19PC90aD5cbiAgICAgICAgICAgICAgPHRoIHNjb3BlPVwidHJ1ZVwiPnt7ICdDcm0uQWNjb3VudE1lc3NhZ2UuU2lnblVwQXQnIHwgdHJhbnNsb2NvIH19PC90aD5cbiAgICAgICAgICAgICAgPHRoIHNjb3BlPVwidHJ1ZVwiPnt7ICdDcm0uQWNjb3VudE1lc3NhZ2UuVW5zdWJzY3JpYmVkQXQnIHwgdHJhbnNsb2NvIH19PC90aD5cbiAgICAgICAgICAgIDwvdHI+XG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiYm9keVwiIGxldC1hY2NvdW50IGxldC1pPVwicm93SW5kZXhcIj5cbiAgICAgICAgICAgIDwhLS0gVG90YWxzIHJvdyBhdCB0aGUgdG9wIChmaXJzdCByb3cpIC0tPlxuICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImkgPT09IDAgJiYgY2h1cm5lZEFjY291bnRzPy5sZW5ndGhcIj5cbiAgICAgICAgICAgICAgPHRyIGNsYXNzPVwidG90YWxzLXJvd1wiPlxuICAgICAgICAgICAgICAgIDx0ZD48L3RkPlxuICAgICAgICAgICAgICAgIDx0ZCBjbGFzcz1cImZ3LWJvbGQgZXhwZWN0ZWQtbXJyXCI+XG4gICAgICAgICAgICAgICAgICA8c3Ryb25nPnt7IGNodXJuZWRBY2NvdW50c1RvdGFsPy50b3RhbF9tcnIgLyAxMDAgfCBjdXJyZW5jeTogJ1VTRCcgfX08L3N0cm9uZz5cbiAgICAgICAgICAgICAgICA8L3RkPlxuICAgICAgICAgICAgICAgIDx0ZD48L3RkPlxuICAgICAgICAgICAgICAgIDx0ZD48L3RkPlxuICAgICAgICAgICAgICAgIDx0ZD48L3RkPlxuICAgICAgICAgICAgICAgIDx0ZD48L3RkPlxuICAgICAgICAgICAgICA8L3RyPlxuICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICA8IS0tIFJlZ3VsYXIgZGF0YSByb3cgLS0+XG4gICAgICAgICAgICA8dHI+XG4gICAgICAgICAgICAgIDx0ZCBkYXRhLWhlYWQ9XCJBY2NvdW50XCI+XG4gICAgICAgICAgICAgICAgPGEgW3JvdXRlckxpbmtdPVwiWycvJyArIHN1YnNjcmlwdGlvbj8uc2x1ZyArIHJvdXRlcnMuYWNjb3VudEluZm8sIGFjY291bnQuY3JtX2FjY291bnRfaWRdXCJcbiAgICAgICAgICAgICAgICAgIGNsYXNzPVwibmFtZS1saW5rXCI+XG4gICAgICAgICAgICAgICAgICA8c3BhbiBbbmdiVG9vbHRpcF09XCJhY2NvdW50LmNybV9hY2NvdW50X25hbWVcIj57eyBhY2NvdW50LmNybV9hY2NvdW50X25hbWUgfCB0ZXh0VHJ1bmNhdGU6MjAgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgICA8L3RkPlxuICAgICAgICAgICAgICA8dGQgZGF0YS1oZWFkPVwiTVJSXCIgY2xhc3M9XCJleHBlY3RlZC1tcnJcIj4ge3sgYWNjb3VudC5leHBlY3RlZF9tcnIgLyAxMDAgfCBjdXJyZW5jeTogKCBhY2NvdW50Lm1haW5fY3VycmVuY3kgfHwgYWNjb3VudC5jdXJyZW5jeSkgfX0gPC90ZD5cbiAgICAgICAgICAgICAgPHRkIGRhdGEtaGVhZD1cIlF1YXJ0ZXJcIiBbbmdDbGFzc109XCJ7J21vbnRoLXF1YXJ0ZXItdGV4dCBmdy1ib2xkJzogYWNjb3VudC5zZXNzaW9uc19sYXN0X3F1YXJ0ZXIgPiAxNX1cIj57eyBhY2NvdW50LnNlc3Npb25zX2xhc3RfcXVhcnRlciB9fTwvdGQ+XG4gICAgICAgICAgICAgIDx0ZCBkYXRhLWhlYWQ9XCJNb250aFwiIFtuZ0NsYXNzXT1cInsnbW9udGgtcXVhcnRlci10ZXh0IGZ3LWJvbGQnOiBhY2NvdW50LnNlc3Npb25zX2xhc3RfbW9udGggPiA1fVwiPnt7IGFjY291bnQuc2Vzc2lvbnNfbGFzdF9tb250aCB9fTwvdGQ+XG4gICAgICAgICAgICAgIDx0ZCBkYXRhLWhlYWQ9XCJTaWduVXBBdFwiPiB7eyBhY2NvdW50LnNpZ25lZF91cF9hdCB8IGRhdGVGb3JtYXQgfX0gPC90ZD5cbiAgICAgICAgICAgICAgPHRkIGRhdGEtaGVhZD1cIlVuc3Vic2NyaWJlZEF0XCIgW25nQ2xhc3NdPVwieyd0ZXh0LWRhbmdlcic6IGFjY291bnQudW5zdWJzY3JpYmVkX2F0IHwgaXNQYXN0RGF0ZX1cIj5cbiAgICAgICAgICAgICAgICB7eyBhY2NvdW50LnVuc3Vic2NyaWJlZF9hdCB8IGRhdGVGb3JtYXQgfX1cbiAgICAgICAgICAgICAgPC90ZD5cbiAgICAgICAgICAgIDwvdHI+XG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiZm9vdGVyXCI+XG4gICAgICAgICAgICA8dHIgKm5nSWY9XCJjaHVybmVkQWNjb3VudHM/Lmxlbmd0aFwiPlxuICAgICAgICAgICAgICA8dGQ+PC90ZD5cbiAgICAgICAgICAgICAgPHRkIGNsYXNzPVwiZnctYm9sZCBleHBlY3RlZC1tcnJcIj5cbiAgICAgICAgICAgICAgICA8c3Ryb25nPnt7IGNodXJuZWRBY2NvdW50c1RvdGFsPy50b3RhbF9tcnIgLyAxMDAgfCBjdXJyZW5jeTogJ1VTRCcgfX08L3N0cm9uZz5cbiAgICAgICAgICAgICAgPC90ZD5cbiAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICAgIDx0ZD48L3RkPlxuICAgICAgICAgICAgICA8dGQ+PC90ZD5cbiAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICA8L3RyPlxuICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgIDwvcC10YWJsZT5cbiAgICAgICAgPHNwYW4gY2xhc3M9XCJ0b3RhbC1yZWNvcmRzLWNvdW50XCIgKm5nSWY9XCJjaHVybmVkQWNjb3VudHM/Lmxlbmd0aCAhPT0gMFwiPnt7ICdMYWJlbC5Ub3RhbCcgfCB0cmFuc2xvY28gfX06IHt7XG4gICAgICAgICAgY2h1cm5lZEFjY291bnRzLmxlbmd0aCB9fTwvc3Bhbj5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiAqbmdJZj1cImNodXJuZWRBY2NvdW50cz8ubGVuZ3RoID09PSAwICYmIGNodXJuZWRBY2NvdW50TG9hZGVkXCI+XG4gICAgICAgIDxwdy1uby1kYXRhIFt3aXRoSW1hZ2VdPVwidHJ1ZVwiIFttZXNzYWdlXT1cIidDcm0uU3VtbWFyeS5Ob0luc2lnaHRNZXNzYWdlJyB8IHRyYW5zbG9jb1wiPiA8L3B3LW5vLWRhdGE+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDwhLS0gQWN0aXZlIE9wcG9ydHVuaXRpZXMgLS0+XG4gICAgPGRpdiBjbGFzcz1cImNvbC0xMiBjb2wtbWQtNiBtYi0zIGFuYWx5dGljc1wiPlxuICAgICAgPGg1IGNsYXNzPVwiYWNjb3JkaW9uLWhlYWRpbmdcIj5BY3RpdmUgT3Bwb3J0dW5pdGllczwvaDU+XG4gICAgICA8ZGl2IGNsYXNzPVwidy0xMDAgdGV4dC1jZW50ZXIgbXQtM1wiPlxuICAgICAgICA8bmctdGVtcGxhdGUgW25nSWZdPVwiIWFjdGl2ZU9wcG9ydHVuaXRpZXNMb2FkZWRcIj5cbiAgICAgICAgICA8cC1wcm9ncmVzc1NwaW5uZXIgc3Ryb2tlV2lkdGg9XCIyXCI+IDwvcC1wcm9ncmVzc1NwaW5uZXI+XG4gICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3M9XCJwcmltZW5nLWRhdGF0YWJsZS1jb250YWluZXIgdGFibGUtcmVzcG9uc2l2ZVwiXG4gICAgICAgICpuZ0lmPVwiYWN0aXZlT3Bwb3J0dW5pdGllcz8ubGVuZ3RoXCI+XG4gICAgICAgIDxwLXRhYmxlIGNsYXNzPVwidGFibGVcIlxuICAgICAgICAgICNkdFxuICAgICAgICAgIFt2YWx1ZV09XCJhY3RpdmVPcHBvcnR1bml0aWVzXCJcbiAgICAgICAgICBbcGFnaW5hdG9yXT1cInRydWVcIlxuICAgICAgICAgIFtyb3dzXT1cIjIwXCJcblxuICAgICAgICAgIFt0b3RhbFJlY29yZHNdPVwiYWN0aXZlT3Bwb3J0dW5pdGllcy5sZW5ndGhcIj5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiaGVhZGVyXCI+XG4gICAgICAgICAgICA8dHI+XG4gICAgICAgICAgICAgIDx0aCBzY29wZT1cInRydWVcIj57eyAnQ3JtLlN1bW1hcnkuQWNjb3VudCcgfCB0cmFuc2xvY28gfX08L3RoPlxuICAgICAgICAgICAgICA8dGggc2NvcGU9XCJ0cnVlXCI+e3sgJ0NybS5TdW1tYXJ5LlRpdGxlJyB8IHRyYW5zbG9jbyB9fTwvdGg+XG4gICAgICAgICAgICAgIDx0aCBzY29wZT1cInRydWVcIj57eyAnQ3JtLlN1bW1hcnkuT25lVGltZUFtb3VudCcgfCB0cmFuc2xvY28gfX08L3RoPlxuICAgICAgICAgICAgICA8dGggc2NvcGU9XCJ0cnVlXCIgY2xhc3M9XCJtcnItaGVhZGVyXCI+e3sgJ0NybS5BY2NvdW50TWVzc2FnZS5NUlInIHwgdHJhbnNsb2NvIH19PC90aD5cbiAgICAgICAgICAgICAgPHRoIHNjb3BlPVwidHJ1ZVwiPnt7ICdDcm0uU3VtbWFyeS5XaW5DaGFuY2UnIHwgdHJhbnNsb2NvIH19PC90aD5cbiAgICAgICAgICAgIDwvdHI+XG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiYm9keVwiXG4gICAgICAgICAgICBsZXQtb3Bwb3J0dW5pdGllc1xuICAgICAgICAgICAgbGV0LWk9XCJyb3dJbmRleFwiPlxuICAgICAgICAgICAgPCEtLSBUb3RhbHMgcm93IGF0IHRoZSB0b3AgKGZpcnN0IHJvdykgLS0+XG4gICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiaSA9PT0gMCAmJiBhY3RpdmVPcHBvcnR1bml0aWVzPy5sZW5ndGhcIj5cbiAgICAgICAgICAgICAgPHRyIGNsYXNzPVwidG90YWxzLXJvd1wiPlxuICAgICAgICAgICAgICAgIDx0ZD48L3RkPlxuICAgICAgICAgICAgICAgIDx0ZD48L3RkPlxuICAgICAgICAgICAgICAgIDx0ZD48L3RkPlxuICAgICAgICAgICAgICAgIDx0ZCBjbGFzcz1cImZ3LWJvbGQgZXhwZWN0ZWQtbXJyXCI+XG4gICAgICAgICAgICAgICAgICA8c3Ryb25nPnt7IGFjdGl2ZU9wcG9ydHVuaXRpZXNUb3RhbD8udG90YWxfbXJyIC8gMTAwIHwgY3VycmVuY3k6ICdVU0QnIH19PC9zdHJvbmc+XG4gICAgICAgICAgICAgICAgPC90ZD5cbiAgICAgICAgICAgICAgICA8dGQ+PC90ZD5cbiAgICAgICAgICAgICAgPC90cj5cbiAgICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgPCEtLSBSZWd1bGFyIGRhdGEgcm93IC0tPlxuICAgICAgICAgICAgPHRyPlxuICAgICAgICAgICAgICA8dGQgZGF0YS1oZWFkPVwiQWNjb3VudFwiPlxuICAgICAgICAgICAgICAgIDxhIFtyb3V0ZXJMaW5rXT1cIlsnLycgKyBzdWJzY3JpcHRpb24/LnNsdWcgKyByb3V0ZXJzLmFjY291bnRJbmZvLCBvcHBvcnR1bml0aWVzLmNybV9hY2NvdW50Py5pZF1cIiBjbGFzcz1cIm5hbWUtbGlua1wiPlxuICAgICAgICAgICAgICAgICAgPHNwYW4gW25nYlRvb2x0aXBdPVwib3Bwb3J0dW5pdGllcy5jcm1fYWNjb3VudD8ubmFtZVwiPnt7IG9wcG9ydHVuaXRpZXMuY3JtX2FjY291bnQ/Lm5hbWUgfCB0ZXh0VHJ1bmNhdGU6MjAgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgICA8L3RkPlxuICAgICAgICAgICAgICA8dGQgZGF0YS1oZWFkPVwiVGl0bGVcIj5cbiAgICAgICAgICAgICAgICA8YSBbbmdiVG9vbHRpcF09XCJvcHBvcnR1bml0aWVzPy50aXRsZVwiICpuZ0lmPVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYXNBY2Nlc3MgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wcG9ydHVuaXRpZXM/Lm93bmVyX2lkID09PSB1c2VySWQgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoZWNrUGVybWlzc2lvbignUGFnZXMuUHJvZHVjdC5DUk0uUm9sZS5BZG1pbicpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiIFtyb3V0ZXJMaW5rXT1cIltcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcvJyArIHN1YnNjcmlwdGlvbj8uc2x1ZyArIHJvdXRlcnMub3Bwb3J0dW5pdHlJbmZvLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3Bwb3J0dW5pdGllcy5pZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBdXCI+XG4gICAgICAgICAgICAgICAgPHNwYW4+e3sgb3Bwb3J0dW5pdGllcz8udGl0bGUgfCB0ZXh0VHJ1bmNhdGU6IDIwIH19IDwvc3Bhbj5cbiAgICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgICA8L3RkPlxuICAgICAgICAgICAgICA8dGQgZGF0YS1oZWFkPVwiT25lIFRpbWUgQW1vdW50XCI+IHt7IG9wcG9ydHVuaXRpZXMub25lX3RpbWVfYW1vdW50IC8gMTAwIHwgY3VycmVuY3k6IChvcHBvcnR1bml0aWVzLm1haW5fY3VycmVuY3kgfHwgb3Bwb3J0dW5pdGllcy5jdXJyZW5jeSkgfX0gPC90ZD5cbiAgICAgICAgICAgICAgPHRkIGRhdGEtaGVhZD1cIk1vbnRobHkgQW1vdW50XCIgY2xhc3M9XCJleHBlY3RlZC1tcnJcIj4ge3sgb3Bwb3J0dW5pdGllcy5tb250aGx5X2Ftb3VudCAvIDEwMCB8IGN1cnJlbmN5OiAob3Bwb3J0dW5pdGllcy5tYWluX2N1cnJlbmN5IHx8IG9wcG9ydHVuaXRpZXMuY3VycmVuY3kpIH19IDwvdGQ+XG4gICAgICAgICAgICAgIDx0ZCBkYXRhLWhlYWQ9XCJXaW4gQ2hhbmNlXCI+IHt7IG9wcG9ydHVuaXRpZXMud2luX2NoYW5jZXMgLyAxMDAgfCBwZXJjZW50IH19IDxzcGFuIGNsYXNzPVwidGV4dC1kYW5nZXJcIlxuICAgICAgICAgICAgICAgICAgKm5nSWY9XCJvcHBvcnR1bml0aWVzLmNhbmNlbGxlZFwiPiFDYW5jZWxsZWQhPC9zcGFuPlxuICAgICAgICAgICAgICA8L3RkPlxuICAgICAgICAgICAgPC90cj5cbiAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICAgIDxuZy10ZW1wbGF0ZSBwVGVtcGxhdGU9XCJmb290ZXJcIj5cbiAgICAgICAgICAgIDx0ciAqbmdJZj1cImFjdGl2ZU9wcG9ydHVuaXRpZXM/Lmxlbmd0aFwiPlxuICAgICAgICAgICAgICA8dGQ+PC90ZD5cbiAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICAgIDx0ZD48L3RkPlxuICAgICAgICAgICAgICA8dGQgY2xhc3M9XCJmdy1ib2xkIGV4cGVjdGVkLW1yclwiPlxuICAgICAgICAgICAgICAgIDxzdHJvbmc+e3sgYWN0aXZlT3Bwb3J0dW5pdGllc1RvdGFsPy50b3RhbF9tcnIgLyAxMDAgfCBjdXJyZW5jeTogJ1VTRCcgfX08L3N0cm9uZz5cbiAgICAgICAgICAgICAgPC90ZD5cbiAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICA8L3RyPlxuICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgIDwvcC10YWJsZT5cbiAgICAgICAgPHNwYW4gY2xhc3M9XCJ0b3RhbC1yZWNvcmRzLWNvdW50XCIgKm5nSWY9XCJhY3RpdmVPcHBvcnR1bml0aWVzLmxlbmd0aCAhPT0gMFwiPnt7ICdMYWJlbC5Ub3RhbCcgfCB0cmFuc2xvY28gfX06IHt7IGFjdGl2ZU9wcG9ydHVuaXRpZXMubGVuZ3RoIH19PC9zcGFuPlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2ICpuZ0lmPVwiYWN0aXZlT3Bwb3J0dW5pdGllcz8ubGVuZ3RoID09PSAwXCI+XG4gICAgICAgIDxwdy1uby1kYXRhIFt3aXRoSW1hZ2VdPVwidHJ1ZVwiIFttZXNzYWdlXT1cIidDcm0uU3VtbWFyeS5Ob0luc2lnaHRNZXNzYWdlJyB8IHRyYW5zbG9jb1wiPiA8L3B3LW5vLWRhdGE+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDwhLS0gTGFzdCBBY3Rpdml0aWVzIC0tPlxuICAgIDxkaXYgY2xhc3M9XCJjb2wtMTIgY29sLW1kLTYgbWItMyBhbmFseXRpY3NcIj5cbiAgICAgIDxoNSBjbGFzcz1cImFjY29yZGlvbi1oZWFkaW5nXCI+TGF0ZXN0IEFjdGl2aXRpZXM8L2g1PlxuICAgICAgPGRpdiBjbGFzcz1cInctMTAwIHRleHQtY2VudGVyIG10LTNcIj5cbiAgICAgICAgPG5nLXRlbXBsYXRlIFtuZ0lmXT1cIiFhY2NvdW50TGFzdEFjdGl2aXRpZXNMb2FkZWRcIj5cbiAgICAgICAgICA8cC1wcm9ncmVzc1NwaW5uZXIgc3Ryb2tlV2lkdGg9XCIyXCI+IDwvcC1wcm9ncmVzc1NwaW5uZXI+XG4gICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3M9XCJwcmltZW5nLWRhdGF0YWJsZS1jb250YWluZXIgdGFibGUtcmVzcG9uc2l2ZVwiXG4gICAgICAgICpuZ0lmPVwiYWNjb3VudExhc3RBY3Rpdml0aWVzPy5sZW5ndGhcIj5cbiAgICAgICAgPHAtdGFibGUgY2xhc3M9XCJ0YWJsZVwiXG4gICAgICAgICAgI2R0XG4gICAgICAgICAgW3ZhbHVlXT1cImFjY291bnRMYXN0QWN0aXZpdGllc1wiXG4gICAgICAgICAgW3BhZ2luYXRvcl09XCJ0cnVlXCJcbiAgICAgICAgICBbcm93c109XCIyMFwiXG4gICAgICAgICAgW3RvdGFsUmVjb3Jkc109XCJhY2NvdW50TGFzdEFjdGl2aXRpZXMubGVuZ3RoXCI+XG4gICAgICAgICAgPG5nLXRlbXBsYXRlIHBUZW1wbGF0ZT1cImhlYWRlclwiPlxuICAgICAgICAgICAgPHRyPlxuICAgICAgICAgICAgICA8dGggc2NvcGU9XCJ0cnVlXCI+e3sgJ0NybS5BY2NvdW50TWVzc2FnZS5Pd25lcicgfCB0cmFuc2xvY28gfX08L3RoPlxuICAgICAgICAgICAgICA8dGggc2NvcGU9XCJ0cnVlXCI+e3sgJ0NybS5BY2NvdW50TWVzc2FnZS5BY2NvdW50JyB8IHRyYW5zbG9jbyB9fTwvdGg+XG4gICAgICAgICAgICAgIDx0aCBzY29wZT1cInRydWVcIj57eyAnQ3JtLkFjY291bnRNZXNzYWdlLkNvbnRhY3QnIHwgdHJhbnNsb2NvIH19PC90aD5cbiAgICAgICAgICAgICAgPHRoIHNjb3BlPVwidHJ1ZVwiPnt7ICdDcm0uQWNjb3VudE1lc3NhZ2UuQWN0aW9uJyB8IHRyYW5zbG9jbyB9fTwvdGg+XG4gICAgICAgICAgICAgIDx0aCBzY29wZT1cInRydWVcIj57eyAnQ3JtLkFjY291bnRNZXNzYWdlLldoZW4nIHwgdHJhbnNsb2NvIH19PC90aD5cbiAgICAgICAgICAgIDwvdHI+XG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiYm9keVwiIGxldC1hY3Rpdml0aWVzPlxuICAgICAgICAgICAgPHRyPlxuICAgICAgICAgICAgICA8dGQgZGF0YS1oZWFkPVwiT3duZXJcIj4ge3sgYWN0aXZpdGllcy5vd25lcj8uZmlyc3RfbmFtZS5jaGFyQXQoMCkgfX0uIHt7IGFjdGl2aXRpZXMub3duZXI/Lmxhc3RfbmFtZSB9fSA8L3RkPlxuICAgICAgICAgICAgICA8dGQgZGF0YS1oZWFkPVwiQWNjb3VudFwiPlxuICAgICAgICAgICAgICAgIDxhIFtyb3V0ZXJMaW5rXT1cIlsnLycgKyBzdWJzY3JpcHRpb24/LnNsdWcgKyByb3V0ZXJzLmFjY291bnRJbmZvLCBhY3Rpdml0aWVzLmNybV9hY2NvdW50X2lkXVwiIGNsYXNzPVwibmFtZS1saW5rXCI+XG4gICAgICAgICAgICAgICAgICA8c3BhbiBbbmdiVG9vbHRpcF09XCJhY3Rpdml0aWVzLmNybV9hY2NvdW50Py5uYW1lXCI+e3sgYWN0aXZpdGllcy5jcm1fYWNjb3VudD8ubmFtZSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICA8L2E+XG4gICAgICAgICAgICAgIDwvdGQ+XG4gICAgICAgICAgICAgIDx0ZCBkYXRhLWhlYWQ9XCJDb250YWN0XCI+XG4gICAgICAgICAgICAgICAgPGEgW3JvdXRlckxpbmtdPVwiWycvJyArIHN1YnNjcmlwdGlvbj8uc2x1ZyArIHJvdXRlcnMuY29udGFjdEluZm8sIGFjdGl2aXRpZXMuY3JtX2NvbnRhY3RfaWRdXCIgY2xhc3M9XCJuYW1lLWxpbmtcIj5cbiAgICAgICAgICAgICAgICAgIDxzcGFuIFtuZ2JUb29sdGlwXT1cImFjdGl2aXRpZXMuY3JtX2NvbnRhY3QgPyBhY3Rpdml0aWVzLmNybV9jb250YWN0LmZpcnN0X25hbWUgKyAnICcgKyBhY3Rpdml0aWVzLmNybV9jb250YWN0Lmxhc3RfbmFtZSA6ICcnXCI+e3sgKGFjdGl2aXRpZXMuY3JtX2NvbnRhY3Q/LmZpcnN0X25hbWUgKyAnICcgKyBhY3Rpdml0aWVzLmNybV9jb250YWN0Py5sYXN0X25hbWUpIHwgdGV4dFRydW5jYXRlOjIwIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgIDwvYT5cbiAgICAgICAgICAgICAgPC90ZD5cbiAgICAgICAgICAgICAgPHRkIGRhdGEtaGVhZD1cIkFjdGlvblwiPlxuICAgICAgICAgICAgICAgIDxzcGFuIFtuZ2JUb29sdGlwXT1cImFjdGl2aXRpZXMuY29tbWVudFwiIFthcHBEeW5hbWljQmFkZ2VdPVwie1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGl0ZW1zQXJyYXk6IGFjdGlvbk5hbWVzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGl0ZW06IGFjdGl2aXRpZXMuY3JtX2FjdGlvbj8ubmFtZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVwiXG4gICAgICAgICAgICAgICAgICBjb2xvcj1cImJsdWUtZ3JleVwiXG4gICAgICAgICAgICAgICAgICBjbGFzcz1cImJhZGdlXCI+e3sgYWN0aXZpdGllcy5jcm1fYWN0aW9uPy5uYW1lIH19PC9zcGFuPlxuICAgICAgICAgICAgICA8L3RkPlxuICAgICAgICAgICAgICA8dGQgZGF0YS1oZWFkPVwiV2hlblwiPnt7IGFjdGl2aXRpZXMud2hlbiB8IGRhdGU6J2RkLU1NTS1ZWVlZJyB9fTwvdGQ+XG4gICAgICAgICAgICA8L3RyPlxuICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgIDwvcC10YWJsZT5cbiAgICAgICAgPHNwYW4gY2xhc3M9XCJ0b3RhbC1yZWNvcmRzLWNvdW50XCIgKm5nSWY9XCJhY2NvdW50TGFzdEFjdGl2aXRpZXMubGVuZ3RoICE9PSAwXCI+e3sgJ0xhYmVsLlRvdGFsJyB8IHRyYW5zbG9jbyB9fToge3sgYWNjb3VudExhc3RBY3Rpdml0aWVzLmxlbmd0aCB9fTwvc3Bhbj5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiAqbmdJZj1cImFjY291bnRMYXN0QWN0aXZpdGllcz8ubGVuZ3RoID09PSAwICYmIGFjY291bnRMYXN0QWN0aXZpdGllc0xvYWRlZFwiPlxuICAgICAgICA8cHctbm8tZGF0YSBbd2l0aEltYWdlXT1cInRydWVcIiBbbWVzc2FnZV09XCInQ3JtLlN1bW1hcnkuTm9JbnNpZ2h0TWVzc2FnZScgfCB0cmFuc2xvY29cIj4gPC9wdy1uby1kYXRhPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG5cbiAgICA8IS0tIEFjY291bnRzIGF0IHJpc2sgLS0+XG4gICAgPGRpdiBjbGFzcz1cImNvbC0xMiBjb2wtbWQtNiBtYi0zIGFuYWx5dGljc1wiPlxuICAgICAgPGg1IGNsYXNzPVwiYWNjb3JkaW9uLWhlYWRpbmdcIj5BY2NvdW50cyBhdCBSaXNrPC9oNT5cbiAgICAgIDxkaXYgY2xhc3M9XCJ3LTEwMCB0ZXh0LWNlbnRlciBtdC0zXCI+XG4gICAgICAgIDxuZy10ZW1wbGF0ZSBbbmdJZl09XCIhYWNjb3VudEF0Umlza0RldGFpbHNMb2FkZWRcIj5cbiAgICAgICAgICA8cC1wcm9ncmVzc1NwaW5uZXIgc3Ryb2tlV2lkdGg9XCIyXCI+IDwvcC1wcm9ncmVzc1NwaW5uZXI+XG4gICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3M9XCJwcmltZW5nLWRhdGF0YWJsZS1jb250YWluZXIgdGFibGUtcmVzcG9uc2l2ZVwiXG4gICAgICAgICpuZ0lmPVwiYWNjb3VudEF0Umlzaz8ubGVuZ3RoXCI+XG4gICAgICAgIDxwLXRhYmxlIGNsYXNzPVwidGFibGVcIlxuICAgICAgICAgICNkdFxuICAgICAgICAgIFt2YWx1ZV09XCJhY2NvdW50QXRSaXNrXCJcbiAgICAgICAgICBbcGFnaW5hdG9yXT1cInRydWVcIlxuICAgICAgICAgIFtyb3dzXT1cIjIwXCJcbiAgICAgICAgICBbdG90YWxSZWNvcmRzXT1cImFjY291bnRBdFJpc2subGVuZ3RoXCI+XG4gICAgICAgICAgPG5nLXRlbXBsYXRlIHBUZW1wbGF0ZT1cImhlYWRlclwiPlxuICAgICAgICAgICAgPHRyPlxuICAgICAgICAgICAgICA8dGggc2NvcGU9XCJ0cnVlXCI+e3sgJ0NybS5TdW1tYXJ5LkFjY291bnQnIHwgdHJhbnNsb2NvIH19PC90aD5cbiAgICAgICAgICAgICAgPHRoIHNjb3BlPVwidHJ1ZVwiIGNsYXNzPVwibXJyLWhlYWRlclwiPnt7ICdDcm0uQWNjb3VudE1lc3NhZ2UuTVJSJyB8IHRyYW5zbG9jbyB9fTwvdGg+XG4gICAgICAgICAgICAgIDx0aCBzY29wZT1cInRydWVcIj57eyAnQ3JtLkFjY291bnRNZXNzYWdlLlF1YXJ0ZXInIHwgdHJhbnNsb2NvIH19PC90aD5cbiAgICAgICAgICAgICAgPHRoIHNjb3BlPVwidHJ1ZVwiPiB7eyAnQ3JtLkFjY291bnRNZXNzYWdlLk1vbnRoJyB8IHRyYW5zbG9jbyB9fTwvdGg+XG4gICAgICAgICAgICAgIDx0aCBzY29wZT1cInRydWVcIj57eyAnQ3JtLkFjY291bnRNZXNzYWdlLlNpZ25VcEF0JyB8IHRyYW5zbG9jbyB9fTwvdGg+XG4gICAgICAgICAgICA8L3RyPlxuICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgICAgPG5nLXRlbXBsYXRlIHBUZW1wbGF0ZT1cImJvZHlcIlxuICAgICAgICAgICAgbGV0LWFjY291bnRcbiAgICAgICAgICAgIGxldC1pPVwicm93SW5kZXhcIj5cbiAgICAgICAgICAgIDwhLS0gVG90YWxzIHJvdyBhdCB0aGUgdG9wIChmaXJzdCByb3cpIC0tPlxuICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImkgPT09IDAgJiYgYWNjb3VudEF0Umlzaz8ubGVuZ3RoXCI+XG4gICAgICAgICAgICAgIDx0ciBjbGFzcz1cInRvdGFscy1yb3dcIj5cbiAgICAgICAgICAgICAgICA8dGQ+PC90ZD5cbiAgICAgICAgICAgICAgICA8dGQgY2xhc3M9XCJmdy1ib2xkIGV4cGVjdGVkLW1yclwiPlxuICAgICAgICAgICAgICAgICAgPHN0cm9uZz57eyBhY2NvdW50QXRSaXNrVG90YWw/LnRvdGFsX21yciAvIDEwMCB8IGN1cnJlbmN5OiAnVVNEJyB9fTwvc3Ryb25nPlxuICAgICAgICAgICAgICAgIDwvdGQ+XG4gICAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICAgIDwvdHI+XG4gICAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgIDwhLS0gUmVndWxhciBkYXRhIHJvdyAtLT5cbiAgICAgICAgICAgIDx0cj5cbiAgICAgICAgICAgICAgPHRkIGRhdGEtaGVhZD1cIkFjY291bnRcIj5cbiAgICAgICAgICAgICAgICA8YSBbcm91dGVyTGlua109XCJbJy8nICsgc3Vic2NyaXB0aW9uPy5zbHVnICsgcm91dGVycy5hY2NvdW50SW5mbywgYWNjb3VudC5jcm1fYWNjb3VudF9pZF1cIiBjbGFzcz1cIm5hbWUtbGlua1wiPlxuICAgICAgICAgICAgICAgICAgPHNwYW4gW25nYlRvb2x0aXBdPVwiYWNjb3VudC5jcm1fYWNjb3VudF9uYW1lXCI+e3sgYWNjb3VudD8uY3JtX2FjY291bnRfbmFtZSB8IHRleHRUcnVuY2F0ZToyMCB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICA8L2E+XG4gICAgICAgICAgICAgIDwvdGQ+XG4gICAgICAgICAgICAgIDx0ZCBkYXRhLWhlYWQ9XCJNUlJcIiBjbGFzcz1cImV4cGVjdGVkLW1yclwiPlxuICAgICAgICAgICAgICAgIHt7IGFjY291bnQuZXhwZWN0ZWRfbXJyIC8gMTAwIHwgY3VycmVuY3k6IChhY2NvdW50Lm1haW5fY3VycmVuY3kgfHwgYWNjb3VudC5jdXJyZW5jeSkgfX1cbiAgICAgICAgICAgICAgPC90ZD5cbiAgICAgICAgICAgICAgPHRkIGRhdGEtaGVhZD1cIlF1YXJ0ZXJcIiBbbmdDbGFzc109XCJ7J21vbnRoLXF1YXJ0ZXItdGV4dCBmdy1ib2xkJzogYWNjb3VudC5zZXNzaW9uc19sYXN0X3F1YXJ0ZXIgPiAxNX1cIj57eyBhY2NvdW50LnNlc3Npb25zX2xhc3RfcXVhcnRlciB9fTwvdGQ+XG4gICAgICAgICAgICAgIDx0ZCBkYXRhLWhlYWQ9XCJNb250aFwiIFtuZ0NsYXNzXT1cInsnbW9udGgtcXVhcnRlci10ZXh0IGZ3LWJvbGQnOiBhY2NvdW50LnNlc3Npb25zX2xhc3RfbW9udGggPiA1fVwiPnt7IGFjY291bnQuc2Vzc2lvbnNfbGFzdF9tb250aCB9fTwvdGQ+XG4gICAgICAgICAgICAgIDx0ZCBkYXRhLWhlYWQ9XCJTaWduVXBBdFwiPlxuICAgICAgICAgICAgICAgIHt7IGFjY291bnQuc2lnbmVkX3VwX2F0IHwgZGF0ZUZvcm1hdCB9fVxuICAgICAgICAgICAgICA8L3RkPlxuICAgICAgICAgICAgPC90cj5cbiAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICAgIDxuZy10ZW1wbGF0ZSBwVGVtcGxhdGU9XCJmb290ZXJcIj5cbiAgICAgICAgICAgIDx0ciAqbmdJZj1cImFjY291bnRBdFJpc2s/Lmxlbmd0aFwiPlxuICAgICAgICAgICAgICA8dGQ+PC90ZD5cbiAgICAgICAgICAgICAgPHRkIGNsYXNzPVwiZnctYm9sZCBleHBlY3RlZC1tcnJcIj5cbiAgICAgICAgICAgICAgICA8c3Ryb25nPnt7IGFjY291bnRBdFJpc2tUb3RhbD8udG90YWxfbXJyIC8gMTAwIHwgY3VycmVuY3k6ICdVU0QnIH19PC9zdHJvbmc+XG4gICAgICAgICAgICAgIDwvdGQ+XG4gICAgICAgICAgICAgIDx0ZD48L3RkPlxuICAgICAgICAgICAgICA8dGQ+PC90ZD5cbiAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICA8L3RyPlxuICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgIDwvcC10YWJsZT5cbiAgICAgICAgPHNwYW4gY2xhc3M9XCJ0b3RhbC1yZWNvcmRzLWNvdW50XCIgICpuZ0lmPVwiYWNjb3VudEF0Umlzay5sZW5ndGggIT09IDBcIj57eyAnTGFiZWwuVG90YWwnIHwgdHJhbnNsb2NvIH19OiB7eyBhY2NvdW50QXRSaXNrLmxlbmd0aCB9fTwvc3Bhbj5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiAqbmdJZj1cImFjY291bnRBdFJpc2s/Lmxlbmd0aCA9PT0gMFwiPlxuICAgICAgICA8cHctbm8tZGF0YSBbd2l0aEltYWdlXT1cInRydWVcIiBbbWVzc2FnZV09XCInQ3JtLlN1bW1hcnkuTm9JbnNpZ2h0TWVzc2FnZScgfCB0cmFuc2xvY29cIj4gPC9wdy1uby1kYXRhPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG5cbiAgICA8IS0tIENvbnRyYWN0IHJlbmV3YWwgLS0+XG4gICAgPGRpdiBjbGFzcz1cImNvbC0xMiBjb2wtbWQtNiBtYi0zIGFuYWx5dGljc1wiPlxuICAgICAgPGg1IGNsYXNzPVwiYWNjb3JkaW9uLWhlYWRpbmdcIj5BY2NvdW50cyBhdCAxLVllYXIgTWFyazwvaDU+XG4gICAgICA8ZGl2IGNsYXNzPVwidy0xMDAgdGV4dC1jZW50ZXIgbXQtM1wiPlxuICAgICAgICA8bmctdGVtcGxhdGUgW25nSWZdPVwiIWNvbnRhY3RSZW5ld2FsTG9hZGVkXCI+XG4gICAgICAgICAgPHAtcHJvZ3Jlc3NTcGlubmVyIHN0cm9rZVdpZHRoPVwiMlwiPiA8L3AtcHJvZ3Jlc3NTcGlubmVyPlxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwicHJpbWVuZy1kYXRhdGFibGUtY29udGFpbmVyIHRhYmxlLXJlc3BvbnNpdmVcIlxuICAgICAgICAqbmdJZj1cIkNvbnRyYWN0UmVuZXdhbD8ubGVuZ3RoXCI+XG4gICAgICAgIDxwLXRhYmxlIGNsYXNzPVwidGFibGVcIlxuICAgICAgICAgICNkdFxuICAgICAgICAgIFt2YWx1ZV09XCJDb250cmFjdFJlbmV3YWxcIlxuICAgICAgICAgIFtwYWdpbmF0b3JdPVwidHJ1ZVwiXG4gICAgICAgICAgW3Jvd3NdPVwiMjBcIlxuICAgICAgICAgIFt0b3RhbFJlY29yZHNdPVwiQ29udHJhY3RSZW5ld2FsLmxlbmd0aFwiPlxuICAgICAgICAgIDxuZy10ZW1wbGF0ZSBwVGVtcGxhdGU9XCJoZWFkZXJcIj5cbiAgICAgICAgICAgIDx0cj5cbiAgICAgICAgICAgICAgPHRoIHNjb3BlPVwidHJ1ZVwiPnt7ICdDcm0uQWNjb3VudE1lc3NhZ2UuQWNjb3VudCcgfCB0cmFuc2xvY28gfX08L3RoPlxuICAgICAgICAgICAgICA8dGggc2NvcGU9XCJ0cnVlXCIgY2xhc3M9XCJtcnItaGVhZGVyXCI+e3sgJ0NybS5BY2NvdW50TWVzc2FnZS5NUlInIHwgdHJhbnNsb2NvIH19PC90aD5cblxuICAgICAgICAgICAgICA8dGggc2NvcGU9XCJ0cnVlXCI+e3sgJ0NybS5BY2NvdW50TWVzc2FnZS5RdWFydGVyJyB8IHRyYW5zbG9jbyB9fTwvdGg+XG4gICAgICAgICAgICAgIDx0aCBzY29wZT1cInRydWVcIj4ge3sgJ0NybS5BY2NvdW50TWVzc2FnZS5Nb250aCcgfCB0cmFuc2xvY28gfX08L3RoPlxuXG4gICAgICAgICAgICAgIDx0aCBzY29wZT1cInRydWVcIj57eyAnQ3JtLkFjY291bnRNZXNzYWdlLlNpZ25VcEF0JyB8IHRyYW5zbG9jbyB9fTwvdGg+XG4gICAgICAgICAgICAgIDx0aCBzY29wZT1cInRydWVcIj57eyAnQ3JtLkFjY291bnRNZXNzYWdlLkNDRXhwQXQnIHwgdHJhbnNsb2NvIH19PC90aD5cbiAgICAgICAgICAgIDwvdHI+XG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiYm9keVwiXG4gICAgICAgICAgICBsZXQtYWNjb3VudFxuICAgICAgICAgICAgbGV0LWk9XCJyb3dJbmRleFwiPlxuICAgICAgICAgICAgPCEtLSBUb3RhbHMgcm93IGF0IHRoZSB0b3AgKGZpcnN0IHJvdykgLS0+XG4gICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiaSA9PT0gMCAmJiBDb250cmFjdFJlbmV3YWw/Lmxlbmd0aFwiPlxuICAgICAgICAgICAgICA8dHIgY2xhc3M9XCJ0b3RhbHMtcm93XCI+XG4gICAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICAgICAgPHRkIGNsYXNzPVwiZnctYm9sZCBleHBlY3RlZC1tcnJcIj5cbiAgICAgICAgICAgICAgICAgIDxzdHJvbmc+e3sgY29udHJhY3RSZW5ld2FsVG90YWw/LnRvdGFsX21yciAvIDEwMCB8IGN1cnJlbmN5OiAnVVNEJyB9fTwvc3Ryb25nPlxuICAgICAgICAgICAgICAgIDwvdGQ+XG4gICAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICAgIDwvdHI+XG4gICAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgIDwhLS0gUmVndWxhciBkYXRhIHJvdyAtLT5cbiAgICAgICAgICAgIDx0cj5cbiAgICAgICAgICAgICAgPHRkIGRhdGEtaGVhZD1cIkFjY291bnRcIj5cbiAgICAgICAgICAgICAgICA8YSBbcm91dGVyTGlua109XCJbJy8nICsgc3Vic2NyaXB0aW9uPy5zbHVnICsgcm91dGVycy5hY2NvdW50SW5mbywgYWNjb3VudC5jcm1fYWNjb3VudF9pZF1cIiBjbGFzcz1cIm5hbWUtbGlua1wiPlxuICAgICAgICAgICAgICAgICAgPHNwYW4gW25nYlRvb2x0aXBdPVwiYWNjb3VudC5jcm1fYWNjb3VudF9uYW1lXCI+e3sgYWNjb3VudC5jcm1fYWNjb3VudF9uYW1lIHwgdGV4dFRydW5jYXRlOjIwIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgIDwvYT5cbiAgICAgICAgICAgICAgPC90ZD5cbiAgICAgICAgICAgICAgPHRkIGRhdGEtaGVhZD1cIk1SUlwiIGNsYXNzPVwiZXhwZWN0ZWQtbXJyXCI+XG4gICAgICAgICAgICAgICAge3sgYWNjb3VudC5leHBlY3RlZF9tcnIgLyAxMDAgfCBjdXJyZW5jeTogKGFjY291bnQubWFpbl9jdXJyZW5jeSB8fCBhY2NvdW50LmN1cnJlbmN5KSB9fVxuICAgICAgICAgICAgICA8L3RkPlxuICAgICAgICAgICAgICA8dGQgZGF0YS1oZWFkPVwiUXVhcnRlclwiIFtuZ0NsYXNzXT1cInsnbW9udGgtcXVhcnRlci10ZXh0IGZ3LWJvbGQnOiBhY2NvdW50LnNlc3Npb25zX2xhc3RfcXVhcnRlciA+IDE1fVwiPnt7IGFjY291bnQuc2Vzc2lvbnNfbGFzdF9xdWFydGVyIH19PC90ZD5cbiAgICAgICAgICAgICAgPHRkIGRhdGEtaGVhZD1cIk1vbnRoXCIgW25nQ2xhc3NdPVwieydtb250aC1xdWFydGVyLXRleHQgZnctYm9sZCc6IGFjY291bnQuc2Vzc2lvbnNfbGFzdF9tb250aCA+IDV9XCI+e3sgYWNjb3VudC5zZXNzaW9uc19sYXN0X21vbnRoIH19PC90ZD5cbiAgICAgICAgICAgICAgPHRkIGRhdGEtaGVhZD1cIlNpZ25VcEF0XCI+XG4gICAgICAgICAgICAgICAge3sgYWNjb3VudC5zaWduZWRfdXBfYXQgfCBkYXRlRm9ybWF0IH19XG4gICAgICAgICAgICAgIDwvdGQ+XG4gICAgICAgICAgICAgIDx0ZCBkYXRhLWhlYWQ9XCJFeHBBdFwiIFtuZ0NsYXNzXT1cInsndGV4dC1kYW5nZXInOiBhY2NvdW50LmNjX2V4cGlyaW5nX2F0IHwgaXNQYXN0RGF0ZX1cIj5cbiAgICAgICAgICAgICAgICB7eyBhY2NvdW50LmNjX2V4cGlyaW5nX2F0IHwgZGF0ZUZvcm1hdCB9fVxuICAgICAgICAgICAgICAgIDxzcGFuICpuZ0lmPVwiYWNjb3VudC5jY19leHBpcmluZ19hdCB8IGlzUGFzdERhdGVcIiBjbGFzcz1cInRvb2x0aXAtd3JhcFwiIFthcHBlbmRUb109XCInYm9keSdcIiBbcFRvb2x0aXBdPVwiJ0FkbWluLkluc2lnaHQuVG9vbHRpcC5FeHBBdE1lc3NhZ2UnIHwgdHJhbnNsb2NvXCIgdG9vbHRpcFBvc2l0aW9uPVwidG9wXCI+XG4gICAgICAgICAgICAgICAgICA8aSBjbGFzcz1cImZhcyBmYS1pbmZvLWNpcmNsZSBtbC0xXCI+PC9pPlxuICAgICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgPC90ZD5cbiAgICAgICAgICAgIDwvdHI+XG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiZm9vdGVyXCI+XG4gICAgICAgICAgICA8dHIgKm5nSWY9XCJDb250cmFjdFJlbmV3YWw/Lmxlbmd0aFwiPlxuICAgICAgICAgICAgICA8dGQ+PC90ZD5cbiAgICAgICAgICAgICAgPHRkIGNsYXNzPVwiZnctYm9sZCBleHBlY3RlZC1tcnJcIj5cbiAgICAgICAgICAgICAgICA8c3Ryb25nPnt7IGNvbnRyYWN0UmVuZXdhbFRvdGFsPy50b3RhbF9tcnIgLyAxMDAgfCBjdXJyZW5jeTogJ1VTRCcgfX08L3N0cm9uZz5cbiAgICAgICAgICAgICAgPC90ZD5cbiAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICAgIDx0ZD48L3RkPlxuICAgICAgICAgICAgICA8dGQ+PC90ZD5cbiAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICA8L3RyPlxuICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgIDwvcC10YWJsZT5cbiAgICAgICAgPHNwYW4gY2xhc3M9XCJ0b3RhbC1yZWNvcmRzLWNvdW50XCIgKm5nSWY9XCJDb250cmFjdFJlbmV3YWwubGVuZ3RoICE9PSAwXCI+e3sgJ0xhYmVsLlRvdGFsJyB8IHRyYW5zbG9jbyB9fToge3sgQ29udHJhY3RSZW5ld2FsLmxlbmd0aCB9fTwvc3Bhbj5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiAqbmdJZj1cIkNvbnRyYWN0UmVuZXdhbD8ubGVuZ3RoID09PSAwXCI+XG4gICAgICAgIDxwdy1uby1kYXRhIFt3aXRoSW1hZ2VdPVwidHJ1ZVwiIFttZXNzYWdlXT1cIidDcm0uU3VtbWFyeS5Ob0luc2lnaHRNZXNzYWdlJyB8IHRyYW5zbG9jb1wiPiA8L3B3LW5vLWRhdGE+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cblxuIDwhLS0gQ3JlZGl0IENhcmRzIEV4cGlyaW5nIC0tPlxuICAgIDxkaXYgY2xhc3M9XCJjb2wtMTIgY29sLW1kLTYgbWItMyBhbmFseXRpY3NcIj5cbiAgICAgIDxoNSBjbGFzcz1cImFjY29yZGlvbi1oZWFkaW5nXCI+QWNjb3VudHMgd2l0aCBFeHBpcmluZyBDcmVkaXQgQ2FyZHM8L2g1PlxuICAgICAgPGRpdiBjbGFzcz1cInctMTAwIHRleHQtY2VudGVyIG10LTNcIj5cbiAgICAgICAgPG5nLXRlbXBsYXRlIFtuZ0lmXT1cIiFjcmVkaXRDYXJkRXhwaXJpbmdEZXRhaWxzTG9hZGVkXCI+XG4gICAgICAgICAgPHAtcHJvZ3Jlc3NTcGlubmVyIHN0cm9rZVdpZHRoPVwiMlwiPiA8L3AtcHJvZ3Jlc3NTcGlubmVyPlxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwicHJpbWVuZy1kYXRhdGFibGUtY29udGFpbmVyIHRhYmxlLXJlc3BvbnNpdmVcIlxuICAgICAgICAqbmdJZj1cImNyZWRpdENhcmRFeHBpcmluZz8ubGVuZ3RoXCI+XG4gICAgICAgIDxwLXRhYmxlIGNsYXNzPVwidGFibGVcIlxuICAgICAgICAgICNkdFxuICAgICAgICAgIFt2YWx1ZV09XCJjcmVkaXRDYXJkRXhwaXJpbmdcIlxuICAgICAgICAgIFtwYWdpbmF0b3JdPVwidHJ1ZVwiXG4gICAgICAgICAgW3Jvd3NdPVwiMjBcIlxuICAgICAgICAgIFt0b3RhbFJlY29yZHNdPVwiY3JlZGl0Q2FyZEV4cGlyaW5nLmxlbmd0aFwiPlxuICAgICAgICAgIDxuZy10ZW1wbGF0ZSBwVGVtcGxhdGU9XCJoZWFkZXJcIj5cbiAgICAgICAgICAgIDx0cj5cbiAgICAgICAgICAgICAgPHRoIHNjb3BlPVwidHJ1ZVwiPnt7ICdDcm0uQWNjb3VudE1lc3NhZ2UuQWNjb3VudCcgfCB0cmFuc2xvY28gfX08L3RoPlxuICAgICAgICAgICAgICA8dGggc2NvcGU9XCJ0cnVlXCIgY2xhc3M9XCJtcnItaGVhZGVyXCI+e3sgJ0NybS5BY2NvdW50TWVzc2FnZS5NUlInIHwgdHJhbnNsb2NvIH19PC90aD5cbiAgICAgICAgICAgICAgPHRoIHNjb3BlPVwidHJ1ZVwiPnt7ICdDcm0uQWNjb3VudE1lc3NhZ2UuU2lnblVwQXQnIHwgdHJhbnNsb2NvIH19PC90aD5cbiAgICAgICAgICAgICAgPHRoIHNjb3BlPVwidHJ1ZVwiPnt7ICdDcm0uQWNjb3VudE1lc3NhZ2UuQ0NFeHBBdCcgfCB0cmFuc2xvY28gfX08L3RoPlxuICAgICAgICAgICAgPC90cj5cbiAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICAgIDxuZy10ZW1wbGF0ZSBwVGVtcGxhdGU9XCJib2R5XCJcbiAgICAgICAgICAgIGxldC1hY2NvdW50XG4gICAgICAgICAgICBsZXQtaT1cInJvd0luZGV4XCI+XG4gICAgICAgICAgICA8IS0tIFRvdGFscyByb3cgYXQgdGhlIHRvcCAoZmlyc3Qgcm93KSAtLT5cbiAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJpID09PSAwICYmIGNyZWRpdENhcmRFeHBpcmluZz8ubGVuZ3RoXCI+XG4gICAgICAgICAgICAgIDx0ciBjbGFzcz1cInRvdGFscy1yb3dcIj5cbiAgICAgICAgICAgICAgICA8dGQ+PC90ZD5cbiAgICAgICAgICAgICAgICA8dGQgY2xhc3M9XCJmdy1ib2xkIGV4cGVjdGVkLW1yclwiPlxuICAgICAgICAgICAgICAgICAgPHN0cm9uZz57eyBjcmVkaXRDYXJkRXhwaXJpbmdUb3RhbD8udG90YWxfbXJyIC8gMTAwIHwgY3VycmVuY3k6ICdVU0QnIH19PC9zdHJvbmc+XG4gICAgICAgICAgICAgICAgPC90ZD5cbiAgICAgICAgICAgICAgICA8dGQ+PC90ZD5cbiAgICAgICAgICAgICAgICA8dGQ+PC90ZD5cbiAgICAgICAgICAgICAgPC90cj5cbiAgICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgPCEtLSBSZWd1bGFyIGRhdGEgcm93IC0tPlxuICAgICAgICAgICAgPHRyPlxuICAgICAgICAgICAgICA8dGQgZGF0YS1oZWFkPVwiQWNjb3VudFwiPlxuICAgICAgICAgICAgICAgIDxhIFtyb3V0ZXJMaW5rXT1cIlsnLycgKyBzdWJzY3JpcHRpb24/LnNsdWcgKyByb3V0ZXJzLmFjY291bnRJbmZvLCBhY2NvdW50LmNybV9hY2NvdW50X2lkXVwiIGNsYXNzPVwibmFtZS1saW5rXCI+XG4gICAgICAgICAgICAgICAgICA8c3BhbiBbbmdiVG9vbHRpcF09XCJhY2NvdW50LmNybV9hY2NvdW50X25hbWVcIj57eyBhY2NvdW50LmNybV9hY2NvdW50X25hbWUgfCB0ZXh0VHJ1bmNhdGU6MjAgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgICA8L3RkPlxuICAgICAgICAgICAgICA8dGQgZGF0YS1oZWFkPVwiTVJSXCIgY2xhc3M9XCJleHBlY3RlZC1tcnJcIj5cbiAgICAgICAgICAgICAgICB7eyBhY2NvdW50LmV4cGVjdGVkX21yciAvIDEwMCB8IGN1cnJlbmN5OiBhY2NvdW50LmN1cnJlbmN5IH19XG4gICAgICAgICAgICAgIDwvdGQ+XG4gICAgICAgICAgICAgIDx0ZCBkYXRhLWhlYWQ9XCJTaWduVXBBdFwiPlxuICAgICAgICAgICAgICAgIHt7IGFjY291bnQuc2lnbmVkX3VwX2F0IHwgZGF0ZUZvcm1hdCB9fVxuICAgICAgICAgICAgICA8L3RkPlxuICAgICAgICAgICAgICA8dGQgZGF0YS1oZWFkPVwiRXhwQXRcIiBbbmdDbGFzc109XCJ7J3RleHQtZGFuZ2VyJzogYWNjb3VudC5jY19leHBpcmluZ19hdCB8IGlzUGFzdERhdGV9XCI+XG4gICAgICAgICAgICAgICAge3sgYWNjb3VudC5jY19leHBpcmluZ19hdCB8IGRhdGVGb3JtYXQgfX1cbiAgICAgICAgICAgICAgICA8c3BhbiAqbmdJZj1cImFjY291bnQuY2NfZXhwaXJpbmdfYXQgfCBpc1Bhc3REYXRlXCIgY2xhc3M9XCJ0b29sdGlwLXdyYXBcIiBbYXBwZW5kVG9dPVwiJ2JvZHknXCIgW3BUb29sdGlwXT1cIidBZG1pbi5JbnNpZ2h0LlRvb2x0aXAuRXhwQXRNZXNzYWdlJyB8IHRyYW5zbG9jb1wiIHRvb2x0aXBQb3NpdGlvbj1cInRvcFwiPlxuICAgICAgICAgICAgICAgICAgPGkgY2xhc3M9XCJmYXMgZmEtaW5mby1jaXJjbGUgbWwtMVwiPjwvaT5cbiAgICAgICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgICAgIDwvdGQ+XG4gICAgICAgICAgICA8L3RyPlxuICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgICAgPG5nLXRlbXBsYXRlIHBUZW1wbGF0ZT1cImZvb3RlclwiPlxuICAgICAgICAgICAgPHRyICpuZ0lmPVwiY3JlZGl0Q2FyZEV4cGlyaW5nPy5sZW5ndGhcIj5cbiAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICAgIDx0ZCBjbGFzcz1cImZ3LWJvbGQgZXhwZWN0ZWQtbXJyXCI+XG4gICAgICAgICAgICAgICAgPHN0cm9uZz57eyBjcmVkaXRDYXJkRXhwaXJpbmdUb3RhbD8udG90YWxfbXJyIC8gMTAwIHwgY3VycmVuY3k6ICdVU0QnIH19PC9zdHJvbmc+XG4gICAgICAgICAgICAgIDwvdGQ+XG4gICAgICAgICAgICAgIDx0ZD48L3RkPlxuICAgICAgICAgICAgICA8dGQ+PC90ZD5cbiAgICAgICAgICAgIDwvdHI+XG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgPC9wLXRhYmxlPlxuICAgICAgICA8c3BhbiBjbGFzcz1cInRvdGFsLXJlY29yZHMtY291bnRcIiAqbmdJZj1cImNyZWRpdENhcmRFeHBpcmluZy5sZW5ndGggIT09IDBcIj57eyAnTGFiZWwuVG90YWwnIHwgdHJhbnNsb2NvIH19OiB7eyBjcmVkaXRDYXJkRXhwaXJpbmcubGVuZ3RoIH19PC9zcGFuPlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2ICpuZ0lmPVwiY3JlZGl0Q2FyZEV4cGlyaW5nPy5sZW5ndGggPT09IDBcIj5cbiAgICAgICAgPHB3LW5vLWRhdGEgW3dpdGhJbWFnZV09XCJ0cnVlXCIgW21lc3NhZ2VdPVwiJ0NybS5TdW1tYXJ5Lk5vSW5zaWdodE1lc3NhZ2UnIHwgdHJhbnNsb2NvXCI+IDwvcHctbm8tZGF0YT5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPCEtLSBNYWdpYyBNb21lbnQgLS0+XG4gICAgPGRpdiBjbGFzcz1cImNvbC0xMiBjb2wtbWQtNiBtYi0zIGFuYWx5dGljc1wiPlxuICAgICAgPGg1IGNsYXNzPVwiYWNjb3JkaW9uLWhlYWRpbmdcIj5BY2NvdW50cyB3aXRoIE1hZ2ljIE1vbWVudDwvaDU+XG4gICAgICA8ZGl2IGNsYXNzPVwidy0xMDAgdGV4dC1jZW50ZXIgbXQtM1wiPlxuICAgICAgICA8bmctdGVtcGxhdGUgW25nSWZdPVwiIW1hZ2ljTW9tZW50TG9hZGVkXCI+XG4gICAgICAgICAgPHAtcHJvZ3Jlc3NTcGlubmVyIHN0cm9rZVdpZHRoPVwiMlwiPiA8L3AtcHJvZ3Jlc3NTcGlubmVyPlxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwicHJpbWVuZy1kYXRhdGFibGUtY29udGFpbmVyIHRhYmxlLXJlc3BvbnNpdmVcIlxuICAgICAgICAqbmdJZj1cIm1hZ2ljTW9tZW50Py5sZW5ndGhcIj5cbiAgICAgICAgPHAtdGFibGUgY2xhc3M9XCJ0YWJsZVwiXG4gICAgICAgICAgI2R0XG4gICAgICAgICAgW3ZhbHVlXT1cIm1hZ2ljTW9tZW50XCJcbiAgICAgICAgICBbcGFnaW5hdG9yXT1cInRydWVcIlxuICAgICAgICAgIFtyb3dzXT1cIjIwXCJcbiAgICAgICAgICBbdG90YWxSZWNvcmRzXT1cIm1hZ2ljTW9tZW50Lmxlbmd0aFwiPlxuICAgICAgICAgIDxuZy10ZW1wbGF0ZSBwVGVtcGxhdGU9XCJoZWFkZXJcIj5cbiAgICAgICAgICAgIDx0cj5cbiAgICAgICAgICAgICAgPHRoIHNjb3BlPVwidHJ1ZVwiPnt7ICdDcm0uU3VtbWFyeS5BY2NvdW50JyB8IHRyYW5zbG9jbyB9fTwvdGg+XG4gICAgICAgICAgICAgIDx0aCBzY29wZT1cInRydWVcIiBjbGFzcz1cIm1yci1oZWFkZXJcIj57eyAnQ3JtLkFjY291bnRNZXNzYWdlLk1SUicgfCB0cmFuc2xvY28gfX08L3RoPlxuICAgICAgICAgICAgICA8dGggc2NvcGU9XCJ0cnVlXCI+e3sgJ0NybS5BY2NvdW50TWVzc2FnZS5RdWFydGVyJyB8IHRyYW5zbG9jbyB9fTwvdGg+XG4gICAgICAgICAgICAgIDx0aCBzY29wZT1cInRydWVcIj4ge3sgJ0NybS5BY2NvdW50TWVzc2FnZS5Nb250aCcgfCB0cmFuc2xvY28gfX08L3RoPlxuICAgICAgICAgICAgICA8dGggc2NvcGU9XCJ0cnVlXCI+e3sgJ0NybS5BY2NvdW50TWVzc2FnZS5TaWduVXBBdCcgfCB0cmFuc2xvY28gfX08L3RoPlxuICAgICAgICAgICAgPC90cj5cbiAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICAgIDxuZy10ZW1wbGF0ZSBwVGVtcGxhdGU9XCJib2R5XCJcbiAgICAgICAgICAgIGxldC1hY2NvdW50XG4gICAgICAgICAgICBsZXQtaT1cInJvd0luZGV4XCI+XG4gICAgICAgICAgICA8IS0tIFRvdGFscyByb3cgYXQgdGhlIHRvcCAoZmlyc3Qgcm93KSAtLT5cbiAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJpID09PSAwICYmIG1hZ2ljTW9tZW50Py5sZW5ndGhcIj5cbiAgICAgICAgICAgICAgPHRyIGNsYXNzPVwidG90YWxzLXJvd1wiPlxuICAgICAgICAgICAgICAgIDx0ZD48L3RkPlxuICAgICAgICAgICAgICAgIDx0ZCBjbGFzcz1cImZ3LWJvbGQgZXhwZWN0ZWQtbXJyXCI+XG4gICAgICAgICAgICAgICAgICA8c3Ryb25nPnt7IG1hZ2ljTW9tZW50VG90YWw/LnRvdGFsX21yciAvIDEwMCB8IGN1cnJlbmN5OiAnVVNEJyB9fTwvc3Ryb25nPlxuICAgICAgICAgICAgICAgIDwvdGQ+XG4gICAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICAgIDwvdHI+XG4gICAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgIDwhLS0gUmVndWxhciBkYXRhIHJvdyAtLT5cbiAgICAgICAgICAgIDx0cj5cbiAgICAgICAgICAgICAgPHRkIGRhdGEtaGVhZD1cIkFjY291bnRcIj5cbiAgICAgICAgICAgICAgICA8YSBbcm91dGVyTGlua109XCJbJy8nICsgc3Vic2NyaXB0aW9uPy5zbHVnICsgcm91dGVycy5hY2NvdW50SW5mbywgYWNjb3VudC5jcm1fYWNjb3VudF9pZF1cIiBjbGFzcz1cIm5hbWUtbGlua1wiPlxuICAgICAgICAgICAgICAgICAgPHNwYW4gW25nYlRvb2x0aXBdPVwiYWNjb3VudC5jcm1fYWNjb3VudF9uYW1lXCI+e3sgYWNjb3VudD8uY3JtX2FjY291bnRfbmFtZSB8IHRleHRUcnVuY2F0ZToyMCB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICA8L2E+XG4gICAgICAgICAgICAgIDwvdGQ+XG4gICAgICAgICAgICAgIDx0ZCBkYXRhLWhlYWQ9XCJNUlJcIiBjbGFzcz1cImV4cGVjdGVkLW1yclwiPlxuICAgICAgICAgICAgICAgIHt7IGFjY291bnQuZXhwZWN0ZWRfbXJyIC8gMTAwIHwgY3VycmVuY3k6IGFjY291bnQuY3VycmVuY3kgfX1cbiAgICAgICAgICAgICAgPC90ZD5cbiAgICAgICAgICAgICAgPHRkIGRhdGEtaGVhZD1cIlF1YXJ0ZXJcIiBbbmdDbGFzc109XCJ7J21vbnRoLXF1YXJ0ZXItdGV4dCBmdy1ib2xkJzogYWNjb3VudC5zZXNzaW9uc19sYXN0X3F1YXJ0ZXIgPiAxNX1cIj57eyBhY2NvdW50LnNlc3Npb25zX2xhc3RfcXVhcnRlciB9fTwvdGQ+XG4gICAgICAgICAgICAgIDx0ZCBkYXRhLWhlYWQ9XCJNb250aFwiIFtuZ0NsYXNzXT1cInsnbW9udGgtcXVhcnRlci10ZXh0IGZ3LWJvbGQnOiBhY2NvdW50LnNlc3Npb25zX2xhc3RfbW9udGggPiA1fVwiPnt7IGFjY291bnQuc2Vzc2lvbnNfbGFzdF9tb250aCB9fTwvdGQ+XG4gICAgICAgICAgICAgIDx0ZCBkYXRhLWhlYWQ9XCJTaWduVXBBdFwiPlxuICAgICAgICAgICAgICAgIHt7IGFjY291bnQuc2lnbmVkX3VwX2F0IHwgZGF0ZUZvcm1hdCB9fVxuICAgICAgICAgICAgICA8L3RkPlxuICAgICAgICAgICAgPC90cj5cbiAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICAgIDxuZy10ZW1wbGF0ZSBwVGVtcGxhdGU9XCJmb290ZXJcIj5cbiAgICAgICAgICAgIDx0ciAqbmdJZj1cIm1hZ2ljTW9tZW50Py5sZW5ndGhcIj5cbiAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICAgIDx0ZCBjbGFzcz1cImZ3LWJvbGQgZXhwZWN0ZWQtbXJyXCI+XG4gICAgICAgICAgICAgICAgPHN0cm9uZz57eyBtYWdpY01vbWVudFRvdGFsPy50b3RhbF9tcnIgLyAxMDAgfCBjdXJyZW5jeTogJ1VTRCcgfX08L3N0cm9uZz5cbiAgICAgICAgICAgICAgPC90ZD5cbiAgICAgICAgICAgICAgPHRkPjwvdGQ+XG4gICAgICAgICAgICAgIDx0ZD48L3RkPlxuICAgICAgICAgICAgICA8dGQ+PC90ZD5cbiAgICAgICAgICAgIDwvdHI+XG4gICAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgPC9wLXRhYmxlPlxuICAgICAgICA8c3BhbiBjbGFzcz1cInRvdGFsLXJlY29yZHMtY291bnRcIiAqbmdJZj1cIm1hZ2ljTW9tZW50Lmxlbmd0aCAhPT0wIFwiPnt7ICdMYWJlbC5Ub3RhbCcgfCB0cmFuc2xvY28gfX06IHt7IG1hZ2ljTW9tZW50Lmxlbmd0aCB9fTwvc3Bhbj5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiAqbmdJZj1cIm1hZ2ljTW9tZW50Py5sZW5ndGggPT09IDBcIj5cbiAgICAgICAgPHB3LW5vLWRhdGEgW3dpdGhJbWFnZV09XCJ0cnVlXCIgW21lc3NhZ2VdPVwiJ0NybS5TdW1tYXJ5Lk5vSW5zaWdodE1lc3NhZ2UnIHwgdHJhbnNsb2NvXCI+IDwvcHctbm8tZGF0YT5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPCEtLSBBY2NvdW50cyBHZW9ncmFwaHkgLS0+XG4gICAgPGRpdiBjbGFzcz1cImNvbC0xMiBjb2wtbWQtNiBtYi0zIGFuYWx5dGljc1wiPlxuICAgICAgPGg1IGNsYXNzPVwiYWNjb3JkaW9uLWhlYWRpbmdcIj5BY2NvdW50cyBMb2NhdGlvbjwvaDU+XG4gICAgICA8ZGl2IGNsYXNzPVwidy0xMDAgdGV4dC1jZW50ZXIgbXQtM1wiPlxuICAgICAgICA8bmctdGVtcGxhdGUgW25nSWZdPVwiIWFjY291bnRHZW9ncmFwaHlMb2FkZWRcIj5cbiAgICAgICAgICA8cC1wcm9ncmVzc1NwaW5uZXIgc3Ryb2tlV2lkdGg9XCIyXCI+IDwvcC1wcm9ncmVzc1NwaW5uZXI+XG4gICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXY+XG4gICAgICAgIDxuZy10ZW1wbGF0ZSBbbmdJZl09XCJhY2NvdW50R2VvZ3JhcGh5TG9hZGVkICYmIGFjY291bnRHZW9ncmFwaHk/LmRhdGE/Lmxlbmd0aFwiPlxuICAgICAgICAgIDxwbG90bHktcGxvdCBbZGF0YV09XCJhY2NvdW50R2VvZ3JhcGh5Py5kYXRhXCJcbiAgICAgICAgICAgIFtsYXlvdXRdPVwiYWNjb3VudEdlb2dyYXBoeT8ubGF5b3V0XCIgW3VzZVJlc2l6ZUhhbmRsZXJdPVwiYWNjb3VudEdlb2dyYXBoeUxvYWRlZCA/IHRydWUgOiBmYWxzZVwiIFtjb25maWddPVwiYWNjb3VudEdlb2dyYXBoeT8uY29uZmlnXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICA8L3Bsb3RseS1wbG90PlxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2ICpuZ0lmPVwiYWNjb3VudEdlb2dyYXBoeUxvYWRlZCAmJiAhYWNjb3VudEdlb2dyYXBoeT8uZGF0YT8ubGVuZ3RoXCI+XG4gICAgICAgIDxwdy1uby1kYXRhIFt3aXRoSW1hZ2VdPVwidHJ1ZVwiIFttZXNzYWdlXT1cIidDcm0uQ29udGFjdE1lc3NhZ2UuTm9JbnNpZ2h0TWVzc2FnZScgfCB0cmFuc2xvY29cIj5cbiAgICAgICAgPC9wdy1uby1kYXRhPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gIDwvbmctY29udGFpbmVyPlxuPC9kaXY+XG4iXX0=