@pagerduty/backstage-plugin-entity-processor 0.3.2 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/apis/client.cjs.js +435 -0
- package/dist/apis/client.cjs.js.map +1 -0
- package/dist/index.cjs.js +2 -673
- package/dist/index.cjs.js.map +1 -1
- package/dist/module.cjs.js +25 -0
- package/dist/module.cjs.js.map +1 -0
- package/dist/processor/PagerDutyEntityProcessor.cjs.js +234 -0
- package/dist/processor/PagerDutyEntityProcessor.cjs.js.map +1 -0
- package/package.json +18 -17
- package/LICENSE +0 -201
- package/README.md +0 -40
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fetch = require('node-fetch');
|
|
4
|
+
|
|
5
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
6
|
+
|
|
7
|
+
var fetch__default = /*#__PURE__*/_interopDefaultCompat(fetch);
|
|
8
|
+
|
|
9
|
+
class PagerDutyClient {
|
|
10
|
+
discovery;
|
|
11
|
+
logger;
|
|
12
|
+
baseUrl = "";
|
|
13
|
+
constructor({ discovery, logger }) {
|
|
14
|
+
this.discovery = discovery;
|
|
15
|
+
this.logger = logger;
|
|
16
|
+
}
|
|
17
|
+
async addServiceRelationToService(serviceId, relations) {
|
|
18
|
+
let response;
|
|
19
|
+
if (this.baseUrl === "") {
|
|
20
|
+
this.baseUrl = await this.discovery.getBaseUrl("pagerduty");
|
|
21
|
+
}
|
|
22
|
+
const options = {
|
|
23
|
+
method: "POST",
|
|
24
|
+
headers: {
|
|
25
|
+
"Content-Type": "application/json; charset=UTF-8",
|
|
26
|
+
Accept: "application/json, text/plain, */*"
|
|
27
|
+
},
|
|
28
|
+
body: JSON.stringify(relations)
|
|
29
|
+
};
|
|
30
|
+
const url = `${await this.discovery.getBaseUrl(
|
|
31
|
+
"pagerduty"
|
|
32
|
+
)}/dependencies/service/${serviceId}`;
|
|
33
|
+
try {
|
|
34
|
+
response = await fetchWithRetries(url, options);
|
|
35
|
+
if (response.status >= 500) {
|
|
36
|
+
throw new Error(`Failed to add service relation to service ${serviceId}. PagerDuty API returned a server error. Retrying with the same arguments will not work.`);
|
|
37
|
+
}
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
throw new Error(await response.text());
|
|
40
|
+
}
|
|
41
|
+
} catch (error) {
|
|
42
|
+
this.logger.error(`Failed to add dependencies: ${error}`);
|
|
43
|
+
throw new Error(`Failed to add dependencies: ${error}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async removeServiceRelationFromService(serviceId, relations) {
|
|
47
|
+
let response;
|
|
48
|
+
if (this.baseUrl === "") {
|
|
49
|
+
this.baseUrl = await this.discovery.getBaseUrl("pagerduty");
|
|
50
|
+
}
|
|
51
|
+
const options = {
|
|
52
|
+
method: "DELETE",
|
|
53
|
+
headers: {
|
|
54
|
+
"Content-Type": "application/json; charset=UTF-8",
|
|
55
|
+
Accept: "application/json, text/plain, */*"
|
|
56
|
+
},
|
|
57
|
+
body: JSON.stringify(relations)
|
|
58
|
+
};
|
|
59
|
+
const url = `${await this.discovery.getBaseUrl(
|
|
60
|
+
"pagerduty"
|
|
61
|
+
)}/dependencies/service/${serviceId}`;
|
|
62
|
+
try {
|
|
63
|
+
response = await fetchWithRetries(url, options);
|
|
64
|
+
if (response.status >= 500) {
|
|
65
|
+
throw new Error(`Failed to remove service relation from service ${serviceId}. PagerDuty API returned a server error. Retrying with the same arguments will not work.`);
|
|
66
|
+
}
|
|
67
|
+
if (response.status === 404) {
|
|
68
|
+
throw new Error(`Service ${serviceId} or dependencies not found.`);
|
|
69
|
+
}
|
|
70
|
+
if (!response.ok) {
|
|
71
|
+
throw new Error(await response.text());
|
|
72
|
+
}
|
|
73
|
+
} catch (error) {
|
|
74
|
+
this.logger.error(`Failed to remove dependencies from ${serviceId}: ${error}`);
|
|
75
|
+
throw new Error(`Failed to remove dependencies from ${serviceId}: ${error}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async getAllServiceMappings() {
|
|
79
|
+
let response;
|
|
80
|
+
const mappings = {};
|
|
81
|
+
if (this.baseUrl === "") {
|
|
82
|
+
this.baseUrl = await this.discovery.getBaseUrl("pagerduty");
|
|
83
|
+
}
|
|
84
|
+
const options = {
|
|
85
|
+
method: "GET",
|
|
86
|
+
headers: {
|
|
87
|
+
"Content-Type": "application/json; charset=UTF-8",
|
|
88
|
+
Accept: "application/json, text/plain, */*"
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
const url = `${await this.discovery.getBaseUrl(
|
|
92
|
+
"pagerduty"
|
|
93
|
+
)}/mapping/entity`;
|
|
94
|
+
try {
|
|
95
|
+
response = await fetchWithRetries(url, options);
|
|
96
|
+
if (response.status >= 500) {
|
|
97
|
+
throw new Error(`Failed to get all service mappings. API returned a server error. Retrying with the same arguments will not work.`);
|
|
98
|
+
}
|
|
99
|
+
const foundMappings = await response.json();
|
|
100
|
+
switch (response.status) {
|
|
101
|
+
case 400:
|
|
102
|
+
throw new Error(await response.text());
|
|
103
|
+
case 404:
|
|
104
|
+
return mappings;
|
|
105
|
+
default:
|
|
106
|
+
foundMappings.mappings.forEach((mapping) => {
|
|
107
|
+
mappings[mapping.serviceId] = mapping.entityRef;
|
|
108
|
+
});
|
|
109
|
+
return mappings;
|
|
110
|
+
}
|
|
111
|
+
} catch (error) {
|
|
112
|
+
this.logger.error(`Failed to retrieve mappings: ${error}`);
|
|
113
|
+
throw new Error(`Failed to retrieve mappings: ${error}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async findServiceMapping({ type, namespace, name }) {
|
|
117
|
+
let response;
|
|
118
|
+
if (this.baseUrl === "") {
|
|
119
|
+
this.baseUrl = await this.discovery.getBaseUrl("pagerduty");
|
|
120
|
+
}
|
|
121
|
+
const options = {
|
|
122
|
+
method: "GET",
|
|
123
|
+
headers: {
|
|
124
|
+
"Content-Type": "application/json; charset=UTF-8",
|
|
125
|
+
Accept: "application/json, text/plain, */*"
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
const url = `${await this.discovery.getBaseUrl(
|
|
129
|
+
"pagerduty"
|
|
130
|
+
)}/mapping/entity/${type}/${namespace}/${name}`;
|
|
131
|
+
try {
|
|
132
|
+
response = await fetchWithRetries(url, options);
|
|
133
|
+
if (response.status >= 500) {
|
|
134
|
+
throw new Error(`Failed to find service mapping. API returned a server error. Retrying with the same arguments will not work.`);
|
|
135
|
+
}
|
|
136
|
+
const foundMapping = await response.json();
|
|
137
|
+
switch (response.status) {
|
|
138
|
+
case 400:
|
|
139
|
+
throw new Error(await response.text());
|
|
140
|
+
case 404:
|
|
141
|
+
return void 0;
|
|
142
|
+
default:
|
|
143
|
+
this.logger.debug(`Found mapping for ${type}:${namespace}/${name}: ${JSON.stringify(foundMapping.mapping)}`);
|
|
144
|
+
return {
|
|
145
|
+
serviceId: foundMapping.mapping.serviceId,
|
|
146
|
+
integrationKey: foundMapping.mapping.integrationKey,
|
|
147
|
+
entityRef: foundMapping.mapping.entityRef,
|
|
148
|
+
account: foundMapping.mapping.account
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
} catch (error) {
|
|
152
|
+
this.logger.error(`Failed to retrieve mapping for ${type}:${namespace}/${name}: ${error}`);
|
|
153
|
+
throw new Error(`Failed to retrieve mapping for ${type}:${namespace}/${name}: ${error}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async findServiceMappingById(serviceId) {
|
|
157
|
+
let response;
|
|
158
|
+
if (this.baseUrl === "") {
|
|
159
|
+
this.baseUrl = await this.discovery.getBaseUrl("pagerduty");
|
|
160
|
+
}
|
|
161
|
+
const options = {
|
|
162
|
+
method: "GET",
|
|
163
|
+
headers: {
|
|
164
|
+
"Content-Type": "application/json; charset=UTF-8",
|
|
165
|
+
Accept: "application/json, text/plain, */*"
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
const url = `${await this.discovery.getBaseUrl(
|
|
169
|
+
"pagerduty"
|
|
170
|
+
)}/mapping/entity/service/${serviceId}`;
|
|
171
|
+
try {
|
|
172
|
+
response = await fetchWithRetries(url, options);
|
|
173
|
+
if (response.status >= 500) {
|
|
174
|
+
throw new Error(`Failed to find service mapping by id. API returned a server error. Retrying with the same arguments will not work.`);
|
|
175
|
+
}
|
|
176
|
+
const foundMapping = await response.json();
|
|
177
|
+
switch (response.status) {
|
|
178
|
+
case 400:
|
|
179
|
+
throw new Error(await response.text());
|
|
180
|
+
case 404:
|
|
181
|
+
return void 0;
|
|
182
|
+
default:
|
|
183
|
+
this.logger.debug(`Found mapping for serviceId ${serviceId}: ${JSON.stringify(foundMapping.mapping)}`);
|
|
184
|
+
return {
|
|
185
|
+
serviceId: foundMapping.mapping.serviceId,
|
|
186
|
+
integrationKey: foundMapping.mapping.integrationKey,
|
|
187
|
+
entityRef: foundMapping.mapping.entityRef,
|
|
188
|
+
account: foundMapping.mapping.account
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
} catch (error) {
|
|
192
|
+
this.logger.error(`Failed to retrieve mapping for serviceId ${serviceId}: ${error}`);
|
|
193
|
+
throw new Error(`Failed to retrieve mapping for serviceId ${serviceId}: ${error}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
async insertServiceMapping(mapping) {
|
|
197
|
+
let response;
|
|
198
|
+
if (this.baseUrl === "") {
|
|
199
|
+
this.baseUrl = await this.discovery.getBaseUrl("pagerduty");
|
|
200
|
+
}
|
|
201
|
+
const options = {
|
|
202
|
+
method: "POST",
|
|
203
|
+
headers: {
|
|
204
|
+
"Content-Type": "application/json; charset=UTF-8",
|
|
205
|
+
Accept: "application/json, text/plain, */*"
|
|
206
|
+
},
|
|
207
|
+
body: JSON.stringify(mapping)
|
|
208
|
+
};
|
|
209
|
+
const url = `${await this.discovery.getBaseUrl(
|
|
210
|
+
"pagerduty"
|
|
211
|
+
)}/mapping/entity`;
|
|
212
|
+
try {
|
|
213
|
+
response = await fetchWithRetries(url, options);
|
|
214
|
+
if (response.status >= 500) {
|
|
215
|
+
throw new Error(`Failed to add service mapping. API returned a server error. Retrying with the same arguments will not work.`);
|
|
216
|
+
}
|
|
217
|
+
if (!response.ok) {
|
|
218
|
+
throw new Error(await response.text());
|
|
219
|
+
}
|
|
220
|
+
} catch (error) {
|
|
221
|
+
this.logger.error(`Failed to add mapping for ${mapping.entityRef}: ${error}`);
|
|
222
|
+
throw new Error(`Failed to add mapping for ${mapping.entityRef}: ${error}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
async getServiceDependencies(serviceId, account) {
|
|
226
|
+
let response;
|
|
227
|
+
if (this.baseUrl === "") {
|
|
228
|
+
this.baseUrl = await this.discovery.getBaseUrl("pagerduty");
|
|
229
|
+
}
|
|
230
|
+
const options = {
|
|
231
|
+
method: "GET",
|
|
232
|
+
headers: {
|
|
233
|
+
"Content-Type": "application/json; charset=UTF-8",
|
|
234
|
+
Accept: "application/json, text/plain, */*"
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
let url = `${await this.discovery.getBaseUrl(
|
|
238
|
+
"pagerduty"
|
|
239
|
+
)}/dependencies/service/${serviceId}`;
|
|
240
|
+
if (account) {
|
|
241
|
+
url = url.concat(`?account=${account}`);
|
|
242
|
+
}
|
|
243
|
+
try {
|
|
244
|
+
response = await fetchWithRetries(url, options);
|
|
245
|
+
if (response.status >= 500) {
|
|
246
|
+
throw new Error(`Failed to get service depedencies. PagerDuty API returned a server error. Retrying with the same arguments will not work.`);
|
|
247
|
+
}
|
|
248
|
+
const foundDependencies = await response.json();
|
|
249
|
+
switch (response.status) {
|
|
250
|
+
case 400:
|
|
251
|
+
throw new Error(await response.text());
|
|
252
|
+
case 404:
|
|
253
|
+
return [];
|
|
254
|
+
default:
|
|
255
|
+
return foundDependencies.relationships;
|
|
256
|
+
}
|
|
257
|
+
} catch (error) {
|
|
258
|
+
this.logger.error(`Failed to retrieve mapping for ${serviceId}: ${error}`);
|
|
259
|
+
throw new Error(`Failed to retrieve mapping for ${serviceId}: ${error}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
async getServiceIdAnnotationFromCatalog(entityRef) {
|
|
263
|
+
let response;
|
|
264
|
+
if (this.baseUrl === "") {
|
|
265
|
+
this.baseUrl = await this.discovery.getBaseUrl("pagerduty");
|
|
266
|
+
}
|
|
267
|
+
const options = {
|
|
268
|
+
method: "GET",
|
|
269
|
+
headers: {
|
|
270
|
+
"Content-Type": "application/json; charset=UTF-8",
|
|
271
|
+
Accept: "application/json, text/plain, */*"
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
const [type, rest] = entityRef.split(":");
|
|
275
|
+
const [namespace, name] = rest.split("/");
|
|
276
|
+
const url = `${await this.discovery.getBaseUrl(
|
|
277
|
+
"pagerduty"
|
|
278
|
+
)}/catalog/entity/${type}/${namespace}/${name}`;
|
|
279
|
+
try {
|
|
280
|
+
response = await fetchWithRetries(url, options);
|
|
281
|
+
if (response.status >= 500) {
|
|
282
|
+
throw new Error(`Failed to get service id annotation from catalog. API returned a server error. Retrying with the same arguments will not work.`);
|
|
283
|
+
}
|
|
284
|
+
const foundServiceId = await response.json();
|
|
285
|
+
switch (response.status) {
|
|
286
|
+
case 400:
|
|
287
|
+
throw new Error(await response.text());
|
|
288
|
+
case 404:
|
|
289
|
+
return "";
|
|
290
|
+
default:
|
|
291
|
+
return foundServiceId;
|
|
292
|
+
}
|
|
293
|
+
} catch (error) {
|
|
294
|
+
this.logger.error(`Failed to retrieve a PagerDuty service id for ${entityRef}: ${error}`);
|
|
295
|
+
throw new Error(`Failed to retrieve a PagerDuty service id for ${entityRef}: ${error}`);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
async getServiceIdFromIntegrationKey(integrationKey, account) {
|
|
299
|
+
let response;
|
|
300
|
+
if (this.baseUrl === "") {
|
|
301
|
+
this.baseUrl = await this.discovery.getBaseUrl("pagerduty");
|
|
302
|
+
}
|
|
303
|
+
const options = {
|
|
304
|
+
method: "GET",
|
|
305
|
+
headers: {
|
|
306
|
+
"Content-Type": "application/json; charset=UTF-8",
|
|
307
|
+
Accept: "application/json, text/plain, */*"
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
let url = `${await this.discovery.getBaseUrl(
|
|
311
|
+
"pagerduty"
|
|
312
|
+
)}/services?integration_key=${integrationKey}`;
|
|
313
|
+
if (account) {
|
|
314
|
+
url = url.concat(`&account=${account}`);
|
|
315
|
+
}
|
|
316
|
+
try {
|
|
317
|
+
response = await fetchWithRetries(url, options);
|
|
318
|
+
if (response.status >= 500) {
|
|
319
|
+
throw new Error(`Failed to get service id from integration key ${integrationKey}. PagerDuty API returned a server error. Retrying with the same arguments will not work.`);
|
|
320
|
+
}
|
|
321
|
+
const foundService = await response.json();
|
|
322
|
+
switch (response.status) {
|
|
323
|
+
case 400:
|
|
324
|
+
throw new Error(await response.text());
|
|
325
|
+
case 404:
|
|
326
|
+
return "";
|
|
327
|
+
default:
|
|
328
|
+
return foundService.service.id;
|
|
329
|
+
}
|
|
330
|
+
} catch (error) {
|
|
331
|
+
this.logger.error(`Failed to retrieve a PagerDuty service id for integration key ${integrationKey}: ${error}`);
|
|
332
|
+
throw new Error(`Failed to retrieve a PagerDuty service id for integration key ${integrationKey}: ${error}`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
async getIntegrationKeyFromServiceId(serviceId, account) {
|
|
336
|
+
let response;
|
|
337
|
+
if (this.baseUrl === "") {
|
|
338
|
+
this.baseUrl = await this.discovery.getBaseUrl("pagerduty");
|
|
339
|
+
}
|
|
340
|
+
const options = {
|
|
341
|
+
method: "GET",
|
|
342
|
+
headers: {
|
|
343
|
+
"Content-Type": "application/json; charset=UTF-8",
|
|
344
|
+
Accept: "application/json, text/plain, */*"
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
let url = `${await this.discovery.getBaseUrl(
|
|
348
|
+
"pagerduty"
|
|
349
|
+
)}/services/${serviceId}`;
|
|
350
|
+
if (account) {
|
|
351
|
+
url = url.concat(`?account=${account}`);
|
|
352
|
+
}
|
|
353
|
+
try {
|
|
354
|
+
response = await fetchWithRetries(url, options);
|
|
355
|
+
if (response.status >= 500) {
|
|
356
|
+
throw new Error(`Failed to get integration key from service id ${serviceId}. PagerDuty API returned a server error. Retrying with the same arguments will not work.`);
|
|
357
|
+
}
|
|
358
|
+
const foundService = await response.json();
|
|
359
|
+
const backstageIntegration = foundService.service.integrations?.find((integration) => integration.vendor?.id === "PRO19CT");
|
|
360
|
+
switch (response.status) {
|
|
361
|
+
case 400:
|
|
362
|
+
throw new Error(await response.text());
|
|
363
|
+
case 404:
|
|
364
|
+
return "";
|
|
365
|
+
default:
|
|
366
|
+
if (!backstageIntegration) {
|
|
367
|
+
return void 0;
|
|
368
|
+
}
|
|
369
|
+
return backstageIntegration.integration_key;
|
|
370
|
+
}
|
|
371
|
+
} catch (error) {
|
|
372
|
+
this.logger.error(`No Backstage integration found for service id ${serviceId}: ${error}`);
|
|
373
|
+
throw new Error(`No Backstage integration found for service id ${serviceId}: ${error}`);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
async getServiceDependencyStrategySetting() {
|
|
377
|
+
const SERVICE_DEPENDENCY_SYNC_STRATEGY = "settings::service-dependency-sync-strategy";
|
|
378
|
+
let response;
|
|
379
|
+
if (this.baseUrl === "") {
|
|
380
|
+
this.baseUrl = await this.discovery.getBaseUrl("pagerduty");
|
|
381
|
+
}
|
|
382
|
+
const options = {
|
|
383
|
+
method: "GET",
|
|
384
|
+
headers: {
|
|
385
|
+
"Content-Type": "application/json; charset=UTF-8",
|
|
386
|
+
Accept: "application/json, text/plain, */*"
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
const url = `${await this.discovery.getBaseUrl(
|
|
390
|
+
"pagerduty"
|
|
391
|
+
)}/settings/${SERVICE_DEPENDENCY_SYNC_STRATEGY}`;
|
|
392
|
+
try {
|
|
393
|
+
response = await fetchWithRetries(url, options);
|
|
394
|
+
if (response.status >= 500) {
|
|
395
|
+
throw new Error(`Failed to get service depedency strategy. API returned a server error. Retrying with the same arguments will not work.`);
|
|
396
|
+
}
|
|
397
|
+
const setting = await response.json();
|
|
398
|
+
switch (response.status) {
|
|
399
|
+
case 400:
|
|
400
|
+
throw new Error(await response.text());
|
|
401
|
+
case 404:
|
|
402
|
+
return "disabled";
|
|
403
|
+
// if setting does not exist in the database, default to disabled
|
|
404
|
+
default:
|
|
405
|
+
return setting.value;
|
|
406
|
+
}
|
|
407
|
+
} catch (error) {
|
|
408
|
+
this.logger.error(`Error getting value for setting: ${error}`);
|
|
409
|
+
throw new Error(`Error getting value for setting: ${error}`);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
async function fetchWithRetries(url, options) {
|
|
414
|
+
let response;
|
|
415
|
+
let error = new Error();
|
|
416
|
+
const maxRetries = 5;
|
|
417
|
+
const delay = 1e3;
|
|
418
|
+
let factor = 2;
|
|
419
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
420
|
+
try {
|
|
421
|
+
response = await fetch__default.default(url, options);
|
|
422
|
+
return response;
|
|
423
|
+
} catch (e) {
|
|
424
|
+
error = e;
|
|
425
|
+
}
|
|
426
|
+
const timeout = delay * factor;
|
|
427
|
+
await new Promise((resolve) => setTimeout(resolve, timeout));
|
|
428
|
+
factor *= 2;
|
|
429
|
+
}
|
|
430
|
+
throw new Error(`Failed to fetch data after ${maxRetries} retries. Last error: ${error}`);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
exports.PagerDutyClient = PagerDutyClient;
|
|
434
|
+
exports.fetchWithRetries = fetchWithRetries;
|
|
435
|
+
//# sourceMappingURL=client.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.cjs.js","sources":["../../src/apis/client.ts"],"sourcesContent":["import fetch from 'node-fetch';\nimport type {\n RequestInit,\n Response\n} from 'node-fetch';\nimport type { EntityMapping } from '../types';\nimport {\n DiscoveryService,\n LoggerService\n} from '@backstage/backend-plugin-api';\nimport {\n PagerDutyEntityMapping,\n PagerDutyEntityMappingResponse,\n PagerDutyServiceResponse,\n PagerDutyServiceDependency,\n PagerDutyServiceDependencyResponse,\n PagerDutySetting,\n PagerDutyEntityMappingsResponse,\n} from '@pagerduty/backstage-plugin-common';\n\nexport interface PagerDutyClientOptions {\n discovery: DiscoveryService;\n logger: LoggerService;\n};\n\nexport type BackstageEntityRef = {\n type: string;\n namespace: string;\n name: string;\n}\n\nexport class PagerDutyClient {\n private discovery: DiscoveryService;\n private logger: LoggerService;\n private baseUrl: string = \"\";\n\n constructor({ discovery, logger }: PagerDutyClientOptions) {\n this.discovery = discovery;\n this.logger = logger;\n }\n\n async addServiceRelationToService(serviceId: string, relations: string[]) : Promise<void> {\n let response: Response;\n\n if (this.baseUrl === \"\") {\n this.baseUrl = await this.discovery.getBaseUrl('pagerduty');\n }\n\n const options: RequestInit = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json; charset=UTF-8',\n Accept: 'application/json, text/plain, */*',\n },\n body: JSON.stringify(relations),\n };\n\n const url = `${await this.discovery.getBaseUrl(\n 'pagerduty',\n )}/dependencies/service/${serviceId}`;\n\n try {\n response = await fetchWithRetries(url, options);\n\n if (response.status >= 500) {\n throw new Error(`Failed to add service relation to service ${serviceId}. PagerDuty API returned a server error. Retrying with the same arguments will not work.`);\n }\n\n if (!response.ok) {\n throw new Error(await response.text());\n }\n } catch (error) {\n this.logger.error(`Failed to add dependencies: ${error}`);\n throw new Error(`Failed to add dependencies: ${error}`);\n }\n }\n\n async removeServiceRelationFromService(serviceId: string, relations: string[]): Promise<void> {\n let response: Response;\n\n if (this.baseUrl === \"\") {\n this.baseUrl = await this.discovery.getBaseUrl('pagerduty');\n }\n\n const options: RequestInit = {\n method: 'DELETE',\n headers: {\n 'Content-Type': 'application/json; charset=UTF-8',\n Accept: 'application/json, text/plain, */*',\n },\n body: JSON.stringify(relations),\n };\n\n const url = `${await this.discovery.getBaseUrl(\n 'pagerduty',\n )}/dependencies/service/${serviceId}`;\n\n try {\n response = await fetchWithRetries(url, options);\n\n if (response.status >= 500) {\n throw new Error(`Failed to remove service relation from service ${serviceId}. PagerDuty API returned a server error. Retrying with the same arguments will not work.`);\n }\n\n if (response.status === 404) {\n throw new Error(`Service ${serviceId} or dependencies not found.`);\n }\n\n if (!response.ok) {\n throw new Error(await response.text());\n }\n } catch (error) {\n this.logger.error(`Failed to remove dependencies from ${serviceId}: ${error}`);\n throw new Error(`Failed to remove dependencies from ${serviceId}: ${error}`);\n }\n }\n\n async getAllServiceMappings(): Promise<Record<string, string>> {\n let response: Response;\n const mappings: Record<string, string> = {};\n\n if (this.baseUrl === \"\") {\n this.baseUrl = await this.discovery.getBaseUrl('pagerduty');\n }\n\n const options: RequestInit = {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json; charset=UTF-8',\n Accept: 'application/json, text/plain, */*',\n },\n };\n\n const url = `${await this.discovery.getBaseUrl(\n 'pagerduty',\n )}/mapping/entity`;\n\n try {\n response = await fetchWithRetries(url, options);\n\n if (response.status >= 500) {\n throw new Error(`Failed to get all service mappings. API returned a server error. Retrying with the same arguments will not work.`);\n }\n\n const foundMappings: PagerDutyEntityMappingsResponse = await response.json();\n\n switch (response.status) {\n case 400:\n throw new Error(await response.text());\n case 404:\n return mappings;\n default: // 200\n foundMappings.mappings.forEach(mapping => {\n mappings[mapping.serviceId] = mapping.entityRef;\n });\n\n return mappings;\n }\n } catch (error) {\n this.logger.error(`Failed to retrieve mappings: ${error}`);\n throw new Error(`Failed to retrieve mappings: ${error}`);\n }\n }\n\n async findServiceMapping({ type, namespace, name }: BackstageEntityRef): Promise<EntityMapping | undefined> {\n let response: Response;\n\n if (this.baseUrl === \"\") {\n this.baseUrl = await this.discovery.getBaseUrl('pagerduty');\n }\n\n const options: RequestInit = {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json; charset=UTF-8',\n Accept: 'application/json, text/plain, */*',\n },\n };\n\n const url = `${await this.discovery.getBaseUrl(\n 'pagerduty',\n )}/mapping/entity/${type}/${namespace}/${name}`;\n\n try {\n response = await fetchWithRetries(url, options);\n\n if (response.status >= 500) {\n throw new Error(`Failed to find service mapping. API returned a server error. Retrying with the same arguments will not work.`);\n }\n\n const foundMapping: PagerDutyEntityMappingResponse = await response.json();\n\n switch (response.status) {\n case 400:\n throw new Error(await response.text());\n case 404:\n return undefined;\n default: // 200\n this.logger.debug(`Found mapping for ${type}:${namespace}/${name}: ${JSON.stringify(foundMapping.mapping)}`);\n\n return {\n serviceId: foundMapping.mapping.serviceId,\n integrationKey: foundMapping.mapping.integrationKey,\n entityRef: foundMapping.mapping.entityRef,\n account: foundMapping.mapping.account,\n }\n }\n } catch (error) {\n this.logger.error(`Failed to retrieve mapping for ${type}:${namespace}/${name}: ${error}`);\n throw new Error(`Failed to retrieve mapping for ${type}:${namespace}/${name}: ${error}`);\n }\n }\n\n async findServiceMappingById(serviceId: string): Promise<EntityMapping | undefined> {\n let response: Response;\n\n if (this.baseUrl === \"\") {\n this.baseUrl = await this.discovery.getBaseUrl('pagerduty');\n }\n\n const options: RequestInit = {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json; charset=UTF-8',\n Accept: 'application/json, text/plain, */*',\n },\n };\n\n const url = `${await this.discovery.getBaseUrl(\n 'pagerduty',\n )}/mapping/entity/service/${serviceId}`;\n\n try {\n response = await fetchWithRetries(url, options);\n\n if (response.status >= 500) {\n throw new Error(`Failed to find service mapping by id. API returned a server error. Retrying with the same arguments will not work.`);\n }\n\n const foundMapping: PagerDutyEntityMappingResponse = await response.json();\n\n switch (response.status) {\n case 400:\n throw new Error(await response.text());\n case 404:\n return undefined;\n default: // 200\n this.logger.debug(`Found mapping for serviceId ${serviceId}: ${JSON.stringify(foundMapping.mapping)}`);\n\n return {\n serviceId: foundMapping.mapping.serviceId,\n integrationKey: foundMapping.mapping.integrationKey,\n entityRef: foundMapping.mapping.entityRef,\n account: foundMapping.mapping.account,\n };\n }\n } catch (error) {\n this.logger.error(`Failed to retrieve mapping for serviceId ${serviceId}: ${error}`);\n throw new Error(`Failed to retrieve mapping for serviceId ${serviceId}: ${error}`);\n }\n }\n\n async insertServiceMapping(mapping: PagerDutyEntityMapping): Promise<void> {\n let response: Response;\n\n if (this.baseUrl === \"\") {\n this.baseUrl = await this.discovery.getBaseUrl('pagerduty');\n }\n\n const options: RequestInit = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json; charset=UTF-8',\n Accept: 'application/json, text/plain, */*',\n },\n body: JSON.stringify(mapping),\n };\n\n const url = `${await this.discovery.getBaseUrl(\n 'pagerduty',\n )}/mapping/entity`;\n\n try {\n response = await fetchWithRetries(url, options);\n\n if (response.status >= 500) {\n throw new Error(`Failed to add service mapping. API returned a server error. Retrying with the same arguments will not work.`);\n }\n\n if (!response.ok) {\n throw new Error(await response.text());\n }\n } catch (error) {\n this.logger.error(`Failed to add mapping for ${mapping.entityRef}: ${error}`);\n throw new Error(`Failed to add mapping for ${mapping.entityRef}: ${error}`);\n }\n }\n\n async getServiceDependencies(serviceId: string, account?: string): Promise<PagerDutyServiceDependency[]> {\n let response: Response;\n\n if (this.baseUrl === \"\") {\n this.baseUrl = await this.discovery.getBaseUrl('pagerduty');\n }\n\n const options: RequestInit = {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json; charset=UTF-8',\n Accept: 'application/json, text/plain, */*',\n },\n };\n\n let url = `${await this.discovery.getBaseUrl(\n 'pagerduty',\n )}/dependencies/service/${serviceId}`;\n\n if (account) {\n url = url.concat(`?account=${account}`);\n }\n\n try {\n response = await fetchWithRetries(url, options);\n\n if (response.status >= 500) {\n throw new Error(`Failed to get service depedencies. PagerDuty API returned a server error. Retrying with the same arguments will not work.`);\n }\n\n const foundDependencies: PagerDutyServiceDependencyResponse = await response.json();\n\n switch (response.status) {\n case 400:\n throw new Error(await response.text());\n case 404:\n return [];\n default: // 200\n return foundDependencies.relationships;\n }\n } catch (error) {\n this.logger.error(`Failed to retrieve mapping for ${serviceId}: ${error}`);\n throw new Error(`Failed to retrieve mapping for ${serviceId}: ${error}`);\n }\n }\n\n async getServiceIdAnnotationFromCatalog(entityRef: string): Promise<string> {\n let response: Response;\n\n if (this.baseUrl === \"\") {\n this.baseUrl = await this.discovery.getBaseUrl('pagerduty');\n }\n\n const options: RequestInit = {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json; charset=UTF-8',\n Accept: 'application/json, text/plain, */*',\n },\n };\n\n // extract type, namespace and name from type:namespace/name\n const [type, rest] = entityRef.split(':');\n const [namespace, name] = rest.split('/');\n\n const url = `${await this.discovery.getBaseUrl(\n 'pagerduty',\n )}/catalog/entity/${type}/${namespace}/${name}`;\n\n try {\n response = await fetchWithRetries(url, options);\n\n if (response.status >= 500) {\n throw new Error(`Failed to get service id annotation from catalog. API returned a server error. Retrying with the same arguments will not work.`);\n }\n\n const foundServiceId: string = await response.json();\n\n switch (response.status) {\n case 400:\n throw new Error(await response.text());\n case 404:\n return \"\";\n default: // 200\n return foundServiceId;\n }\n } catch (error) {\n this.logger.error(`Failed to retrieve a PagerDuty service id for ${entityRef}: ${error}`);\n throw new Error(`Failed to retrieve a PagerDuty service id for ${entityRef}: ${error}`);\n }\n }\n\n async getServiceIdFromIntegrationKey(integrationKey: string, account?: string): Promise<string> {\n let response: Response;\n\n if (this.baseUrl === \"\") {\n this.baseUrl = await this.discovery.getBaseUrl('pagerduty');\n }\n\n const options: RequestInit = {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json; charset=UTF-8',\n Accept: 'application/json, text/plain, */*',\n },\n };\n\n let url = `${await this.discovery.getBaseUrl(\n 'pagerduty',\n )}/services?integration_key=${integrationKey}`;\n\n if (account) {\n url = url.concat(`&account=${account}`);\n }\n\n try {\n response = await fetchWithRetries(url, options);\n\n if (response.status >= 500) {\n throw new Error(`Failed to get service id from integration key ${integrationKey}. PagerDuty API returned a server error. Retrying with the same arguments will not work.`);\n }\n\n const foundService: PagerDutyServiceResponse = await response.json();\n\n switch (response.status) {\n case 400:\n throw new Error(await response.text());\n case 404:\n return \"\";\n default: // 200\n return foundService.service.id;\n }\n } catch (error) {\n this.logger.error(`Failed to retrieve a PagerDuty service id for integration key ${integrationKey}: ${error}`);\n throw new Error(`Failed to retrieve a PagerDuty service id for integration key ${integrationKey}: ${error}`);\n }\n }\n\n async getIntegrationKeyFromServiceId(serviceId: string, account?: string): Promise<string | undefined> {\n let response: Response;\n\n if (this.baseUrl === \"\") {\n this.baseUrl = await this.discovery.getBaseUrl('pagerduty');\n }\n\n const options: RequestInit = {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json; charset=UTF-8',\n Accept: 'application/json, text/plain, */*',\n },\n };\n\n let url = `${await this.discovery.getBaseUrl(\n 'pagerduty',\n )}/services/${serviceId}`;\n\n if (account) {\n url = url.concat(`?account=${account}`);\n }\n\n try {\n response = await fetchWithRetries(url, options);\n\n if (response.status >= 500) {\n throw new Error(`Failed to get integration key from service id ${serviceId}. PagerDuty API returned a server error. Retrying with the same arguments will not work.`);\n }\n\n const foundService: PagerDutyServiceResponse = await response.json();\n const backstageIntegration = foundService.service.integrations?.find(integration => integration.vendor?.id === \"PRO19CT\");\n\n switch (response.status) {\n case 400:\n throw new Error(await response.text());\n case 404:\n return \"\";\n default: // 200\n\n if (!backstageIntegration) {\n return undefined;\n }\n\n return backstageIntegration.integration_key;\n }\n } catch (error) {\n this.logger.error(`No Backstage integration found for service id ${serviceId}: ${error}`);\n throw new Error(`No Backstage integration found for service id ${serviceId}: ${error}`);\n }\n }\n\n async getServiceDependencyStrategySetting(): Promise<string> {\n const SERVICE_DEPENDENCY_SYNC_STRATEGY = \"settings::service-dependency-sync-strategy\";\n\n let response: Response;\n\n if (this.baseUrl === \"\") {\n this.baseUrl = await this.discovery.getBaseUrl('pagerduty');\n }\n\n const options: RequestInit = {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json; charset=UTF-8',\n Accept: 'application/json, text/plain, */*',\n },\n };\n\n const url = `${await this.discovery.getBaseUrl(\n 'pagerduty',\n )}/settings/${SERVICE_DEPENDENCY_SYNC_STRATEGY}`;\n\n try {\n response = await fetchWithRetries(url, options); \n\n if (response.status >= 500) {\n throw new Error(`Failed to get service depedency strategy. API returned a server error. Retrying with the same arguments will not work.`);\n }\n\n const setting: PagerDutySetting = await response.json(); \n\n switch (response.status) {\n case 400:\n throw new Error(await response.text());\n case 404:\n return \"disabled\"; // if setting does not exist in the database, default to disabled\n default: // 200\n return setting.value;\n }\n } catch (error) {\n this.logger.error(`Error getting value for setting: ${error}`);\n throw new Error(`Error getting value for setting: ${error}`);\n }\n }\n}\n\nexport async function fetchWithRetries(url: string, options: RequestInit): Promise<Response> {\n let response: Response;\n let error: Error = new Error();\n\n // set retry parameters\n const maxRetries = 5;\n const delay = 1000;\n let factor = 2;\n\n for (let i = 0; i < maxRetries; i++) {\n try {\n response = await fetch(url, options);\n return response;\n } catch (e) {\n error = e as Error;\n }\n\n const timeout = delay * factor;\n await new Promise(resolve => setTimeout(resolve, timeout));\n factor *= 2;\n }\n\n throw new Error(`Failed to fetch data after ${maxRetries} retries. Last error: ${error}`);\n}"],"names":["fetch"],"mappings":";;;;;;;;AA+BO,MAAM,eAAA,CAAgB;AAAA,EACjB,SAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA,GAAkB,EAAA;AAAA,EAE1B,WAAA,CAAY,EAAE,SAAA,EAAW,MAAA,EAAO,EAA2B;AACvD,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AACjB,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAClB;AAAA,EAEA,MAAM,2BAAA,CAA4B,SAAA,EAAmB,SAAA,EAAqC;AACtF,IAAA,IAAI,QAAA;AAEJ,IAAA,IAAI,IAAA,CAAK,YAAY,EAAA,EAAI;AACrB,MAAA,IAAA,CAAK,OAAA,GAAU,MAAM,IAAA,CAAK,SAAA,CAAU,WAAW,WAAW,CAAA;AAAA,IAC9D;AAEA,IAAA,MAAM,OAAA,GAAuB;AAAA,MACzB,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACL,cAAA,EAAgB,iCAAA;AAAA,QAChB,MAAA,EAAQ;AAAA,OACZ;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,SAAS;AAAA,KAClC;AAEA,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,MAAM,IAAA,CAAK,SAAA,CAAU,UAAA;AAAA,MAChC;AAAA,KACH,yBAAyB,SAAS,CAAA,CAAA;AAEnC,IAAA,IAAI;AACA,MAAA,QAAA,GAAW,MAAM,gBAAA,CAAiB,GAAA,EAAK,OAAO,CAAA;AAE9C,MAAA,IAAI,QAAA,CAAS,UAAU,GAAA,EAAK;AACxB,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,0CAAA,EAA6C,SAAS,CAAA,wFAAA,CAA0F,CAAA;AAAA,MACpK;AAEA,MAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AACd,QAAA,MAAM,IAAI,KAAA,CAAM,MAAM,QAAA,CAAS,MAAM,CAAA;AAAA,MACzC;AAAA,IACJ,SAAS,KAAA,EAAO;AACZ,MAAA,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,CAAA,4BAAA,EAA+B,KAAK,CAAA,CAAE,CAAA;AACxD,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,4BAAA,EAA+B,KAAK,CAAA,CAAE,CAAA;AAAA,IAC1D;AAAA,EACJ;AAAA,EAEA,MAAM,gCAAA,CAAiC,SAAA,EAAmB,SAAA,EAAoC;AAC1F,IAAA,IAAI,QAAA;AAEJ,IAAA,IAAI,IAAA,CAAK,YAAY,EAAA,EAAI;AACrB,MAAA,IAAA,CAAK,OAAA,GAAU,MAAM,IAAA,CAAK,SAAA,CAAU,WAAW,WAAW,CAAA;AAAA,IAC9D;AAEA,IAAA,MAAM,OAAA,GAAuB;AAAA,MACzB,MAAA,EAAQ,QAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACL,cAAA,EAAgB,iCAAA;AAAA,QAChB,MAAA,EAAQ;AAAA,OACZ;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,SAAS;AAAA,KAClC;AAEA,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,MAAM,IAAA,CAAK,SAAA,CAAU,UAAA;AAAA,MAChC;AAAA,KACH,yBAAyB,SAAS,CAAA,CAAA;AAEnC,IAAA,IAAI;AACA,MAAA,QAAA,GAAW,MAAM,gBAAA,CAAiB,GAAA,EAAK,OAAO,CAAA;AAE9C,MAAA,IAAI,QAAA,CAAS,UAAU,GAAA,EAAK;AACxB,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,+CAAA,EAAkD,SAAS,CAAA,wFAAA,CAA0F,CAAA;AAAA,MACzK;AAEA,MAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AACzB,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,QAAA,EAAW,SAAS,CAAA,2BAAA,CAA6B,CAAA;AAAA,MACrE;AAEA,MAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AACd,QAAA,MAAM,IAAI,KAAA,CAAM,MAAM,QAAA,CAAS,MAAM,CAAA;AAAA,MACzC;AAAA,IACJ,SAAS,KAAA,EAAO;AACZ,MAAA,IAAA,CAAK,OAAO,KAAA,CAAM,CAAA,mCAAA,EAAsC,SAAS,CAAA,EAAA,EAAK,KAAK,CAAA,CAAE,CAAA;AAC7E,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mCAAA,EAAsC,SAAS,CAAA,EAAA,EAAK,KAAK,CAAA,CAAE,CAAA;AAAA,IAC/E;AAAA,EACJ;AAAA,EAEA,MAAM,qBAAA,GAAyD;AAC3D,IAAA,IAAI,QAAA;AACJ,IAAA,MAAM,WAAmC,EAAC;AAE1C,IAAA,IAAI,IAAA,CAAK,YAAY,EAAA,EAAI;AACrB,MAAA,IAAA,CAAK,OAAA,GAAU,MAAM,IAAA,CAAK,SAAA,CAAU,WAAW,WAAW,CAAA;AAAA,IAC9D;AAEA,IAAA,MAAM,OAAA,GAAuB;AAAA,MACzB,MAAA,EAAQ,KAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACL,cAAA,EAAgB,iCAAA;AAAA,QAChB,MAAA,EAAQ;AAAA;AACZ,KACJ;AAEA,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,MAAM,IAAA,CAAK,SAAA,CAAU,UAAA;AAAA,MAChC;AAAA,KACH,CAAA,eAAA,CAAA;AAED,IAAA,IAAI;AACA,MAAA,QAAA,GAAW,MAAM,gBAAA,CAAiB,GAAA,EAAK,OAAO,CAAA;AAE9C,MAAA,IAAI,QAAA,CAAS,UAAU,GAAA,EAAK;AACxB,QAAA,MAAM,IAAI,MAAM,CAAA,gHAAA,CAAkH,CAAA;AAAA,MACtI;AAEA,MAAA,MAAM,aAAA,GAAiD,MAAM,QAAA,CAAS,IAAA,EAAK;AAE3E,MAAA,QAAQ,SAAS,MAAA;AAAQ,QACrB,KAAK,GAAA;AACD,UAAA,MAAM,IAAI,KAAA,CAAM,MAAM,QAAA,CAAS,MAAM,CAAA;AAAA,QACzC,KAAK,GAAA;AACD,UAAA,OAAO,QAAA;AAAA,QACX;AACI,UAAA,aAAA,CAAc,QAAA,CAAS,QAAQ,CAAA,OAAA,KAAW;AACtC,YAAA,QAAA,CAAS,OAAA,CAAQ,SAAS,CAAA,GAAI,OAAA,CAAQ,SAAA;AAAA,UAC1C,CAAC,CAAA;AAED,UAAA,OAAO,QAAA;AAAA;AACf,IACJ,SAAS,KAAA,EAAO;AACZ,MAAA,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,CAAA,6BAAA,EAAgC,KAAK,CAAA,CAAE,CAAA;AACzD,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,6BAAA,EAAgC,KAAK,CAAA,CAAE,CAAA;AAAA,IAC3D;AAAA,EACJ;AAAA,EAEA,MAAM,kBAAA,CAAmB,EAAE,IAAA,EAAM,SAAA,EAAW,MAAK,EAA2D;AACxG,IAAA,IAAI,QAAA;AAEJ,IAAA,IAAI,IAAA,CAAK,YAAY,EAAA,EAAI;AACrB,MAAA,IAAA,CAAK,OAAA,GAAU,MAAM,IAAA,CAAK,SAAA,CAAU,WAAW,WAAW,CAAA;AAAA,IAC9D;AAEA,IAAA,MAAM,OAAA,GAAuB;AAAA,MACzB,MAAA,EAAQ,KAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACL,cAAA,EAAgB,iCAAA;AAAA,QAChB,MAAA,EAAQ;AAAA;AACZ,KACJ;AAEA,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,MAAM,IAAA,CAAK,SAAA,CAAU,UAAA;AAAA,MAChC;AAAA,KACH,CAAA,gBAAA,EAAmB,IAAI,CAAA,CAAA,EAAI,SAAS,IAAI,IAAI,CAAA,CAAA;AAE7C,IAAA,IAAI;AACA,MAAA,QAAA,GAAW,MAAM,gBAAA,CAAiB,GAAA,EAAK,OAAO,CAAA;AAE9C,MAAA,IAAI,QAAA,CAAS,UAAU,GAAA,EAAK;AACxB,QAAA,MAAM,IAAI,MAAM,CAAA,4GAAA,CAA8G,CAAA;AAAA,MAClI;AAEA,MAAA,MAAM,YAAA,GAA+C,MAAM,QAAA,CAAS,IAAA,EAAK;AAEzE,MAAA,QAAQ,SAAS,MAAA;AAAQ,QACrB,KAAK,GAAA;AACD,UAAA,MAAM,IAAI,KAAA,CAAM,MAAM,QAAA,CAAS,MAAM,CAAA;AAAA,QACzC,KAAK,GAAA;AACD,UAAA,OAAO,KAAA,CAAA;AAAA,QACX;AACI,UAAA,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,CAAA,kBAAA,EAAqB,IAAI,IAAI,SAAS,CAAA,CAAA,EAAI,IAAI,CAAA,EAAA,EAAK,IAAA,CAAK,SAAA,CAAU,YAAA,CAAa,OAAO,CAAC,CAAA,CAAE,CAAA;AAE3G,UAAA,OAAO;AAAA,YACH,SAAA,EAAW,aAAa,OAAA,CAAQ,SAAA;AAAA,YAChC,cAAA,EAAgB,aAAa,OAAA,CAAQ,cAAA;AAAA,YACrC,SAAA,EAAW,aAAa,OAAA,CAAQ,SAAA;AAAA,YAChC,OAAA,EAAS,aAAa,OAAA,CAAQ;AAAA,WAClC;AAAA;AACR,IACJ,SAAS,KAAA,EAAO;AACZ,MAAA,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,CAAA,+BAAA,EAAkC,IAAI,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,EAAI,IAAI,CAAA,EAAA,EAAK,KAAK,CAAA,CAAE,CAAA;AACzF,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,+BAAA,EAAkC,IAAI,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,EAAI,IAAI,CAAA,EAAA,EAAK,KAAK,CAAA,CAAE,CAAA;AAAA,IAC3F;AAAA,EACJ;AAAA,EAEA,MAAM,uBAAuB,SAAA,EAAuD;AAChF,IAAA,IAAI,QAAA;AAEJ,IAAA,IAAI,IAAA,CAAK,YAAY,EAAA,EAAI;AACrB,MAAA,IAAA,CAAK,OAAA,GAAU,MAAM,IAAA,CAAK,SAAA,CAAU,WAAW,WAAW,CAAA;AAAA,IAC9D;AAEA,IAAA,MAAM,OAAA,GAAuB;AAAA,MACzB,MAAA,EAAQ,KAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACL,cAAA,EAAgB,iCAAA;AAAA,QAChB,MAAA,EAAQ;AAAA;AACZ,KACJ;AAEA,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,MAAM,IAAA,CAAK,SAAA,CAAU,UAAA;AAAA,MAChC;AAAA,KACH,2BAA2B,SAAS,CAAA,CAAA;AAErC,IAAA,IAAI;AACA,MAAA,QAAA,GAAW,MAAM,gBAAA,CAAiB,GAAA,EAAK,OAAO,CAAA;AAE9C,MAAA,IAAI,QAAA,CAAS,UAAU,GAAA,EAAK;AACxB,QAAA,MAAM,IAAI,MAAM,CAAA,kHAAA,CAAoH,CAAA;AAAA,MACxI;AAEA,MAAA,MAAM,YAAA,GAA+C,MAAM,QAAA,CAAS,IAAA,EAAK;AAEzE,MAAA,QAAQ,SAAS,MAAA;AAAQ,QACrB,KAAK,GAAA;AACD,UAAA,MAAM,IAAI,KAAA,CAAM,MAAM,QAAA,CAAS,MAAM,CAAA;AAAA,QACzC,KAAK,GAAA;AACD,UAAA,OAAO,KAAA,CAAA;AAAA,QACX;AACI,UAAA,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,CAAA,4BAAA,EAA+B,SAAS,CAAA,EAAA,EAAK,KAAK,SAAA,CAAU,YAAA,CAAa,OAAO,CAAC,CAAA,CAAE,CAAA;AAErG,UAAA,OAAO;AAAA,YACH,SAAA,EAAW,aAAa,OAAA,CAAQ,SAAA;AAAA,YAChC,cAAA,EAAgB,aAAa,OAAA,CAAQ,cAAA;AAAA,YACrC,SAAA,EAAW,aAAa,OAAA,CAAQ,SAAA;AAAA,YAChC,OAAA,EAAS,aAAa,OAAA,CAAQ;AAAA,WAClC;AAAA;AACR,IACJ,SAAS,KAAA,EAAO;AACZ,MAAA,IAAA,CAAK,OAAO,KAAA,CAAM,CAAA,yCAAA,EAA4C,SAAS,CAAA,EAAA,EAAK,KAAK,CAAA,CAAE,CAAA;AACnF,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,yCAAA,EAA4C,SAAS,CAAA,EAAA,EAAK,KAAK,CAAA,CAAE,CAAA;AAAA,IACrF;AAAA,EACJ;AAAA,EAEA,MAAM,qBAAqB,OAAA,EAAgD;AACvE,IAAA,IAAI,QAAA;AAEJ,IAAA,IAAI,IAAA,CAAK,YAAY,EAAA,EAAI;AACrB,MAAA,IAAA,CAAK,OAAA,GAAU,MAAM,IAAA,CAAK,SAAA,CAAU,WAAW,WAAW,CAAA;AAAA,IAC9D;AAEA,IAAA,MAAM,OAAA,GAAuB;AAAA,MACzB,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACL,cAAA,EAAgB,iCAAA;AAAA,QAChB,MAAA,EAAQ;AAAA,OACZ;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,OAAO;AAAA,KAChC;AAEA,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,MAAM,IAAA,CAAK,SAAA,CAAU,UAAA;AAAA,MAChC;AAAA,KACH,CAAA,eAAA,CAAA;AAED,IAAA,IAAI;AACA,MAAA,QAAA,GAAW,MAAM,gBAAA,CAAiB,GAAA,EAAK,OAAO,CAAA;AAE9C,MAAA,IAAI,QAAA,CAAS,UAAU,GAAA,EAAK;AACxB,QAAA,MAAM,IAAI,MAAM,CAAA,2GAAA,CAA6G,CAAA;AAAA,MACjI;AAEA,MAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AACd,QAAA,MAAM,IAAI,KAAA,CAAM,MAAM,QAAA,CAAS,MAAM,CAAA;AAAA,MACzC;AAAA,IACJ,SAAS,KAAA,EAAO;AACZ,MAAA,IAAA,CAAK,OAAO,KAAA,CAAM,CAAA,0BAAA,EAA6B,QAAQ,SAAS,CAAA,EAAA,EAAK,KAAK,CAAA,CAAE,CAAA;AAC5E,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,0BAAA,EAA6B,QAAQ,SAAS,CAAA,EAAA,EAAK,KAAK,CAAA,CAAE,CAAA;AAAA,IAC9E;AAAA,EACJ;AAAA,EAEA,MAAM,sBAAA,CAAuB,SAAA,EAAmB,OAAA,EAAyD;AACrG,IAAA,IAAI,QAAA;AAEJ,IAAA,IAAI,IAAA,CAAK,YAAY,EAAA,EAAI;AACrB,MAAA,IAAA,CAAK,OAAA,GAAU,MAAM,IAAA,CAAK,SAAA,CAAU,WAAW,WAAW,CAAA;AAAA,IAC9D;AAEA,IAAA,MAAM,OAAA,GAAuB;AAAA,MACzB,MAAA,EAAQ,KAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACL,cAAA,EAAgB,iCAAA;AAAA,QAChB,MAAA,EAAQ;AAAA;AACZ,KACJ;AAEA,IAAA,IAAI,GAAA,GAAM,CAAA,EAAG,MAAM,IAAA,CAAK,SAAA,CAAU,UAAA;AAAA,MAC9B;AAAA,KACH,yBAAyB,SAAS,CAAA,CAAA;AAEnC,IAAA,IAAI,OAAA,EAAS;AACT,MAAA,GAAA,GAAM,GAAA,CAAI,MAAA,CAAO,CAAA,SAAA,EAAY,OAAO,CAAA,CAAE,CAAA;AAAA,IAC1C;AAEA,IAAA,IAAI;AACA,MAAA,QAAA,GAAW,MAAM,gBAAA,CAAiB,GAAA,EAAK,OAAO,CAAA;AAE9C,MAAA,IAAI,QAAA,CAAS,UAAU,GAAA,EAAK;AACxB,QAAA,MAAM,IAAI,MAAM,CAAA,yHAAA,CAA2H,CAAA;AAAA,MAC/I;AAEA,MAAA,MAAM,iBAAA,GAAwD,MAAM,QAAA,CAAS,IAAA,EAAK;AAElF,MAAA,QAAQ,SAAS,MAAA;AAAQ,QACrB,KAAK,GAAA;AACD,UAAA,MAAM,IAAI,KAAA,CAAM,MAAM,QAAA,CAAS,MAAM,CAAA;AAAA,QACzC,KAAK,GAAA;AACD,UAAA,OAAO,EAAC;AAAA,QACZ;AACI,UAAA,OAAO,iBAAA,CAAkB,aAAA;AAAA;AACjC,IACJ,SAAS,KAAA,EAAO;AACZ,MAAA,IAAA,CAAK,OAAO,KAAA,CAAM,CAAA,+BAAA,EAAkC,SAAS,CAAA,EAAA,EAAK,KAAK,CAAA,CAAE,CAAA;AACzE,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,+BAAA,EAAkC,SAAS,CAAA,EAAA,EAAK,KAAK,CAAA,CAAE,CAAA;AAAA,IAC3E;AAAA,EACJ;AAAA,EAEA,MAAM,kCAAkC,SAAA,EAAoC;AACxE,IAAA,IAAI,QAAA;AAEJ,IAAA,IAAI,IAAA,CAAK,YAAY,EAAA,EAAI;AACrB,MAAA,IAAA,CAAK,OAAA,GAAU,MAAM,IAAA,CAAK,SAAA,CAAU,WAAW,WAAW,CAAA;AAAA,IAC9D;AAEA,IAAA,MAAM,OAAA,GAAuB;AAAA,MACzB,MAAA,EAAQ,KAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACL,cAAA,EAAgB,iCAAA;AAAA,QAChB,MAAA,EAAQ;AAAA;AACZ,KACJ;AAGA,IAAA,MAAM,CAAC,IAAA,EAAM,IAAI,CAAA,GAAI,SAAA,CAAU,MAAM,GAAG,CAAA;AACxC,IAAA,MAAM,CAAC,SAAA,EAAW,IAAI,CAAA,GAAI,IAAA,CAAK,MAAM,GAAG,CAAA;AAExC,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,MAAM,IAAA,CAAK,SAAA,CAAU,UAAA;AAAA,MAChC;AAAA,KACH,CAAA,gBAAA,EAAmB,IAAI,CAAA,CAAA,EAAI,SAAS,IAAI,IAAI,CAAA,CAAA;AAE7C,IAAA,IAAI;AACA,MAAA,QAAA,GAAW,MAAM,gBAAA,CAAiB,GAAA,EAAK,OAAO,CAAA;AAE9C,MAAA,IAAI,QAAA,CAAS,UAAU,GAAA,EAAK;AACxB,QAAA,MAAM,IAAI,MAAM,CAAA,8HAAA,CAAgI,CAAA;AAAA,MACpJ;AAEA,MAAA,MAAM,cAAA,GAAyB,MAAM,QAAA,CAAS,IAAA,EAAK;AAEnD,MAAA,QAAQ,SAAS,MAAA;AAAQ,QACrB,KAAK,GAAA;AACD,UAAA,MAAM,IAAI,KAAA,CAAM,MAAM,QAAA,CAAS,MAAM,CAAA;AAAA,QACzC,KAAK,GAAA;AACD,UAAA,OAAO,EAAA;AAAA,QACX;AACI,UAAA,OAAO,cAAA;AAAA;AACf,IACJ,SAAS,KAAA,EAAO;AACZ,MAAA,IAAA,CAAK,OAAO,KAAA,CAAM,CAAA,8CAAA,EAAiD,SAAS,CAAA,EAAA,EAAK,KAAK,CAAA,CAAE,CAAA;AACxF,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,8CAAA,EAAiD,SAAS,CAAA,EAAA,EAAK,KAAK,CAAA,CAAE,CAAA;AAAA,IAC1F;AAAA,EACJ;AAAA,EAEA,MAAM,8BAAA,CAA+B,cAAA,EAAwB,OAAA,EAAmC;AAC5F,IAAA,IAAI,QAAA;AAEJ,IAAA,IAAI,IAAA,CAAK,YAAY,EAAA,EAAI;AACrB,MAAA,IAAA,CAAK,OAAA,GAAU,MAAM,IAAA,CAAK,SAAA,CAAU,WAAW,WAAW,CAAA;AAAA,IAC9D;AAEA,IAAA,MAAM,OAAA,GAAuB;AAAA,MACzB,MAAA,EAAQ,KAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACL,cAAA,EAAgB,iCAAA;AAAA,QAChB,MAAA,EAAQ;AAAA;AACZ,KACJ;AAEA,IAAA,IAAI,GAAA,GAAM,CAAA,EAAG,MAAM,IAAA,CAAK,SAAA,CAAU,UAAA;AAAA,MAC9B;AAAA,KACH,6BAA6B,cAAc,CAAA,CAAA;AAE5C,IAAA,IAAI,OAAA,EAAS;AACT,MAAA,GAAA,GAAM,GAAA,CAAI,MAAA,CAAO,CAAA,SAAA,EAAY,OAAO,CAAA,CAAE,CAAA;AAAA,IAC1C;AAEA,IAAA,IAAI;AACA,MAAA,QAAA,GAAW,MAAM,gBAAA,CAAiB,GAAA,EAAK,OAAO,CAAA;AAE9C,MAAA,IAAI,QAAA,CAAS,UAAU,GAAA,EAAK;AACxB,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,8CAAA,EAAiD,cAAc,CAAA,wFAAA,CAA0F,CAAA;AAAA,MAC7K;AAEA,MAAA,MAAM,YAAA,GAAyC,MAAM,QAAA,CAAS,IAAA,EAAK;AAEnE,MAAA,QAAQ,SAAS,MAAA;AAAQ,QACrB,KAAK,GAAA;AACD,UAAA,MAAM,IAAI,KAAA,CAAM,MAAM,QAAA,CAAS,MAAM,CAAA;AAAA,QACzC,KAAK,GAAA;AACD,UAAA,OAAO,EAAA;AAAA,QACX;AACI,UAAA,OAAO,aAAa,OAAA,CAAQ,EAAA;AAAA;AACpC,IACJ,SAAS,KAAA,EAAO;AACZ,MAAA,IAAA,CAAK,OAAO,KAAA,CAAM,CAAA,8DAAA,EAAiE,cAAc,CAAA,EAAA,EAAK,KAAK,CAAA,CAAE,CAAA;AAC7G,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,8DAAA,EAAiE,cAAc,CAAA,EAAA,EAAK,KAAK,CAAA,CAAE,CAAA;AAAA,IAC/G;AAAA,EACJ;AAAA,EAEA,MAAM,8BAAA,CAA+B,SAAA,EAAmB,OAAA,EAA+C;AACnG,IAAA,IAAI,QAAA;AAEJ,IAAA,IAAI,IAAA,CAAK,YAAY,EAAA,EAAI;AACrB,MAAA,IAAA,CAAK,OAAA,GAAU,MAAM,IAAA,CAAK,SAAA,CAAU,WAAW,WAAW,CAAA;AAAA,IAC9D;AAEA,IAAA,MAAM,OAAA,GAAuB;AAAA,MACzB,MAAA,EAAQ,KAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACL,cAAA,EAAgB,iCAAA;AAAA,QAChB,MAAA,EAAQ;AAAA;AACZ,KACJ;AAEA,IAAA,IAAI,GAAA,GAAM,CAAA,EAAG,MAAM,IAAA,CAAK,SAAA,CAAU,UAAA;AAAA,MAC9B;AAAA,KACH,aAAa,SAAS,CAAA,CAAA;AAEvB,IAAA,IAAI,OAAA,EAAS;AACT,MAAA,GAAA,GAAM,GAAA,CAAI,MAAA,CAAO,CAAA,SAAA,EAAY,OAAO,CAAA,CAAE,CAAA;AAAA,IAC1C;AAEA,IAAA,IAAI;AACA,MAAA,QAAA,GAAW,MAAM,gBAAA,CAAiB,GAAA,EAAK,OAAO,CAAA;AAE9C,MAAA,IAAI,QAAA,CAAS,UAAU,GAAA,EAAK;AACxB,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,8CAAA,EAAiD,SAAS,CAAA,wFAAA,CAA0F,CAAA;AAAA,MACxK;AAEA,MAAA,MAAM,YAAA,GAAyC,MAAM,QAAA,CAAS,IAAA,EAAK;AACnE,MAAA,MAAM,oBAAA,GAAuB,aAAa,OAAA,CAAQ,YAAA,EAAc,KAAK,CAAA,WAAA,KAAe,WAAA,CAAY,MAAA,EAAQ,EAAA,KAAO,SAAS,CAAA;AAExH,MAAA,QAAQ,SAAS,MAAA;AAAQ,QACrB,KAAK,GAAA;AACD,UAAA,MAAM,IAAI,KAAA,CAAM,MAAM,QAAA,CAAS,MAAM,CAAA;AAAA,QACzC,KAAK,GAAA;AACD,UAAA,OAAO,EAAA;AAAA,QACX;AAEI,UAAA,IAAI,CAAC,oBAAA,EAAsB;AACvB,YAAA,OAAO,KAAA,CAAA;AAAA,UACX;AAEA,UAAA,OAAO,oBAAA,CAAqB,eAAA;AAAA;AACpC,IACJ,SAAS,KAAA,EAAO;AACZ,MAAA,IAAA,CAAK,OAAO,KAAA,CAAM,CAAA,8CAAA,EAAiD,SAAS,CAAA,EAAA,EAAK,KAAK,CAAA,CAAE,CAAA;AACxF,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,8CAAA,EAAiD,SAAS,CAAA,EAAA,EAAK,KAAK,CAAA,CAAE,CAAA;AAAA,IAC1F;AAAA,EACJ;AAAA,EAEA,MAAM,mCAAA,GAAuD;AACzD,IAAA,MAAM,gCAAA,GAAmC,4CAAA;AAEzC,IAAA,IAAI,QAAA;AAEJ,IAAA,IAAI,IAAA,CAAK,YAAY,EAAA,EAAI;AACrB,MAAA,IAAA,CAAK,OAAA,GAAU,MAAM,IAAA,CAAK,SAAA,CAAU,WAAW,WAAW,CAAA;AAAA,IAC9D;AAEA,IAAA,MAAM,OAAA,GAAuB;AAAA,MACzB,MAAA,EAAQ,KAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACL,cAAA,EAAgB,iCAAA;AAAA,QAChB,MAAA,EAAQ;AAAA;AACZ,KACJ;AAEA,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,MAAM,IAAA,CAAK,SAAA,CAAU,UAAA;AAAA,MAChC;AAAA,KACH,aAAa,gCAAgC,CAAA,CAAA;AAE9C,IAAA,IAAI;AACA,MAAA,QAAA,GAAW,MAAM,gBAAA,CAAiB,GAAA,EAAK,OAAO,CAAA;AAE9C,MAAA,IAAI,QAAA,CAAS,UAAU,GAAA,EAAK;AACxB,QAAA,MAAM,IAAI,MAAM,CAAA,sHAAA,CAAwH,CAAA;AAAA,MAC5I;AAEA,MAAA,MAAM,OAAA,GAA4B,MAAM,QAAA,CAAS,IAAA,EAAK;AAEtD,MAAA,QAAQ,SAAS,MAAA;AAAQ,QACrB,KAAK,GAAA;AACD,UAAA,MAAM,IAAI,KAAA,CAAM,MAAM,QAAA,CAAS,MAAM,CAAA;AAAA,QACzC,KAAK,GAAA;AACD,UAAA,OAAO,UAAA;AAAA;AAAA,QACX;AACI,UAAA,OAAO,OAAA,CAAQ,KAAA;AAAA;AACvB,IACJ,SAAS,KAAA,EAAO;AACZ,MAAA,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,CAAA,iCAAA,EAAoC,KAAK,CAAA,CAAE,CAAA;AAC7D,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,iCAAA,EAAoC,KAAK,CAAA,CAAE,CAAA;AAAA,IAC/D;AAAA,EACJ;AACJ;AAEA,eAAsB,gBAAA,CAAiB,KAAa,OAAA,EAAyC;AACzF,EAAA,IAAI,QAAA;AACJ,EAAA,IAAI,KAAA,GAAe,IAAI,KAAA,EAAM;AAG7B,EAAA,MAAM,UAAA,GAAa,CAAA;AACnB,EAAA,MAAM,KAAA,GAAQ,GAAA;AACd,EAAA,IAAI,MAAA,GAAS,CAAA;AAEb,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,UAAA,EAAY,CAAA,EAAA,EAAK;AACjC,IAAA,IAAI;AACA,MAAA,QAAA,GAAW,MAAMA,sBAAA,CAAM,GAAA,EAAK,OAAO,CAAA;AACnC,MAAA,OAAO,QAAA;AAAA,IACX,SAAS,CAAA,EAAG;AACR,MAAA,KAAA,GAAQ,CAAA;AAAA,IACZ;AAEA,IAAA,MAAM,UAAU,KAAA,GAAQ,MAAA;AACxB,IAAA,MAAM,IAAI,OAAA,CAAQ,CAAA,OAAA,KAAW,UAAA,CAAW,OAAA,EAAS,OAAO,CAAC,CAAA;AACzD,IAAA,MAAA,IAAU,CAAA;AAAA,EACd;AAEA,EAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,UAAU,CAAA,sBAAA,EAAyB,KAAK,CAAA,CAAE,CAAA;AAC5F;;;;;"}
|