@pipeline-builder/pipeline-data 3.4.85 → 3.4.87

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.
@@ -0,0 +1,457 @@
1
+ /**
2
+ * User-editable observability dashboard. Replaces the code-defined dashboards
3
+ * under `frontend/src/lib/dashboards/*.ts` so operators can add panels and
4
+ * customize layout per-org without a redeploy.
5
+ *
6
+ * `layoutJson` carries the react-grid-layout coordinate set keyed by panel id;
7
+ * `dashboard_panels` holds the panel-content rows so an N-panel dashboard
8
+ * doesn't bloat one row's JSON to several KB. The catalog query is referenced
9
+ * by key only (see platform/src/observability/catalog.ts) the dashboard
10
+ * record never carries raw PromQL/LogQL, keeping the catalog as the security
11
+ * boundary for upstream query execution.
12
+ *
13
+ * Visibility ladder * - `private` only the creator can read/write
14
+ * - `org` anyone in the same org can read; org admins + creator can write
15
+ * - `public` every authenticated user can read; only sysadmins can write.
16
+ * Used for the 5 default dashboards (`org_id='system'`) so the
17
+ * existing system-org visibility rule covers them by default.
18
+ *
19
+ * @table dashboards
20
+ */
21
+ export declare const dashboard: import("drizzle-orm/pg-core").PgTableWithColumns<{
22
+ name: "dashboards";
23
+ schema: undefined;
24
+ columns: {
25
+ id: import("drizzle-orm/pg-core").PgColumn<{
26
+ name: "id";
27
+ tableName: "dashboards";
28
+ dataType: "string";
29
+ columnType: "PgUUID";
30
+ data: string;
31
+ driverParam: string;
32
+ notNull: true;
33
+ hasDefault: true;
34
+ isPrimaryKey: true;
35
+ isAutoincrement: false;
36
+ hasRuntimeDefault: false;
37
+ enumValues: undefined;
38
+ baseColumn: never;
39
+ identity: undefined;
40
+ generated: undefined;
41
+ }, {}, {}>;
42
+ orgId: import("drizzle-orm/pg-core").PgColumn<{
43
+ name: "org_id";
44
+ tableName: "dashboards";
45
+ dataType: "string";
46
+ columnType: "PgVarchar";
47
+ data: string;
48
+ driverParam: string;
49
+ notNull: true;
50
+ hasDefault: true;
51
+ isPrimaryKey: false;
52
+ isAutoincrement: false;
53
+ hasRuntimeDefault: false;
54
+ enumValues: [string, ...string[]];
55
+ baseColumn: never;
56
+ identity: undefined;
57
+ generated: undefined;
58
+ }, {}, {
59
+ length: 255;
60
+ }>;
61
+ createdBy: import("drizzle-orm/pg-core").PgColumn<{
62
+ name: "created_by";
63
+ tableName: "dashboards";
64
+ dataType: "string";
65
+ columnType: "PgText";
66
+ data: string;
67
+ driverParam: string;
68
+ notNull: true;
69
+ hasDefault: true;
70
+ isPrimaryKey: false;
71
+ isAutoincrement: false;
72
+ hasRuntimeDefault: false;
73
+ enumValues: [string, ...string[]];
74
+ baseColumn: never;
75
+ identity: undefined;
76
+ generated: undefined;
77
+ }, {}, {}>;
78
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
79
+ name: "created_at";
80
+ tableName: "dashboards";
81
+ dataType: "date";
82
+ columnType: "PgTimestamp";
83
+ data: Date;
84
+ driverParam: string;
85
+ notNull: true;
86
+ hasDefault: true;
87
+ isPrimaryKey: false;
88
+ isAutoincrement: false;
89
+ hasRuntimeDefault: false;
90
+ enumValues: undefined;
91
+ baseColumn: never;
92
+ identity: undefined;
93
+ generated: undefined;
94
+ }, {}, {}>;
95
+ updatedBy: import("drizzle-orm/pg-core").PgColumn<{
96
+ name: "updated_by";
97
+ tableName: "dashboards";
98
+ dataType: "string";
99
+ columnType: "PgText";
100
+ data: string;
101
+ driverParam: string;
102
+ notNull: true;
103
+ hasDefault: true;
104
+ isPrimaryKey: false;
105
+ isAutoincrement: false;
106
+ hasRuntimeDefault: false;
107
+ enumValues: [string, ...string[]];
108
+ baseColumn: never;
109
+ identity: undefined;
110
+ generated: undefined;
111
+ }, {}, {}>;
112
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
113
+ name: "updated_at";
114
+ tableName: "dashboards";
115
+ dataType: "date";
116
+ columnType: "PgTimestamp";
117
+ data: Date;
118
+ driverParam: string;
119
+ notNull: true;
120
+ hasDefault: true;
121
+ isPrimaryKey: false;
122
+ isAutoincrement: false;
123
+ hasRuntimeDefault: false;
124
+ enumValues: undefined;
125
+ baseColumn: never;
126
+ identity: undefined;
127
+ generated: undefined;
128
+ }, {}, {}>;
129
+ name: import("drizzle-orm/pg-core").PgColumn<{
130
+ name: "name";
131
+ tableName: "dashboards";
132
+ dataType: "string";
133
+ columnType: "PgVarchar";
134
+ data: string;
135
+ driverParam: string;
136
+ notNull: true;
137
+ hasDefault: false;
138
+ isPrimaryKey: false;
139
+ isAutoincrement: false;
140
+ hasRuntimeDefault: false;
141
+ enumValues: [string, ...string[]];
142
+ baseColumn: never;
143
+ identity: undefined;
144
+ generated: undefined;
145
+ }, {}, {
146
+ length: 150;
147
+ }>;
148
+ description: import("drizzle-orm/pg-core").PgColumn<{
149
+ name: "description";
150
+ tableName: "dashboards";
151
+ dataType: "string";
152
+ columnType: "PgText";
153
+ data: string;
154
+ driverParam: string;
155
+ notNull: false;
156
+ hasDefault: false;
157
+ isPrimaryKey: false;
158
+ isAutoincrement: false;
159
+ hasRuntimeDefault: false;
160
+ enumValues: [string, ...string[]];
161
+ baseColumn: never;
162
+ identity: undefined;
163
+ generated: undefined;
164
+ }, {}, {}>;
165
+ layoutJson: import("drizzle-orm/pg-core").PgColumn<{
166
+ name: "layout_json";
167
+ tableName: "dashboards";
168
+ dataType: "json";
169
+ columnType: "PgJsonb";
170
+ data: Record<string, {
171
+ x: number;
172
+ y: number;
173
+ w: number;
174
+ h: number;
175
+ minW?: number;
176
+ minH?: number;
177
+ }>;
178
+ driverParam: unknown;
179
+ notNull: true;
180
+ hasDefault: true;
181
+ isPrimaryKey: false;
182
+ isAutoincrement: false;
183
+ hasRuntimeDefault: false;
184
+ enumValues: undefined;
185
+ baseColumn: never;
186
+ identity: undefined;
187
+ generated: undefined;
188
+ }, {}, {
189
+ $type: Record<string, {
190
+ x: number;
191
+ y: number;
192
+ w: number;
193
+ h: number;
194
+ minW?: number;
195
+ minH?: number;
196
+ }>;
197
+ }>;
198
+ visibility: import("drizzle-orm/pg-core").PgColumn<{
199
+ name: "visibility";
200
+ tableName: "dashboards";
201
+ dataType: "string";
202
+ columnType: "PgVarchar";
203
+ data: "public" | "private" | "org";
204
+ driverParam: string;
205
+ notNull: true;
206
+ hasDefault: true;
207
+ isPrimaryKey: false;
208
+ isAutoincrement: false;
209
+ hasRuntimeDefault: false;
210
+ enumValues: [string, ...string[]];
211
+ baseColumn: never;
212
+ identity: undefined;
213
+ generated: undefined;
214
+ }, {}, {
215
+ length: 10;
216
+ $type: "public" | "private" | "org";
217
+ }>;
218
+ deletedAt: import("drizzle-orm/pg-core").PgColumn<{
219
+ name: "deleted_at";
220
+ tableName: "dashboards";
221
+ dataType: "date";
222
+ columnType: "PgTimestamp";
223
+ data: Date;
224
+ driverParam: string;
225
+ notNull: false;
226
+ hasDefault: false;
227
+ isPrimaryKey: false;
228
+ isAutoincrement: false;
229
+ hasRuntimeDefault: false;
230
+ enumValues: undefined;
231
+ baseColumn: never;
232
+ identity: undefined;
233
+ generated: undefined;
234
+ }, {}, {}>;
235
+ deletedBy: import("drizzle-orm/pg-core").PgColumn<{
236
+ name: "deleted_by";
237
+ tableName: "dashboards";
238
+ dataType: "string";
239
+ columnType: "PgText";
240
+ data: string;
241
+ driverParam: string;
242
+ notNull: false;
243
+ hasDefault: false;
244
+ isPrimaryKey: false;
245
+ isAutoincrement: false;
246
+ hasRuntimeDefault: false;
247
+ enumValues: [string, ...string[]];
248
+ baseColumn: never;
249
+ identity: undefined;
250
+ generated: undefined;
251
+ }, {}, {}>;
252
+ };
253
+ dialect: "pg";
254
+ }>;
255
+ /**
256
+ * A single panel inside a dashboard. The catalog `queryKey` is the only thing
257
+ * the panel carries from the query side substitution + execution happens
258
+ * server-side via the existing catalog, so no PromQL/LogQL travels with the
259
+ * panel record.
260
+ *
261
+ * @table dashboard_panels
262
+ */
263
+ export declare const dashboardPanel: import("drizzle-orm/pg-core").PgTableWithColumns<{
264
+ name: "dashboard_panels";
265
+ schema: undefined;
266
+ columns: {
267
+ id: import("drizzle-orm/pg-core").PgColumn<{
268
+ name: "id";
269
+ tableName: "dashboard_panels";
270
+ dataType: "string";
271
+ columnType: "PgUUID";
272
+ data: string;
273
+ driverParam: string;
274
+ notNull: true;
275
+ hasDefault: true;
276
+ isPrimaryKey: true;
277
+ isAutoincrement: false;
278
+ hasRuntimeDefault: false;
279
+ enumValues: undefined;
280
+ baseColumn: never;
281
+ identity: undefined;
282
+ generated: undefined;
283
+ }, {}, {}>;
284
+ dashboardId: import("drizzle-orm/pg-core").PgColumn<{
285
+ name: "dashboard_id";
286
+ tableName: "dashboard_panels";
287
+ dataType: "string";
288
+ columnType: "PgUUID";
289
+ data: string;
290
+ driverParam: string;
291
+ notNull: true;
292
+ hasDefault: false;
293
+ isPrimaryKey: false;
294
+ isAutoincrement: false;
295
+ hasRuntimeDefault: false;
296
+ enumValues: undefined;
297
+ baseColumn: never;
298
+ identity: undefined;
299
+ generated: undefined;
300
+ }, {}, {}>;
301
+ queryKey: import("drizzle-orm/pg-core").PgColumn<{
302
+ name: "query_key";
303
+ tableName: "dashboard_panels";
304
+ dataType: "string";
305
+ columnType: "PgVarchar";
306
+ data: string;
307
+ driverParam: string;
308
+ notNull: true;
309
+ hasDefault: false;
310
+ isPrimaryKey: false;
311
+ isAutoincrement: false;
312
+ hasRuntimeDefault: false;
313
+ enumValues: [string, ...string[]];
314
+ baseColumn: never;
315
+ identity: undefined;
316
+ generated: undefined;
317
+ }, {}, {
318
+ length: 100;
319
+ }>;
320
+ vizKind: import("drizzle-orm/pg-core").PgColumn<{
321
+ name: "viz_kind";
322
+ tableName: "dashboard_panels";
323
+ dataType: "string";
324
+ columnType: "PgVarchar";
325
+ data: string;
326
+ driverParam: string;
327
+ notNull: true;
328
+ hasDefault: true;
329
+ isPrimaryKey: false;
330
+ isAutoincrement: false;
331
+ hasRuntimeDefault: false;
332
+ enumValues: [string, ...string[]];
333
+ baseColumn: never;
334
+ identity: undefined;
335
+ generated: undefined;
336
+ }, {}, {
337
+ length: 30;
338
+ }>;
339
+ title: import("drizzle-orm/pg-core").PgColumn<{
340
+ name: "title";
341
+ tableName: "dashboard_panels";
342
+ dataType: "string";
343
+ columnType: "PgVarchar";
344
+ data: string;
345
+ driverParam: string;
346
+ notNull: true;
347
+ hasDefault: false;
348
+ isPrimaryKey: false;
349
+ isAutoincrement: false;
350
+ hasRuntimeDefault: false;
351
+ enumValues: [string, ...string[]];
352
+ baseColumn: never;
353
+ identity: undefined;
354
+ generated: undefined;
355
+ }, {}, {
356
+ length: 200;
357
+ }>;
358
+ span: import("drizzle-orm/pg-core").PgColumn<{
359
+ name: "span";
360
+ tableName: "dashboard_panels";
361
+ dataType: "number";
362
+ columnType: "PgInteger";
363
+ data: number;
364
+ driverParam: string | number;
365
+ notNull: true;
366
+ hasDefault: true;
367
+ isPrimaryKey: false;
368
+ isAutoincrement: false;
369
+ hasRuntimeDefault: false;
370
+ enumValues: undefined;
371
+ baseColumn: never;
372
+ identity: undefined;
373
+ generated: undefined;
374
+ }, {}, {}>;
375
+ groupBy: import("drizzle-orm/pg-core").PgColumn<{
376
+ name: "group_by";
377
+ tableName: "dashboard_panels";
378
+ dataType: "string";
379
+ columnType: "PgVarchar";
380
+ data: string;
381
+ driverParam: string;
382
+ notNull: false;
383
+ hasDefault: false;
384
+ isPrimaryKey: false;
385
+ isAutoincrement: false;
386
+ hasRuntimeDefault: false;
387
+ enumValues: [string, ...string[]];
388
+ baseColumn: never;
389
+ identity: undefined;
390
+ generated: undefined;
391
+ }, {}, {
392
+ length: 50;
393
+ }>;
394
+ format: import("drizzle-orm/pg-core").PgColumn<{
395
+ name: "format";
396
+ tableName: "dashboard_panels";
397
+ dataType: "string";
398
+ columnType: "PgVarchar";
399
+ data: string;
400
+ driverParam: string;
401
+ notNull: false;
402
+ hasDefault: false;
403
+ isPrimaryKey: false;
404
+ isAutoincrement: false;
405
+ hasRuntimeDefault: false;
406
+ enumValues: [string, ...string[]];
407
+ baseColumn: never;
408
+ identity: undefined;
409
+ generated: undefined;
410
+ }, {}, {
411
+ length: 20;
412
+ }>;
413
+ position: import("drizzle-orm/pg-core").PgColumn<{
414
+ name: "position";
415
+ tableName: "dashboard_panels";
416
+ dataType: "number";
417
+ columnType: "PgInteger";
418
+ data: number;
419
+ driverParam: string | number;
420
+ notNull: true;
421
+ hasDefault: true;
422
+ isPrimaryKey: false;
423
+ isAutoincrement: false;
424
+ hasRuntimeDefault: false;
425
+ enumValues: undefined;
426
+ baseColumn: never;
427
+ identity: undefined;
428
+ generated: undefined;
429
+ }, {}, {}>;
430
+ vars: import("drizzle-orm/pg-core").PgColumn<{
431
+ name: "vars";
432
+ tableName: "dashboard_panels";
433
+ dataType: "json";
434
+ columnType: "PgJsonb";
435
+ data: Record<string, string>;
436
+ driverParam: unknown;
437
+ notNull: true;
438
+ hasDefault: true;
439
+ isPrimaryKey: false;
440
+ isAutoincrement: false;
441
+ hasRuntimeDefault: false;
442
+ enumValues: undefined;
443
+ baseColumn: never;
444
+ identity: undefined;
445
+ generated: undefined;
446
+ }, {}, {
447
+ $type: Record<string, string>;
448
+ }>;
449
+ };
450
+ dialect: "pg";
451
+ }>;
452
+ export type Dashboard = typeof dashboard.$inferSelect;
453
+ export type DashboardInsert = typeof dashboard.$inferInsert;
454
+ export type DashboardUpdate = Partial<Omit<DashboardInsert, 'id' | 'createdAt' | 'createdBy'>>;
455
+ export type DashboardPanel = typeof dashboardPanel.$inferSelect;
456
+ export type DashboardPanelInsert = typeof dashboardPanel.$inferInsert;
457
+ export type DashboardPanelUpdate = Partial<Omit<DashboardPanelInsert, 'id'>>;
@@ -0,0 +1,120 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { SYSTEM_ORG_ID } from '@pipeline-builder/api-core';
4
+ import { integer, varchar, pgTable, text, timestamp, uuid, jsonb, index, uniqueIndex } from 'drizzle-orm/pg-core';
5
+ /**
6
+ * User-editable observability dashboard. Replaces the code-defined dashboards
7
+ * under `frontend/src/lib/dashboards/*.ts` so operators can add panels and
8
+ * customize layout per-org without a redeploy.
9
+ *
10
+ * `layoutJson` carries the react-grid-layout coordinate set keyed by panel id;
11
+ * `dashboard_panels` holds the panel-content rows so an N-panel dashboard
12
+ * doesn't bloat one row's JSON to several KB. The catalog query is referenced
13
+ * by key only (see platform/src/observability/catalog.ts) the dashboard
14
+ * record never carries raw PromQL/LogQL, keeping the catalog as the security
15
+ * boundary for upstream query execution.
16
+ *
17
+ * Visibility ladder * - `private` only the creator can read/write
18
+ * - `org` anyone in the same org can read; org admins + creator can write
19
+ * - `public` every authenticated user can read; only sysadmins can write.
20
+ * Used for the 5 default dashboards (`org_id='system'`) so the
21
+ * existing system-org visibility rule covers them by default.
22
+ *
23
+ * @table dashboards
24
+ */
25
+ export const dashboard = pgTable('dashboards', {
26
+ id: uuid('id').primaryKey().defaultRandom(),
27
+ // Org + creator
28
+ orgId: varchar('org_id', { length: 255 })
29
+ .default(SYSTEM_ORG_ID)
30
+ .notNull(),
31
+ createdBy: text('created_by')
32
+ .default(SYSTEM_ORG_ID)
33
+ .notNull(),
34
+ createdAt: timestamp('created_at', { withTimezone: true })
35
+ .defaultNow()
36
+ .notNull(),
37
+ updatedBy: text('updated_by')
38
+ .default(SYSTEM_ORG_ID)
39
+ .notNull(),
40
+ updatedAt: timestamp('updated_at', { withTimezone: true })
41
+ .defaultNow()
42
+ .notNull(),
43
+ // Identity
44
+ name: varchar('name', { length: 150 })
45
+ .notNull(),
46
+ description: text('description'),
47
+ // react-grid-layout coordinate set keyed by panel id.
48
+ // Shape: { [panelId]: { x, y, w, h, minW?, minH? } }
49
+ layoutJson: jsonb('layout_json')
50
+ .$type()
51
+ .default({})
52
+ .notNull(),
53
+ // Visibility see header for ladder semantics. Constrained at the SQL
54
+ // layer too via a CHECK in postgres-init.sql to keep typos from sneaking
55
+ // past the application layer.
56
+ visibility: varchar('visibility', { length: 10 })
57
+ .$type()
58
+ .default('private')
59
+ .notNull(),
60
+ // Soft delete (matches the rest of the schema's convention)
61
+ deletedAt: timestamp('deleted_at', { withTimezone: true }),
62
+ deletedBy: text('deleted_by'),
63
+ }, (table) => ({
64
+ // Listing is org-scoped and visibility-filtered, so both go in the index.
65
+ orgVisibilityIdx: index('dashboard_org_visibility_idx').on(table.orgId, table.visibility),
66
+ // Convenience for "all my dashboards" listing
67
+ createdByIdx: index('dashboard_created_by_idx').on(table.createdBy),
68
+ // Same-org duplicate-name guard. The (orgId, name) tuple is unique among
69
+ // non-deleted rows; soft-deleted rows are excluded so name reuse after
70
+ // deletion works.
71
+ nameUnique: uniqueIndex('dashboard_org_name_unique').on(table.orgId, table.name),
72
+ }));
73
+ /**
74
+ * A single panel inside a dashboard. The catalog `queryKey` is the only thing
75
+ * the panel carries from the query side substitution + execution happens
76
+ * server-side via the existing catalog, so no PromQL/LogQL travels with the
77
+ * panel record.
78
+ *
79
+ * @table dashboard_panels
80
+ */
81
+ export const dashboardPanel = pgTable('dashboard_panels', {
82
+ id: uuid('id').primaryKey().defaultRandom(),
83
+ dashboardId: uuid('dashboard_id')
84
+ .notNull(),
85
+ // Catalog key (e.g. `plugin_builds_per_min`). The server validates this
86
+ // against QUERIES at render time.
87
+ queryKey: varchar('query_key', { length: 100 })
88
+ .notNull(),
89
+ // 'stat' | 'line' | 'table' | 'stacked-bar' kept stringly-typed for
90
+ // forward compatibility; the renderer falls back to 'line' on unknown.
91
+ vizKind: varchar('viz_kind', { length: 30 })
92
+ .default('line')
93
+ .notNull(),
94
+ title: varchar('title', { length: 200 })
95
+ .notNull(),
96
+ // Tailwind col-span tier (1-12, but only 3/4/6/8/9/12 are renderable).
97
+ span: integer('span')
98
+ .default(6)
99
+ .notNull(),
100
+ // Optional: label key for series grouping (e.g. 'status', 'state').
101
+ groupBy: varchar('group_by', { length: 50 }),
102
+ // Optional: catalog format key ('percent' | 'seconds' |...).
103
+ format: varchar('format', { length: 20 }),
104
+ // 0-based render order within the dashboard. Editor reassigns on drag.
105
+ position: integer('position')
106
+ .default(0)
107
+ .notNull(),
108
+ // Optional template var values bound at panel level (e.g. `plugin=X` for
109
+ // the per-plugin drill-down panel). Sanitized server-side via the catalog
110
+ // substituteVars allow-list.
111
+ vars: jsonb('vars')
112
+ .$type()
113
+ .default({})
114
+ .notNull(),
115
+ }, (table) => ({
116
+ // The render path is "fetch all panels for dashboard X in order".
117
+ dashboardPositionIdx: index('dashboard_panel_dashboard_position_idx')
118
+ .on(table.dashboardId, table.position),
119
+ }));
120
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGFzaGJvYXJkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2RhdGFiYXNlL3NjaGVtYS9kYXNoYm9hcmQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDM0QsT0FBTyxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFbEg7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FtQkc7QUFDSCxNQUFNLENBQUMsTUFBTSxTQUFTLEdBQUcsT0FBTyxDQUFDLFlBQVksRUFBRTtJQUM3QyxFQUFFLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLFVBQVUsRUFBRSxDQUFDLGFBQWEsRUFBRTtJQUUzQyxnQkFBZ0I7SUFDaEIsS0FBSyxFQUFFLE9BQU8sQ0FBQyxRQUFRLEVBQUUsRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUM7U0FDdEMsT0FBTyxDQUFDLGFBQWEsQ0FBQztTQUN0QixPQUFPLEVBQUU7SUFDWixTQUFTLEVBQUUsSUFBSSxDQUFDLFlBQVksQ0FBQztTQUMxQixPQUFPLENBQUMsYUFBYSxDQUFDO1NBQ3RCLE9BQU8sRUFBRTtJQUNaLFNBQVMsRUFBRSxTQUFTLENBQUMsWUFBWSxFQUFFLEVBQUUsWUFBWSxFQUFFLElBQUksRUFBRSxDQUFDO1NBQ3ZELFVBQVUsRUFBRTtTQUNaLE9BQU8sRUFBRTtJQUNaLFNBQVMsRUFBRSxJQUFJLENBQUMsWUFBWSxDQUFDO1NBQzFCLE9BQU8sQ0FBQyxhQUFhLENBQUM7U0FDdEIsT0FBTyxFQUFFO0lBQ1osU0FBUyxFQUFFLFNBQVMsQ0FBQyxZQUFZLEVBQUUsRUFBRSxZQUFZLEVBQUUsSUFBSSxFQUFFLENBQUM7U0FDdkQsVUFBVSxFQUFFO1NBQ1osT0FBTyxFQUFFO0lBRVosV0FBVztJQUNYLElBQUksRUFBRSxPQUFPLENBQUMsTUFBTSxFQUFFLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDO1NBQ25DLE9BQU8sRUFBRTtJQUNaLFdBQVcsRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDO0lBRWhDLHNEQUFzRDtJQUN0RCxxREFBcUQ7SUFDckQsVUFBVSxFQUFFLEtBQUssQ0FBQyxhQUFhLENBQUM7U0FDN0IsS0FBSyxFQUFnRztTQUNyRyxPQUFPLENBQUMsRUFBRSxDQUFDO1NBQ1gsT0FBTyxFQUFFO0lBRVosc0VBQXNFO0lBQ3RFLHlFQUF5RTtJQUN6RSw4QkFBOEI7SUFDOUIsVUFBVSxFQUFFLE9BQU8sQ0FBQyxZQUFZLEVBQUUsRUFBRSxNQUFNLEVBQUUsRUFBRSxFQUFFLENBQUM7U0FDOUMsS0FBSyxFQUFnQztTQUNyQyxPQUFPLENBQUMsU0FBUyxDQUFDO1NBQ2xCLE9BQU8sRUFBRTtJQUVaLDREQUE0RDtJQUM1RCxTQUFTLEVBQUUsU0FBUyxDQUFDLFlBQVksRUFBRSxFQUFFLFlBQVksRUFBRSxJQUFJLEVBQUUsQ0FBQztJQUMxRCxTQUFTLEVBQUUsSUFBSSxDQUFDLFlBQVksQ0FBQztDQUM5QixFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ2IsMEVBQTBFO0lBQzFFLGdCQUFnQixFQUFFLEtBQUssQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxVQUFVLENBQUM7SUFDekYsOENBQThDO0lBQzlDLFlBQVksRUFBRSxLQUFLLENBQUMsMEJBQTBCLENBQUMsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQztJQUNuRSx5RUFBeUU7SUFDekUsdUVBQXVFO0lBQ3ZFLGtCQUFrQjtJQUNsQixVQUFVLEVBQUUsV0FBVyxDQUFDLDJCQUEyQixDQUFDLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQztDQUNqRixDQUFDLENBQUMsQ0FBQztBQUVKOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUcsT0FBTyxDQUFDLGtCQUFrQixFQUFFO0lBQ3hELEVBQUUsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsVUFBVSxFQUFFLENBQUMsYUFBYSxFQUFFO0lBQzNDLFdBQVcsRUFBRSxJQUFJLENBQUMsY0FBYyxDQUFDO1NBQzlCLE9BQU8sRUFBRTtJQUNaLHdFQUF3RTtJQUN4RSxrQ0FBa0M7SUFDbEMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxXQUFXLEVBQUUsRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUM7U0FDNUMsT0FBTyxFQUFFO0lBQ1oscUVBQXFFO0lBQ3JFLHVFQUF1RTtJQUN2RSxPQUFPLEVBQUUsT0FBTyxDQUFDLFVBQVUsRUFBRSxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUUsQ0FBQztTQUN6QyxPQUFPLENBQUMsTUFBTSxDQUFDO1NBQ2YsT0FBTyxFQUFFO0lBQ1osS0FBSyxFQUFFLE9BQU8sQ0FBQyxPQUFPLEVBQUUsRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUM7U0FDckMsT0FBTyxFQUFFO0lBQ1osdUVBQXVFO0lBQ3ZFLElBQUksRUFBRSxPQUFPLENBQUMsTUFBTSxDQUFDO1NBQ2xCLE9BQU8sQ0FBQyxDQUFDLENBQUM7U0FDVixPQUFPLEVBQUU7SUFDWixvRUFBb0U7SUFDcEUsT0FBTyxFQUFFLE9BQU8sQ0FBQyxVQUFVLEVBQUUsRUFBRSxNQUFNLEVBQUUsRUFBRSxFQUFFLENBQUM7SUFDNUMsNkRBQTZEO0lBQzdELE1BQU0sRUFBRSxPQUFPLENBQUMsUUFBUSxFQUFFLEVBQUUsTUFBTSxFQUFFLEVBQUUsRUFBRSxDQUFDO0lBQ3pDLHVFQUF1RTtJQUN2RSxRQUFRLEVBQUUsT0FBTyxDQUFDLFVBQVUsQ0FBQztTQUMxQixPQUFPLENBQUMsQ0FBQyxDQUFDO1NBQ1YsT0FBTyxFQUFFO0lBQ1oseUVBQXlFO0lBQ3pFLDBFQUEwRTtJQUMxRSw2QkFBNkI7SUFDN0IsSUFBSSxFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUM7U0FDaEIsS0FBSyxFQUEwQjtTQUMvQixPQUFPLENBQUMsRUFBRSxDQUFDO1NBQ1gsT0FBTyxFQUFFO0NBQ2IsRUFBRSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNiLGtFQUFrRTtJQUNsRSxvQkFBb0IsRUFBRSxLQUFLLENBQUMsd0NBQXdDLENBQUM7U0FDbEUsRUFBRSxDQUFDLEtBQUssQ0FBQyxXQUFXLEVBQUUsS0FBSyxDQUFDLFFBQVEsQ0FBQztDQUN6QyxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyBTWVNURU1fT1JHX0lEIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuaW1wb3J0IHsgaW50ZWdlciwgdmFyY2hhciwgcGdUYWJsZSwgdGV4dCwgdGltZXN0YW1wLCB1dWlkLCBqc29uYiwgaW5kZXgsIHVuaXF1ZUluZGV4IH0gZnJvbSAnZHJpenpsZS1vcm0vcGctY29yZSc7XG5cbi8qKlxuICogVXNlci1lZGl0YWJsZSBvYnNlcnZhYmlsaXR5IGRhc2hib2FyZC4gUmVwbGFjZXMgdGhlIGNvZGUtZGVmaW5lZCBkYXNoYm9hcmRzXG4gKiB1bmRlciBgZnJvbnRlbmQvc3JjL2xpYi9kYXNoYm9hcmRzLyoudHNgIHNvIG9wZXJhdG9ycyBjYW4gYWRkIHBhbmVscyBhbmRcbiAqIGN1c3RvbWl6ZSBsYXlvdXQgcGVyLW9yZyB3aXRob3V0IGEgcmVkZXBsb3kuXG4gKlxuICogYGxheW91dEpzb25gIGNhcnJpZXMgdGhlIHJlYWN0LWdyaWQtbGF5b3V0IGNvb3JkaW5hdGUgc2V0IGtleWVkIGJ5IHBhbmVsIGlkO1xuICogYGRhc2hib2FyZF9wYW5lbHNgIGhvbGRzIHRoZSBwYW5lbC1jb250ZW50IHJvd3Mgc28gYW4gTi1wYW5lbCBkYXNoYm9hcmRcbiAqIGRvZXNuJ3QgYmxvYXQgb25lIHJvdydzIEpTT04gdG8gc2V2ZXJhbCBLQi4gVGhlIGNhdGFsb2cgcXVlcnkgaXMgcmVmZXJlbmNlZFxuICogYnkga2V5IG9ubHkgKHNlZSBwbGF0Zm9ybS9zcmMvb2JzZXJ2YWJpbGl0eS9jYXRhbG9nLnRzKSAgdGhlIGRhc2hib2FyZFxuICogcmVjb3JkIG5ldmVyIGNhcnJpZXMgcmF3IFByb21RTC9Mb2dRTCwga2VlcGluZyB0aGUgY2F0YWxvZyBhcyB0aGUgc2VjdXJpdHlcbiAqIGJvdW5kYXJ5IGZvciB1cHN0cmVhbSBxdWVyeSBleGVjdXRpb24uXG4gKlxuICogVmlzaWJpbGl0eSBsYWRkZXIgKiAtIGBwcml2YXRlYCAgb25seSB0aGUgY3JlYXRvciBjYW4gcmVhZC93cml0ZVxuICogLSBgb3JnYCAgYW55b25lIGluIHRoZSBzYW1lIG9yZyBjYW4gcmVhZDsgb3JnIGFkbWlucyArIGNyZWF0b3IgY2FuIHdyaXRlXG4gKiAtIGBwdWJsaWNgICBldmVyeSBhdXRoZW50aWNhdGVkIHVzZXIgY2FuIHJlYWQ7IG9ubHkgc3lzYWRtaW5zIGNhbiB3cml0ZS5cbiAqIFVzZWQgZm9yIHRoZSA1IGRlZmF1bHQgZGFzaGJvYXJkcyAoYG9yZ19pZD0nc3lzdGVtJ2ApIHNvIHRoZVxuICogZXhpc3Rpbmcgc3lzdGVtLW9yZyB2aXNpYmlsaXR5IHJ1bGUgY292ZXJzIHRoZW0gYnkgZGVmYXVsdC5cbiAqXG4gKiBAdGFibGUgZGFzaGJvYXJkc1xuICovXG5leHBvcnQgY29uc3QgZGFzaGJvYXJkID0gcGdUYWJsZSgnZGFzaGJvYXJkcycsIHtcbiAgaWQ6IHV1aWQoJ2lkJykucHJpbWFyeUtleSgpLmRlZmF1bHRSYW5kb20oKSxcblxuICAvLyBPcmcgKyBjcmVhdG9yXG4gIG9yZ0lkOiB2YXJjaGFyKCdvcmdfaWQnLCB7IGxlbmd0aDogMjU1IH0pXG4gICAgLmRlZmF1bHQoU1lTVEVNX09SR19JRClcbiAgICAubm90TnVsbCgpLFxuICBjcmVhdGVkQnk6IHRleHQoJ2NyZWF0ZWRfYnknKVxuICAgIC5kZWZhdWx0KFNZU1RFTV9PUkdfSUQpXG4gICAgLm5vdE51bGwoKSxcbiAgY3JlYXRlZEF0OiB0aW1lc3RhbXAoJ2NyZWF0ZWRfYXQnLCB7IHdpdGhUaW1lem9uZTogdHJ1ZSB9KVxuICAgIC5kZWZhdWx0Tm93KClcbiAgICAubm90TnVsbCgpLFxuICB1cGRhdGVkQnk6IHRleHQoJ3VwZGF0ZWRfYnknKVxuICAgIC5kZWZhdWx0KFNZU1RFTV9PUkdfSUQpXG4gICAgLm5vdE51bGwoKSxcbiAgdXBkYXRlZEF0OiB0aW1lc3RhbXAoJ3VwZGF0ZWRfYXQnLCB7IHdpdGhUaW1lem9uZTogdHJ1ZSB9KVxuICAgIC5kZWZhdWx0Tm93KClcbiAgICAubm90TnVsbCgpLFxuXG4gIC8vIElkZW50aXR5XG4gIG5hbWU6IHZhcmNoYXIoJ25hbWUnLCB7IGxlbmd0aDogMTUwIH0pXG4gICAgLm5vdE51bGwoKSxcbiAgZGVzY3JpcHRpb246IHRleHQoJ2Rlc2NyaXB0aW9uJyksXG5cbiAgLy8gcmVhY3QtZ3JpZC1sYXlvdXQgY29vcmRpbmF0ZSBzZXQga2V5ZWQgYnkgcGFuZWwgaWQuXG4gIC8vIFNoYXBlOiB7IFtwYW5lbElkXTogeyB4LCB5LCB3LCBoLCBtaW5XPywgbWluSD8gfSB9XG4gIGxheW91dEpzb246IGpzb25iKCdsYXlvdXRfanNvbicpXG4gICAgLiR0eXBlPFJlY29yZDxzdHJpbmcsIHsgeDogbnVtYmVyOyB5OiBudW1iZXI7IHc6IG51bWJlcjsgaDogbnVtYmVyOyBtaW5XPzogbnVtYmVyOyBtaW5IPzogbnVtYmVyIH0+PigpXG4gICAgLmRlZmF1bHQoe30pXG4gICAgLm5vdE51bGwoKSxcblxuICAvLyBWaXNpYmlsaXR5ICBzZWUgaGVhZGVyIGZvciBsYWRkZXIgc2VtYW50aWNzLiBDb25zdHJhaW5lZCBhdCB0aGUgU1FMXG4gIC8vIGxheWVyIHRvbyB2aWEgYSBDSEVDSyBpbiBwb3N0Z3Jlcy1pbml0LnNxbCB0byBrZWVwIHR5cG9zIGZyb20gc25lYWtpbmdcbiAgLy8gcGFzdCB0aGUgYXBwbGljYXRpb24gbGF5ZXIuXG4gIHZpc2liaWxpdHk6IHZhcmNoYXIoJ3Zpc2liaWxpdHknLCB7IGxlbmd0aDogMTAgfSlcbiAgICAuJHR5cGU8J3ByaXZhdGUnIHwgJ29yZycgfCAncHVibGljJz4oKVxuICAgIC5kZWZhdWx0KCdwcml2YXRlJylcbiAgICAubm90TnVsbCgpLFxuXG4gIC8vIFNvZnQgZGVsZXRlIChtYXRjaGVzIHRoZSByZXN0IG9mIHRoZSBzY2hlbWEncyBjb252ZW50aW9uKVxuICBkZWxldGVkQXQ6IHRpbWVzdGFtcCgnZGVsZXRlZF9hdCcsIHsgd2l0aFRpbWV6b25lOiB0cnVlIH0pLFxuICBkZWxldGVkQnk6IHRleHQoJ2RlbGV0ZWRfYnknKSxcbn0sICh0YWJsZSkgPT4gKHtcbiAgLy8gTGlzdGluZyBpcyBvcmctc2NvcGVkIGFuZCB2aXNpYmlsaXR5LWZpbHRlcmVkLCBzbyBib3RoIGdvIGluIHRoZSBpbmRleC5cbiAgb3JnVmlzaWJpbGl0eUlkeDogaW5kZXgoJ2Rhc2hib2FyZF9vcmdfdmlzaWJpbGl0eV9pZHgnKS5vbih0YWJsZS5vcmdJZCwgdGFibGUudmlzaWJpbGl0eSksXG4gIC8vIENvbnZlbmllbmNlIGZvciBcImFsbCBteSBkYXNoYm9hcmRzXCIgbGlzdGluZ1xuICBjcmVhdGVkQnlJZHg6IGluZGV4KCdkYXNoYm9hcmRfY3JlYXRlZF9ieV9pZHgnKS5vbih0YWJsZS5jcmVhdGVkQnkpLFxuICAvLyBTYW1lLW9yZyBkdXBsaWNhdGUtbmFtZSBndWFyZC4gVGhlIChvcmdJZCwgbmFtZSkgdHVwbGUgaXMgdW5pcXVlIGFtb25nXG4gIC8vIG5vbi1kZWxldGVkIHJvd3M7IHNvZnQtZGVsZXRlZCByb3dzIGFyZSBleGNsdWRlZCBzbyBuYW1lIHJldXNlIGFmdGVyXG4gIC8vIGRlbGV0aW9uIHdvcmtzLlxuICBuYW1lVW5pcXVlOiB1bmlxdWVJbmRleCgnZGFzaGJvYXJkX29yZ19uYW1lX3VuaXF1ZScpLm9uKHRhYmxlLm9yZ0lkLCB0YWJsZS5uYW1lKSxcbn0pKTtcblxuLyoqXG4gKiBBIHNpbmdsZSBwYW5lbCBpbnNpZGUgYSBkYXNoYm9hcmQuIFRoZSBjYXRhbG9nIGBxdWVyeUtleWAgaXMgdGhlIG9ubHkgdGhpbmdcbiAqIHRoZSBwYW5lbCBjYXJyaWVzIGZyb20gdGhlIHF1ZXJ5IHNpZGUgIHN1YnN0aXR1dGlvbiArIGV4ZWN1dGlvbiBoYXBwZW5zXG4gKiBzZXJ2ZXItc2lkZSB2aWEgdGhlIGV4aXN0aW5nIGNhdGFsb2csIHNvIG5vIFByb21RTC9Mb2dRTCB0cmF2ZWxzIHdpdGggdGhlXG4gKiBwYW5lbCByZWNvcmQuXG4gKlxuICogQHRhYmxlIGRhc2hib2FyZF9wYW5lbHNcbiAqL1xuZXhwb3J0IGNvbnN0IGRhc2hib2FyZFBhbmVsID0gcGdUYWJsZSgnZGFzaGJvYXJkX3BhbmVscycsIHtcbiAgaWQ6IHV1aWQoJ2lkJykucHJpbWFyeUtleSgpLmRlZmF1bHRSYW5kb20oKSxcbiAgZGFzaGJvYXJkSWQ6IHV1aWQoJ2Rhc2hib2FyZF9pZCcpXG4gICAgLm5vdE51bGwoKSxcbiAgLy8gQ2F0YWxvZyBrZXkgKGUuZy4gYHBsdWdpbl9idWlsZHNfcGVyX21pbmApLiBUaGUgc2VydmVyIHZhbGlkYXRlcyB0aGlzXG4gIC8vIGFnYWluc3QgUVVFUklFUyBhdCByZW5kZXIgdGltZS5cbiAgcXVlcnlLZXk6IHZhcmNoYXIoJ3F1ZXJ5X2tleScsIHsgbGVuZ3RoOiAxMDAgfSlcbiAgICAubm90TnVsbCgpLFxuICAvLyAnc3RhdCcgfCAnbGluZScgfCAndGFibGUnIHwgJ3N0YWNrZWQtYmFyJyAga2VwdCBzdHJpbmdseS10eXBlZCBmb3JcbiAgLy8gZm9yd2FyZCBjb21wYXRpYmlsaXR5OyB0aGUgcmVuZGVyZXIgZmFsbHMgYmFjayB0byAnbGluZScgb24gdW5rbm93bi5cbiAgdml6S2luZDogdmFyY2hhcigndml6X2tpbmQnLCB7IGxlbmd0aDogMzAgfSlcbiAgICAuZGVmYXVsdCgnbGluZScpXG4gICAgLm5vdE51bGwoKSxcbiAgdGl0bGU6IHZhcmNoYXIoJ3RpdGxlJywgeyBsZW5ndGg6IDIwMCB9KVxuICAgIC5ub3ROdWxsKCksXG4gIC8vIFRhaWx3aW5kIGNvbC1zcGFuIHRpZXIgKDEtMTIsIGJ1dCBvbmx5IDMvNC82LzgvOS8xMiBhcmUgcmVuZGVyYWJsZSkuXG4gIHNwYW46IGludGVnZXIoJ3NwYW4nKVxuICAgIC5kZWZhdWx0KDYpXG4gICAgLm5vdE51bGwoKSxcbiAgLy8gT3B0aW9uYWw6IGxhYmVsIGtleSBmb3Igc2VyaWVzIGdyb3VwaW5nIChlLmcuICdzdGF0dXMnLCAnc3RhdGUnKS5cbiAgZ3JvdXBCeTogdmFyY2hhcignZ3JvdXBfYnknLCB7IGxlbmd0aDogNTAgfSksXG4gIC8vIE9wdGlvbmFsOiBjYXRhbG9nIGZvcm1hdCBrZXkgKCdwZXJjZW50JyB8ICdzZWNvbmRzJyB8Li4uKS5cbiAgZm9ybWF0OiB2YXJjaGFyKCdmb3JtYXQnLCB7IGxlbmd0aDogMjAgfSksXG4gIC8vIDAtYmFzZWQgcmVuZGVyIG9yZGVyIHdpdGhpbiB0aGUgZGFzaGJvYXJkLiBFZGl0b3IgcmVhc3NpZ25zIG9uIGRyYWcuXG4gIHBvc2l0aW9uOiBpbnRlZ2VyKCdwb3NpdGlvbicpXG4gICAgLmRlZmF1bHQoMClcbiAgICAubm90TnVsbCgpLFxuICAvLyBPcHRpb25hbCB0ZW1wbGF0ZSB2YXIgdmFsdWVzIGJvdW5kIGF0IHBhbmVsIGxldmVsIChlLmcuIGBwbHVnaW49WGAgZm9yXG4gIC8vIHRoZSBwZXItcGx1Z2luIGRyaWxsLWRvd24gcGFuZWwpLiBTYW5pdGl6ZWQgc2VydmVyLXNpZGUgdmlhIHRoZSBjYXRhbG9nXG4gIC8vIHN1YnN0aXR1dGVWYXJzIGFsbG93LWxpc3QuXG4gIHZhcnM6IGpzb25iKCd2YXJzJylcbiAgICAuJHR5cGU8UmVjb3JkPHN0cmluZywgc3RyaW5nPj4oKVxuICAgIC5kZWZhdWx0KHt9KVxuICAgIC5ub3ROdWxsKCksXG59LCAodGFibGUpID0+ICh7XG4gIC8vIFRoZSByZW5kZXIgcGF0aCBpcyBcImZldGNoIGFsbCBwYW5lbHMgZm9yIGRhc2hib2FyZCBYIGluIG9yZGVyXCIuXG4gIGRhc2hib2FyZFBvc2l0aW9uSWR4OiBpbmRleCgnZGFzaGJvYXJkX3BhbmVsX2Rhc2hib2FyZF9wb3NpdGlvbl9pZHgnKVxuICAgIC5vbih0YWJsZS5kYXNoYm9hcmRJZCwgdGFibGUucG9zaXRpb24pLFxufSkpO1xuXG4vLyBPYnNlcnZhYmlsaXR5IGRhc2hib2FyZHNcbmV4cG9ydCB0eXBlIERhc2hib2FyZCA9IHR5cGVvZiBkYXNoYm9hcmQuJGluZmVyU2VsZWN0O1xuZXhwb3J0IHR5cGUgRGFzaGJvYXJkSW5zZXJ0ID0gdHlwZW9mIGRhc2hib2FyZC4kaW5mZXJJbnNlcnQ7XG5leHBvcnQgdHlwZSBEYXNoYm9hcmRVcGRhdGUgPSBQYXJ0aWFsPE9taXQ8RGFzaGJvYXJkSW5zZXJ0LCAnaWQnIHwgJ2NyZWF0ZWRBdCcgfCAnY3JlYXRlZEJ5Jz4+O1xuXG5leHBvcnQgdHlwZSBEYXNoYm9hcmRQYW5lbCA9IHR5cGVvZiBkYXNoYm9hcmRQYW5lbC4kaW5mZXJTZWxlY3Q7XG5leHBvcnQgdHlwZSBEYXNoYm9hcmRQYW5lbEluc2VydCA9IHR5cGVvZiBkYXNoYm9hcmRQYW5lbC4kaW5mZXJJbnNlcnQ7XG5leHBvcnQgdHlwZSBEYXNoYm9hcmRQYW5lbFVwZGF0ZSA9IFBhcnRpYWw8T21pdDxEYXNoYm9hcmRQYW5lbEluc2VydCwgJ2lkJz4+O1xuIl19