sonamu 0.9.8 → 0.9.10

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 (84) hide show
  1. package/dist/ai/agents/agent.d.ts.map +1 -1
  2. package/dist/ai/agents/agent.js +4 -2
  3. package/dist/ai/providers/rtzr/api.d.ts +1 -1
  4. package/dist/api/decorators.d.ts +0 -1
  5. package/dist/api/decorators.d.ts.map +1 -1
  6. package/dist/api/decorators.js +8 -6
  7. package/dist/api/sonamu.d.ts.map +1 -1
  8. package/dist/api/sonamu.js +123 -12
  9. package/dist/api/websocket-helpers.d.ts +1 -3
  10. package/dist/api/websocket-helpers.d.ts.map +1 -1
  11. package/dist/api/websocket-helpers.js +2 -15
  12. package/dist/stream/index.d.ts +3 -0
  13. package/dist/stream/index.d.ts.map +1 -1
  14. package/dist/stream/index.js +8 -2
  15. package/dist/stream/ws-core.d.ts +1 -0
  16. package/dist/stream/ws-core.d.ts.map +1 -1
  17. package/dist/stream/ws-delivery.d.ts +8 -0
  18. package/dist/stream/ws-delivery.d.ts.map +1 -1
  19. package/dist/stream/ws-delivery.js +160 -14
  20. package/dist/stream/ws-local-connection-store.d.ts +2 -0
  21. package/dist/stream/ws-local-connection-store.d.ts.map +1 -1
  22. package/dist/stream/ws-local-connection-store.js +21 -1
  23. package/dist/stream/ws-registry.d.ts +6 -2
  24. package/dist/stream/ws-registry.d.ts.map +1 -1
  25. package/dist/stream/ws-registry.js +170 -6
  26. package/dist/stream/ws-telemetry-memory.d.ts +28 -0
  27. package/dist/stream/ws-telemetry-memory.d.ts.map +1 -0
  28. package/dist/stream/ws-telemetry-memory.js +180 -0
  29. package/dist/stream/ws-telemetry-trace.d.ts +12 -0
  30. package/dist/stream/ws-telemetry-trace.d.ts.map +1 -0
  31. package/dist/stream/ws-telemetry-trace.js +41 -0
  32. package/dist/stream/ws-telemetry.d.ts +509 -0
  33. package/dist/stream/ws-telemetry.d.ts.map +1 -0
  34. package/dist/stream/ws-telemetry.js +931 -0
  35. package/dist/stream/ws.d.ts +10 -3
  36. package/dist/stream/ws.d.ts.map +1 -1
  37. package/dist/stream/ws.js +306 -27
  38. package/dist/syncer/file-patterns.js +2 -2
  39. package/dist/syncer/syncer-actions.d.ts +2 -8
  40. package/dist/syncer/syncer-actions.d.ts.map +1 -1
  41. package/dist/syncer/syncer-actions.js +4 -11
  42. package/dist/syncer/syncer.d.ts +1 -1
  43. package/dist/syncer/syncer.d.ts.map +1 -1
  44. package/dist/syncer/syncer.js +8 -6
  45. package/dist/template/template.d.ts +1 -2
  46. package/dist/template/template.d.ts.map +1 -1
  47. package/dist/template/template.js +3 -4
  48. package/dist/template/zod-converter.d.ts +2 -2
  49. package/dist/testing/dev-vitest-manager.d.ts +1 -1
  50. package/dist/testing/dev-vitest-manager.js +2 -2
  51. package/dist/types/types.d.ts +11 -5
  52. package/dist/types/types.d.ts.map +1 -1
  53. package/dist/types/types.js +2 -2
  54. package/dist/utils/class-name.d.ts +6 -0
  55. package/dist/utils/class-name.d.ts.map +1 -0
  56. package/dist/utils/class-name.js +19 -0
  57. package/package.json +2 -2
  58. package/src/ai/agents/agent.ts +2 -1
  59. package/src/api/__tests__/sonamu.websocket.test.ts +84 -10
  60. package/src/api/decorators.ts +6 -6
  61. package/src/api/sonamu.ts +142 -7
  62. package/src/api/websocket-helpers.ts +2 -28
  63. package/src/shared/app.shared.ts.txt +16 -8
  64. package/src/shared/web.shared.ts.txt +8 -7
  65. package/src/skills/sonamu/testing-devrunner.md +1 -1
  66. package/src/stream/__tests__/ws-telemetry.test.ts +821 -0
  67. package/src/stream/__tests__/ws.test.ts +362 -2
  68. package/src/stream/index.ts +3 -0
  69. package/src/stream/ws-core.ts +2 -0
  70. package/src/stream/ws-delivery.ts +161 -19
  71. package/src/stream/ws-local-connection-store.ts +33 -0
  72. package/src/stream/ws-registry.ts +186 -5
  73. package/src/stream/ws-telemetry-memory.ts +246 -0
  74. package/src/stream/ws-telemetry-trace.ts +52 -0
  75. package/src/stream/ws-telemetry.ts +1772 -0
  76. package/src/stream/ws.ts +332 -34
  77. package/src/syncer/file-patterns.ts +3 -3
  78. package/src/syncer/syncer-actions.ts +3 -15
  79. package/src/syncer/syncer.ts +9 -13
  80. package/src/template/__tests__/services.template.websocket.test.ts +2 -0
  81. package/src/template/template.ts +2 -3
  82. package/src/testing/dev-vitest-manager.ts +1 -1
  83. package/src/types/types.ts +10 -3
  84. package/src/utils/class-name.ts +12 -0
@@ -0,0 +1,931 @@
1
+ import { __esmMin } from "../_virtual/rolldown_runtime.js";
2
+ import { InMemoryEventStore, InMemoryMetricStore, InMemorySpanStore, init_ws_telemetry_memory } from "./ws-telemetry-memory.js";
3
+ import { generateSpanId, generateTraceId, init_ws_telemetry_trace, parseTraceParent } from "./ws-telemetry-trace.js";
4
+
5
+ //#region src/stream/ws-telemetry.ts
6
+ function isSensitiveKey(key) {
7
+ const normalized = key.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
8
+ return SENSITIVE_KEY_PATTERNS.some((pattern) => normalized.includes(pattern));
9
+ }
10
+ function redactValue(value, key) {
11
+ if (key !== undefined && isSensitiveKey(key)) {
12
+ return REDACTED_VALUE;
13
+ }
14
+ if (Array.isArray(value)) {
15
+ return value.map((item) => redactValue(item));
16
+ }
17
+ if (value instanceof Date) {
18
+ return value;
19
+ }
20
+ if (value && typeof value === "object") {
21
+ const redacted = {};
22
+ for (const [childKey, childValue] of Object.entries(value)) {
23
+ redacted[childKey] = redactValue(childValue, childKey);
24
+ }
25
+ return redacted;
26
+ }
27
+ return value;
28
+ }
29
+ /**
30
+ * defaultSensitiveKeyRedact — sensitive key 패턴 기반 built-in redactor.
31
+ * pipeline emit flow의 첫 단계에서 항상 적용된다.
32
+ */
33
+ function defaultSensitiveKeyRedact(record) {
34
+ if (record.type === "event") {
35
+ return {
36
+ ...record,
37
+ attributes: record.attributes ? redactValue(record.attributes) : undefined,
38
+ detail: record.detail ? redactValue(record.detail) : undefined,
39
+ payloadPreview: record.payloadPreview
40
+ };
41
+ }
42
+ if (record.type === "metric") {
43
+ return {
44
+ ...record,
45
+ tags: record.tags ? redactValue(record.tags) : undefined,
46
+ snapshot: record.snapshot ? { ...record.snapshot } : undefined
47
+ };
48
+ }
49
+ return {
50
+ ...record,
51
+ attributes: record.attributes ? redactValue(record.attributes) : undefined,
52
+ events: record.events?.map((event) => ({
53
+ ...event,
54
+ attributes: event.attributes ? redactValue(event.attributes) : undefined
55
+ })),
56
+ links: record.links?.map((link) => ({
57
+ ...link,
58
+ attributes: link.attributes ? redactValue(link.attributes) : undefined
59
+ }))
60
+ };
61
+ }
62
+ function truncatePayloadPreview(payload, maxBytes) {
63
+ try {
64
+ const serialized = JSON.stringify(redactValue(payload));
65
+ if (Buffer.byteLength(serialized, "utf-8") <= maxBytes) {
66
+ return serialized;
67
+ }
68
+ return truncateUtf8String(serialized, maxBytes);
69
+ } catch {
70
+ return "[unserializable]";
71
+ }
72
+ }
73
+ function truncateUtf8String(value, maxBytes) {
74
+ if (maxBytes <= 0) return "";
75
+ const suffix = maxBytes >= 3 ? "..." : "";
76
+ const contentBudget = maxBytes - Buffer.byteLength(suffix, "utf-8");
77
+ let result = "";
78
+ let usedBytes = 0;
79
+ for (const char of value) {
80
+ const charBytes = Buffer.byteLength(char, "utf-8");
81
+ if (usedBytes + charBytes > contentBudget) break;
82
+ result += char;
83
+ usedBytes += charBytes;
84
+ }
85
+ return result + suffix;
86
+ }
87
+ function isPromiseLike(value) {
88
+ return typeof value === "object" && value !== null && "then" in value && "catch" in value;
89
+ }
90
+ function buildController(options, runtimeMetadata) {
91
+ const defaults = options.defaults ?? {};
92
+ const eventsOpt = options.events ?? {};
93
+ const metricsOpt = options.metrics ?? {};
94
+ const spansOpt = options.spans ?? {};
95
+ const defaultsMaxRecordsPerSecond = defaults.maxRecordsPerSecond ?? DEFAULT_MAX_RECORDS_PER_SECOND;
96
+ const eventsSharedRedactor = eventsOpt.redactor === null ? undefined : defaults.redactor;
97
+ const eventsSignalRedactor = typeof eventsOpt.redactor === "function" ? eventsOpt.redactor : undefined;
98
+ const eventsSharedBeforeRecord = eventsOpt.beforeRecord === null ? undefined : defaults.beforeRecord;
99
+ const eventsSignalBeforeRecord = typeof eventsOpt.beforeRecord === "function" ? eventsOpt.beforeRecord : undefined;
100
+ const metricsSharedRedactor = metricsOpt.redactor === null ? undefined : defaults.redactor;
101
+ const metricsSignalRedactor = typeof metricsOpt.redactor === "function" ? metricsOpt.redactor : undefined;
102
+ const metricsSharedBeforeRecord = metricsOpt.beforeRecord === null ? undefined : defaults.beforeRecord;
103
+ const metricsSignalBeforeRecord = typeof metricsOpt.beforeRecord === "function" ? metricsOpt.beforeRecord : undefined;
104
+ const spansSharedRedactor = spansOpt.redactor === null ? undefined : defaults.redactor;
105
+ const spansSignalRedactor = typeof spansOpt.redactor === "function" ? spansOpt.redactor : undefined;
106
+ const spansSharedBeforeRecord = spansOpt.beforeRecord === null ? undefined : defaults.beforeRecord;
107
+ const spansSignalBeforeRecord = typeof spansOpt.beforeRecord === "function" ? spansOpt.beforeRecord : undefined;
108
+ const eventSinks = eventsOpt.sinks ? [...eventsOpt.sinks] : [];
109
+ let eventStore = eventsOpt.store;
110
+ if (eventSinks.length === 0 && eventStore === undefined) {
111
+ eventStore = new InMemoryEventStore({
112
+ maxRecords: eventsOpt.maxRecords ?? defaults.maxRecords,
113
+ maxBytes: eventsOpt.maxBytes ?? defaults.maxBytes
114
+ });
115
+ eventSinks.push(eventStore.sink);
116
+ } else if (eventStore !== undefined && !eventSinks.includes(eventStore.sink)) {
117
+ eventSinks.push(eventStore.sink);
118
+ }
119
+ const eventsResolved = {
120
+ sinks: eventSinks,
121
+ store: eventStore,
122
+ maxRecordsPerSecond: eventsOpt.sampling?.maxRecordsPerSecond ?? defaultsMaxRecordsPerSecond,
123
+ maxInFlightEmits: eventsOpt.maxInFlightEmits ?? DEFAULT_MAX_IN_FLIGHT_EMITS_PER_SINK,
124
+ sharedRedactor: eventsSharedRedactor,
125
+ signalRedactor: eventsSignalRedactor,
126
+ sharedBeforeRecord: eventsSharedBeforeRecord,
127
+ signalBeforeRecord: eventsSignalBeforeRecord,
128
+ sampling: {
129
+ defaultRate: eventsOpt.sampling?.defaultRate ?? DEFAULT_EVENT_SAMPLING_DEFAULT_RATE,
130
+ rateByEvent: eventsOpt.sampling?.rateByEvent ?? {},
131
+ alwaysRecordLevels: eventsOpt.sampling?.alwaysRecordLevels ?? [...DEFAULT_EVENT_ALWAYS_RECORD_LEVELS]
132
+ },
133
+ capturePayload: eventsOpt.capturePayload ?? DEFAULT_EVENT_CAPTURE_PAYLOAD,
134
+ maxPayloadPreviewBytes: eventsOpt.maxPayloadPreviewBytes ?? DEFAULT_EVENT_MAX_PAYLOAD_PREVIEW_BYTES
135
+ };
136
+ const metricSinks = metricsOpt.sinks ? [...metricsOpt.sinks] : [];
137
+ let metricStore = metricsOpt.store;
138
+ if (metricSinks.length === 0 && metricStore === undefined) {
139
+ metricStore = new InMemoryMetricStore({
140
+ maxRecords: metricsOpt.maxRecords ?? defaults.maxRecords,
141
+ maxBytes: metricsOpt.maxBytes ?? defaults.maxBytes
142
+ });
143
+ metricSinks.push(metricStore.sink);
144
+ } else if (metricStore !== undefined && !metricSinks.includes(metricStore.sink)) {
145
+ metricSinks.push(metricStore.sink);
146
+ }
147
+ const metricsResolved = {
148
+ sinks: metricSinks,
149
+ store: metricStore,
150
+ maxRecordsPerSecond: metricsOpt.sampling?.maxRecordsPerSecond ?? defaultsMaxRecordsPerSecond,
151
+ maxInFlightEmits: metricsOpt.maxInFlightEmits ?? DEFAULT_MAX_IN_FLIGHT_EMITS_PER_SINK,
152
+ sharedRedactor: metricsSharedRedactor,
153
+ signalRedactor: metricsSignalRedactor,
154
+ sharedBeforeRecord: metricsSharedBeforeRecord,
155
+ signalBeforeRecord: metricsSignalBeforeRecord,
156
+ collectionEnabled: metricsOpt.collectionEnabled ?? DEFAULT_METRIC_COLLECTION_ENABLED,
157
+ sampleIntervalMs: metricsOpt.sampleIntervalMs ?? DEFAULT_METRIC_SAMPLE_INTERVAL_MS
158
+ };
159
+ const spanSinks = spansOpt.sinks ? [...spansOpt.sinks] : [];
160
+ let spanStore = spansOpt.store;
161
+ if (spanSinks.length === 0 && spanStore === undefined) {
162
+ spanStore = new InMemorySpanStore({
163
+ maxRecords: spansOpt.maxRecords ?? defaults.maxRecords,
164
+ maxBytes: spansOpt.maxBytes ?? defaults.maxBytes
165
+ });
166
+ spanSinks.push(spanStore.sink);
167
+ } else if (spanStore !== undefined && !spanSinks.includes(spanStore.sink)) {
168
+ spanSinks.push(spanStore.sink);
169
+ }
170
+ const spansResolved = {
171
+ sinks: spanSinks,
172
+ store: spanStore,
173
+ maxRecordsPerSecond: spansOpt.sampling?.maxRecordsPerSecond ?? defaultsMaxRecordsPerSecond,
174
+ maxInFlightEmits: spansOpt.maxInFlightEmits ?? DEFAULT_MAX_IN_FLIGHT_EMITS_PER_SINK,
175
+ sharedRedactor: spansSharedRedactor,
176
+ signalRedactor: spansSignalRedactor,
177
+ sharedBeforeRecord: spansSharedBeforeRecord,
178
+ signalBeforeRecord: spansSignalBeforeRecord,
179
+ sampling: { defaultRate: spansOpt.sampling?.defaultRate ?? DEFAULT_SPAN_SAMPLING_DEFAULT_RATE }
180
+ };
181
+ const eventPipeline = new EventPipeline(eventsResolved, runtimeMetadata);
182
+ const metricPipeline = new MetricPipeline(metricsResolved, runtimeMetadata);
183
+ const spanPipeline = new SpanPipeline(spansResolved, runtimeMetadata);
184
+ const traceOptions = {
185
+ extractTraceParent: options.trace?.extractTraceParent ?? DEFAULT_TRACE_OPTIONS.extractTraceParent,
186
+ generateConnectionTrace: options.trace?.generateConnectionTrace ?? DEFAULT_TRACE_OPTIONS.generateConnectionTrace,
187
+ propagateMessageTrace: options.trace?.propagateMessageTrace ?? DEFAULT_TRACE_OPTIONS.propagateMessageTrace,
188
+ recordConnectionLifetimeSpan: options.trace?.recordConnectionLifetimeSpan ?? DEFAULT_TRACE_OPTIONS.recordConnectionLifetimeSpan
189
+ };
190
+ const shutdownTimeoutMs = options.shutdownTimeoutMs ?? DEFAULT_SHUTDOWN_TIMEOUT_MS;
191
+ return new WebSocketTelemetryControllerImpl(eventPipeline, metricPipeline, spanPipeline, traceOptions, runtimeMetadata, shutdownTimeoutMs);
192
+ }
193
+ function assertControllerOptionIsExclusive(options) {
194
+ const ignoredKeys = Object.entries(options).filter(([key, value]) => key !== "enabled" && key !== "controller" && value !== undefined).map(([key]) => key);
195
+ if (ignoredKeys.length === 0) return;
196
+ throw new Error(`WebSocket telemetry controller option cannot be combined with other telemetry options: ${ignoredKeys.join(", ")}`);
197
+ }
198
+ function createWebSocketTelemetryController(telemetryOption, runtimeMetadata) {
199
+ if (telemetryOption === undefined || telemetryOption === false) {
200
+ return new NoopWebSocketTelemetryController();
201
+ }
202
+ if (telemetryOption === true) {
203
+ return buildController({}, runtimeMetadata);
204
+ }
205
+ if (telemetryOption.enabled === false) {
206
+ return new NoopWebSocketTelemetryController();
207
+ }
208
+ if (telemetryOption.controller) {
209
+ assertControllerOptionIsExclusive(telemetryOption);
210
+ return telemetryOption.controller;
211
+ }
212
+ return buildController(telemetryOption, runtimeMetadata);
213
+ }
214
+ var EMPTY_METRICS_SNAPSHOT, DEFAULT_TRACE_OPTIONS, DEFAULT_MAX_RECORDS_PER_SECOND, DEFAULT_SHUTDOWN_TIMEOUT_MS, DEFAULT_EVENT_SAMPLING_DEFAULT_RATE, DEFAULT_EVENT_ALWAYS_RECORD_LEVELS, DEFAULT_EVENT_CAPTURE_PAYLOAD, DEFAULT_EVENT_MAX_PAYLOAD_PREVIEW_BYTES, DEFAULT_METRIC_COLLECTION_ENABLED, DEFAULT_METRIC_SAMPLE_INTERVAL_MS, DEFAULT_SPAN_SAMPLING_DEFAULT_RATE, DEFAULT_MAX_IN_FLIGHT_EMITS_PER_SINK, SENSITIVE_KEY_PATTERNS, REDACTED_VALUE, TokenBucket, noopUnsubscribe, NoopWebSocketTelemetryController, TelemetryPipeline, EventPipeline, MetricPipeline, SpanPipeline, WebSocketTelemetryControllerImpl;
215
+ var init_ws_telemetry = __esmMin((() => {
216
+ init_ws_telemetry_memory();
217
+ init_ws_telemetry_trace();
218
+ EMPTY_METRICS_SNAPSHOT = {
219
+ timestamp: 0,
220
+ activeConnections: 0,
221
+ activeConnectionsByNamespace: {},
222
+ roomCount: 0,
223
+ pendingInboundMessages: 0,
224
+ pendingOutboundMessages: 0,
225
+ socketBufferedBytes: 0,
226
+ pendingFanOutJobs: 0,
227
+ pendingFanOutTargets: 0,
228
+ telemetryDroppedRecords: 0,
229
+ telemetrySinkFailures: 0
230
+ };
231
+ DEFAULT_TRACE_OPTIONS = {
232
+ extractTraceParent: true,
233
+ generateConnectionTrace: true,
234
+ propagateMessageTrace: true,
235
+ recordConnectionLifetimeSpan: false
236
+ };
237
+ DEFAULT_MAX_RECORDS_PER_SECOND = 1e4;
238
+ DEFAULT_SHUTDOWN_TIMEOUT_MS = 2e3;
239
+ DEFAULT_EVENT_SAMPLING_DEFAULT_RATE = 1;
240
+ DEFAULT_EVENT_ALWAYS_RECORD_LEVELS = ["warn", "error"];
241
+ DEFAULT_EVENT_CAPTURE_PAYLOAD = false;
242
+ DEFAULT_EVENT_MAX_PAYLOAD_PREVIEW_BYTES = 1024;
243
+ DEFAULT_METRIC_COLLECTION_ENABLED = true;
244
+ DEFAULT_METRIC_SAMPLE_INTERVAL_MS = 1e4;
245
+ DEFAULT_SPAN_SAMPLING_DEFAULT_RATE = 1;
246
+ DEFAULT_MAX_IN_FLIGHT_EMITS_PER_SINK = 100;
247
+ SENSITIVE_KEY_PATTERNS = [
248
+ "authorization",
249
+ "cookie",
250
+ "token",
251
+ "password",
252
+ "secret",
253
+ "apikey",
254
+ "session",
255
+ "email"
256
+ ];
257
+ REDACTED_VALUE = "[redacted]";
258
+ TokenBucket = class {
259
+ tokens;
260
+ lastRefill;
261
+ constructor(maxTokens, refillRate) {
262
+ this.maxTokens = maxTokens;
263
+ this.refillRate = refillRate;
264
+ this.tokens = maxTokens;
265
+ this.lastRefill = Date.now();
266
+ }
267
+ tryConsume() {
268
+ this.refill();
269
+ if (this.tokens < 1) return false;
270
+ this.tokens -= 1;
271
+ return true;
272
+ }
273
+ refill() {
274
+ const now = Date.now();
275
+ const elapsed = (now - this.lastRefill) / 1e3;
276
+ this.tokens = Math.min(this.maxTokens, this.tokens + elapsed * this.refillRate);
277
+ this.lastRefill = now;
278
+ }
279
+ };
280
+ noopUnsubscribe = () => {};
281
+ NoopWebSocketTelemetryController = class {
282
+ emit(_input) {}
283
+ recordMetric(_input) {}
284
+ recordSpan(_input) {}
285
+ getMetricsSnapshot() {
286
+ return {
287
+ ...EMPTY_METRICS_SNAPSHOT,
288
+ timestamp: Date.now()
289
+ };
290
+ }
291
+ getEventStore() {
292
+ return undefined;
293
+ }
294
+ getMetricStore() {
295
+ return undefined;
296
+ }
297
+ getSpanStore() {
298
+ return undefined;
299
+ }
300
+ registerMetricSource(_source) {
301
+ return noopUnsubscribe;
302
+ }
303
+ createConnectionContext(_request) {
304
+ return {};
305
+ }
306
+ getTraceOptions() {
307
+ return { ...DEFAULT_TRACE_OPTIONS };
308
+ }
309
+ shutdown(_options) {
310
+ return Promise.resolve();
311
+ }
312
+ };
313
+ TelemetryPipeline = class {
314
+ sinks;
315
+ _store;
316
+ tokenBucket;
317
+ maxInFlightEmits;
318
+ runtimeMetadata;
319
+ sharedRedactor;
320
+ sharedBeforeRecord;
321
+ internalEventReporter;
322
+ inFlightEmits = new WeakMap();
323
+ droppedCount = 0;
324
+ sinkFailureCount = 0;
325
+ shutdownCalled = false;
326
+ constructor(sinks, store, maxRecordsPerSecond, maxInFlightEmits, sharedRedactor, sharedBeforeRecord, runtimeMetadata) {
327
+ this.sinks = sinks;
328
+ this._store = store;
329
+ this.tokenBucket = new TokenBucket(maxRecordsPerSecond, maxRecordsPerSecond);
330
+ this.maxInFlightEmits = maxInFlightEmits;
331
+ this.sharedRedactor = sharedRedactor;
332
+ this.sharedBeforeRecord = sharedBeforeRecord;
333
+ this.runtimeMetadata = runtimeMetadata;
334
+ }
335
+ get store() {
336
+ return this._store;
337
+ }
338
+ setInternalEventReporter(reporter) {
339
+ this.internalEventReporter = reporter;
340
+ }
341
+ emitInternal(input) {
342
+ if (this.shutdownCalled) return;
343
+ let record;
344
+ try {
345
+ record = this.buildRecord(input);
346
+ } catch {
347
+ this.droppedCount += 1;
348
+ return;
349
+ }
350
+ const skipRateLimit = this.shouldBypassRateLimit(record);
351
+ if (!skipRateLimit && !this.tokenBucket.tryConsume()) {
352
+ this.droppedCount += 1;
353
+ return;
354
+ }
355
+ let prepared;
356
+ try {
357
+ const afterDefault = defaultSensitiveKeyRedact(record);
358
+ if (afterDefault.type !== record.type) {
359
+ this.droppedCount += 1;
360
+ return;
361
+ }
362
+ prepared = afterDefault;
363
+ } catch {
364
+ this.droppedCount += 1;
365
+ return;
366
+ }
367
+ if (this.sharedRedactor !== undefined) {
368
+ const sharedRedactor = this.sharedRedactor;
369
+ const result = this.applyTransform(prepared, (r) => sharedRedactor(r), "shared", "redactor");
370
+ if (result === null) return;
371
+ prepared = result;
372
+ }
373
+ const signalRedactor = this.getSignalRedactor();
374
+ if (signalRedactor !== undefined) {
375
+ const result = this.applyTransform(prepared, (r) => signalRedactor(r), "signal", "redactor");
376
+ if (result === null) return;
377
+ prepared = result;
378
+ }
379
+ if (this.sharedBeforeRecord !== undefined) {
380
+ const sharedBeforeRecord = this.sharedBeforeRecord;
381
+ const result = this.applyTransform(prepared, (r) => sharedBeforeRecord(r), "shared", "beforeRecord");
382
+ if (result === null) return;
383
+ prepared = result;
384
+ }
385
+ const signalBeforeRecord = this.getSignalBeforeRecord();
386
+ if (signalBeforeRecord !== undefined) {
387
+ const result = this.applyTransform(prepared, (r) => signalBeforeRecord(r), "signal", "beforeRecord");
388
+ if (result === null) return;
389
+ prepared = result;
390
+ }
391
+ this.dispatchToSinks(prepared);
392
+ }
393
+ applyTransform(record, runner, source, kind) {
394
+ let result;
395
+ try {
396
+ result = runner(record);
397
+ } catch {
398
+ this.droppedCount += 1;
399
+ return null;
400
+ }
401
+ if (result === null) {
402
+ this.droppedCount += 1;
403
+ return null;
404
+ }
405
+ if (result.type !== record.type) {
406
+ this.droppedCount += 1;
407
+ const eventName = kind === "redactor" ? "ws.telemetry.redactor.type_mismatch" : "ws.telemetry.beforeRecord.type_mismatch";
408
+ this.dispatchInternalEvent(eventName, "warn", {
409
+ expected: record.type,
410
+ actual: result.type,
411
+ source
412
+ });
413
+ return null;
414
+ }
415
+ return result;
416
+ }
417
+ dispatchToSinks(record, selfObserveFailures = true) {
418
+ const critical = this.isCriticalRecord(record);
419
+ let droppedForRecord = false;
420
+ for (const sink of this.sinks) {
421
+ const inFlight = this.inFlightEmits.get(sink) ?? 0;
422
+ if (!critical && inFlight >= this.maxInFlightEmits) {
423
+ if (!droppedForRecord) {
424
+ this.droppedCount += 1;
425
+ droppedForRecord = true;
426
+ }
427
+ continue;
428
+ }
429
+ try {
430
+ const result = sink.emit(record);
431
+ if (isPromiseLike(result)) {
432
+ this.inFlightEmits.set(sink, inFlight + 1);
433
+ result.then(() => {
434
+ this.decrementInFlightEmit(sink);
435
+ }, (error) => {
436
+ this.decrementInFlightEmit(sink);
437
+ this.observeSinkFailure("emit", error, selfObserveFailures);
438
+ });
439
+ }
440
+ } catch (error) {
441
+ this.observeSinkFailure("emit", error, selfObserveFailures);
442
+ }
443
+ }
444
+ }
445
+ decrementInFlightEmit(sink) {
446
+ const current = this.inFlightEmits.get(sink) ?? 0;
447
+ if (current <= 1) {
448
+ this.inFlightEmits.delete(sink);
449
+ return;
450
+ }
451
+ this.inFlightEmits.set(sink, current - 1);
452
+ }
453
+ observeSinkFailure(phase, error, selfObserveFailure) {
454
+ this.sinkFailureCount += 1;
455
+ if (!selfObserveFailure) return;
456
+ this.dispatchInternalEvent("ws.telemetry.sink.failed", "warn", {
457
+ phase,
458
+ signal: this.signal,
459
+ errorType: error instanceof Error ? error.name : typeof error
460
+ });
461
+ }
462
+ dispatchInternalEvent(name, level, detail) {
463
+ if (this.internalEventReporter === undefined) return;
464
+ try {
465
+ this.internalEventReporter(name, level, detail);
466
+ } catch {}
467
+ }
468
+ async shutdown(timeoutMs) {
469
+ if (this.shutdownCalled) return;
470
+ this.shutdownCalled = true;
471
+ const sinkShutdowns = this.sinks.map((sink) => this.shutdownSink(sink, timeoutMs));
472
+ if (sinkShutdowns.length > 0) {
473
+ await Promise.allSettled(sinkShutdowns);
474
+ }
475
+ }
476
+ async shutdownSink(sink, timeoutMs) {
477
+ if (!sink.shutdown) return;
478
+ try {
479
+ const result = sink.shutdown({ timeoutMs });
480
+ if (!isPromiseLike(result)) return;
481
+ let timeout = null;
482
+ const shutdownPromise = result.then(() => "completed", (error) => {
483
+ throw error;
484
+ });
485
+ const timeoutPromise = new Promise((resolve) => {
486
+ timeout = setTimeout(() => {
487
+ resolve("timeout");
488
+ }, timeoutMs);
489
+ });
490
+ const outcome = await Promise.race([shutdownPromise, timeoutPromise]);
491
+ if (timeout) {
492
+ clearTimeout(timeout);
493
+ }
494
+ if (outcome === "timeout") {
495
+ shutdownPromise.catch(() => {});
496
+ this.sinkFailureCount += 1;
497
+ this.dispatchInternalEvent("ws.telemetry.shutdown.timeout", "warn", {
498
+ timeoutMs,
499
+ signal: this.signal
500
+ });
501
+ }
502
+ } catch (error) {
503
+ this.observeSinkFailure("shutdown", error, true);
504
+ }
505
+ }
506
+ };
507
+ EventPipeline = class extends TelemetryPipeline {
508
+ signal = "event";
509
+ signalRedactor;
510
+ signalBeforeRecord;
511
+ sampling;
512
+ capturePayload;
513
+ maxPayloadPreviewBytes;
514
+ currentEmitAlwaysRecord = false;
515
+ constructor(options, runtimeMetadata) {
516
+ super(options.sinks, options.store, options.maxRecordsPerSecond, options.maxInFlightEmits, options.sharedRedactor, options.sharedBeforeRecord, runtimeMetadata);
517
+ this.signalRedactor = options.signalRedactor;
518
+ this.signalBeforeRecord = options.signalBeforeRecord;
519
+ this.sampling = options.sampling;
520
+ this.capturePayload = options.capturePayload;
521
+ this.maxPayloadPreviewBytes = options.maxPayloadPreviewBytes;
522
+ }
523
+ emit(input) {
524
+ try {
525
+ if (this.shutdownCalled) return;
526
+ const levels = this.sampling.alwaysRecordLevels;
527
+ const alwaysRecord = levels.includes(input.level);
528
+ if (!alwaysRecord) {
529
+ const rate = this.sampling.rateByEvent[input.name] ?? this.sampling.defaultRate;
530
+ if (rate <= 0) {
531
+ this.droppedCount += 1;
532
+ return;
533
+ }
534
+ if (rate < 1 && Math.random() >= rate) {
535
+ this.droppedCount += 1;
536
+ return;
537
+ }
538
+ }
539
+ this.currentEmitAlwaysRecord = alwaysRecord;
540
+ try {
541
+ this.emitInternal(input);
542
+ } finally {
543
+ this.currentEmitAlwaysRecord = false;
544
+ }
545
+ } catch {}
546
+ }
547
+ dispatchInternalDiagnosticEvent(name, level, detail) {
548
+ const record = {
549
+ type: "event",
550
+ timestamp: Date.now(),
551
+ monotonicTime: performance.now(),
552
+ runtimeId: this.runtimeMetadata.runtimeId,
553
+ nodeId: this.runtimeMetadata.nodeId,
554
+ name,
555
+ level,
556
+ detail
557
+ };
558
+ try {
559
+ const sanitized = defaultSensitiveKeyRedact(record);
560
+ if (sanitized.type !== "event") return;
561
+ this.dispatchToSinks(sanitized, false);
562
+ } catch {}
563
+ }
564
+ buildRecord(input) {
565
+ let record = {
566
+ type: "event",
567
+ timestamp: Date.now(),
568
+ monotonicTime: performance.now(),
569
+ runtimeId: this.runtimeMetadata.runtimeId,
570
+ nodeId: this.runtimeMetadata.nodeId,
571
+ name: input.name,
572
+ level: input.level,
573
+ namespace: input.namespace,
574
+ connectionId: input.connectionId,
575
+ userId: input.userId,
576
+ attributes: input.attributes,
577
+ detail: input.detail,
578
+ traceId: input.traceId,
579
+ spanId: input.spanId,
580
+ parentSpanId: input.parentSpanId,
581
+ sampled: input.sampled
582
+ };
583
+ if (this.capturePayload === "preview" && input.payload !== undefined) {
584
+ record = {
585
+ ...record,
586
+ payloadPreview: truncatePayloadPreview(input.payload, this.maxPayloadPreviewBytes)
587
+ };
588
+ }
589
+ return record;
590
+ }
591
+ shouldBypassRateLimit(_record) {
592
+ return this.currentEmitAlwaysRecord;
593
+ }
594
+ isCriticalRecord(record) {
595
+ return record.level === "warn" || record.level === "error";
596
+ }
597
+ getSignalRedactor() {
598
+ return this.signalRedactor;
599
+ }
600
+ getSignalBeforeRecord() {
601
+ return this.signalBeforeRecord;
602
+ }
603
+ };
604
+ MetricPipeline = class extends TelemetryPipeline {
605
+ signal = "metric";
606
+ signalRedactor;
607
+ signalBeforeRecord;
608
+ metricSources = new Set();
609
+ collectionEnabled;
610
+ sampleIntervalMs;
611
+ collectionInterval = null;
612
+ snapshotProvider;
613
+ constructor(options, runtimeMetadata) {
614
+ super(options.sinks, options.store, options.maxRecordsPerSecond, options.maxInFlightEmits, options.sharedRedactor, options.sharedBeforeRecord, runtimeMetadata);
615
+ this.signalRedactor = options.signalRedactor;
616
+ this.signalBeforeRecord = options.signalBeforeRecord;
617
+ this.collectionEnabled = options.collectionEnabled;
618
+ this.sampleIntervalMs = options.sampleIntervalMs;
619
+ if (this.collectionEnabled && this.sampleIntervalMs > 0) {
620
+ this.collectionInterval = setInterval(() => {
621
+ this.collectAndEmit();
622
+ }, this.sampleIntervalMs);
623
+ if (this.collectionInterval && typeof this.collectionInterval === "object" && "unref" in this.collectionInterval) {
624
+ this.collectionInterval.unref();
625
+ }
626
+ }
627
+ }
628
+ emit(input) {
629
+ try {
630
+ this.emitInternal(input);
631
+ } catch {}
632
+ }
633
+ buildRecord(input) {
634
+ return {
635
+ type: "metric",
636
+ timestamp: Date.now(),
637
+ monotonicTime: performance.now(),
638
+ runtimeId: this.runtimeMetadata.runtimeId,
639
+ nodeId: this.runtimeMetadata.nodeId,
640
+ name: input.name,
641
+ kind: input.kind,
642
+ value: input.value,
643
+ unit: input.unit,
644
+ tags: input.tags,
645
+ namespace: input.namespace,
646
+ connectionId: input.connectionId,
647
+ userId: input.userId,
648
+ traceId: input.traceId,
649
+ spanId: input.spanId,
650
+ parentSpanId: input.parentSpanId,
651
+ sampled: input.sampled,
652
+ snapshot: input.snapshot
653
+ };
654
+ }
655
+ shouldBypassRateLimit(record) {
656
+ const outcome = record.tags?.outcome;
657
+ if (outcome === "failed" || outcome === "rejected" || outcome === "dropped") {
658
+ return true;
659
+ }
660
+ return record.name.endsWith(".failures") || record.name.endsWith(".failure") || record.name.endsWith(".dropped") || record.name.includes(".failures.") || record.name.includes(".dropped.");
661
+ }
662
+ isCriticalRecord(record) {
663
+ return this.shouldBypassRateLimit(record);
664
+ }
665
+ getSignalRedactor() {
666
+ return this.signalRedactor;
667
+ }
668
+ getSignalBeforeRecord() {
669
+ return this.signalBeforeRecord;
670
+ }
671
+ registerMetricSource(source) {
672
+ this.metricSources.add(source);
673
+ return () => {
674
+ this.metricSources.delete(source);
675
+ };
676
+ }
677
+ setSnapshotProvider(provider) {
678
+ this.snapshotProvider = provider;
679
+ }
680
+ getSnapshot() {
681
+ const now = Date.now();
682
+ const base = {
683
+ ...EMPTY_METRICS_SNAPSHOT,
684
+ timestamp: now,
685
+ activeConnectionsByNamespace: {},
686
+ telemetryDroppedRecords: this.droppedCount,
687
+ telemetrySinkFailures: this.sinkFailureCount
688
+ };
689
+ for (const source of this.metricSources) {
690
+ try {
691
+ const partial = source.collect(now);
692
+ base.activeConnections += partial.activeConnections ?? 0;
693
+ base.roomCount += partial.roomCount ?? 0;
694
+ base.pendingInboundMessages += partial.pendingInboundMessages ?? 0;
695
+ base.pendingOutboundMessages += partial.pendingOutboundMessages ?? 0;
696
+ base.socketBufferedBytes += partial.socketBufferedBytes ?? 0;
697
+ base.pendingFanOutJobs += partial.pendingFanOutJobs ?? 0;
698
+ base.pendingFanOutTargets += partial.pendingFanOutTargets ?? 0;
699
+ if (partial.activeConnectionsByNamespace) {
700
+ for (const [ns, count] of Object.entries(partial.activeConnectionsByNamespace)) {
701
+ base.activeConnectionsByNamespace[ns] = (base.activeConnectionsByNamespace[ns] ?? 0) + count;
702
+ }
703
+ }
704
+ } catch {}
705
+ }
706
+ return base;
707
+ }
708
+ collectAndEmit() {
709
+ try {
710
+ if (this.shutdownCalled) return;
711
+ const snapshot = this.snapshotProvider?.() ?? this.getSnapshot();
712
+ const input = {
713
+ name: "ws.connections.active",
714
+ kind: "gauge",
715
+ value: snapshot.activeConnections,
716
+ unit: "1",
717
+ snapshot
718
+ };
719
+ this.emit(input);
720
+ } catch {}
721
+ }
722
+ async shutdown(timeoutMs) {
723
+ if (this.collectionInterval !== null) {
724
+ clearInterval(this.collectionInterval);
725
+ this.collectionInterval = null;
726
+ }
727
+ await super.shutdown(timeoutMs);
728
+ }
729
+ };
730
+ SpanPipeline = class extends TelemetryPipeline {
731
+ signal = "span";
732
+ signalRedactor;
733
+ signalBeforeRecord;
734
+ sampling;
735
+ constructor(options, runtimeMetadata) {
736
+ super(options.sinks, options.store, options.maxRecordsPerSecond, options.maxInFlightEmits, options.sharedRedactor, options.sharedBeforeRecord, runtimeMetadata);
737
+ this.signalRedactor = options.signalRedactor;
738
+ this.signalBeforeRecord = options.signalBeforeRecord;
739
+ this.sampling = { defaultRate: options.sampling.defaultRate };
740
+ }
741
+ emit(input) {
742
+ try {
743
+ if (this.shutdownCalled) return;
744
+ if (input.status !== "error") {
745
+ const rate = this.sampling.defaultRate;
746
+ if (rate <= 0) {
747
+ this.droppedCount += 1;
748
+ return;
749
+ }
750
+ if (rate < 1 && Math.random() >= rate) {
751
+ this.droppedCount += 1;
752
+ return;
753
+ }
754
+ }
755
+ this.emitInternal(input);
756
+ } catch {}
757
+ }
758
+ buildRecord(input) {
759
+ return {
760
+ type: "span",
761
+ timestamp: Date.now(),
762
+ monotonicTime: performance.now(),
763
+ runtimeId: this.runtimeMetadata.runtimeId,
764
+ nodeId: this.runtimeMetadata.nodeId,
765
+ operationName: input.operationName,
766
+ kind: input.kind,
767
+ durationMs: input.durationMs,
768
+ status: input.status,
769
+ namespace: input.namespace,
770
+ connectionId: input.connectionId,
771
+ userId: input.userId,
772
+ attributes: input.attributes,
773
+ errorType: input.errorType,
774
+ traceId: input.traceId,
775
+ spanId: input.spanId,
776
+ parentSpanId: input.parentSpanId,
777
+ sampled: input.sampled,
778
+ events: input.events,
779
+ links: input.links
780
+ };
781
+ }
782
+ shouldBypassRateLimit(record) {
783
+ return record.status === "error";
784
+ }
785
+ isCriticalRecord(record) {
786
+ return record.status === "error";
787
+ }
788
+ getSignalRedactor() {
789
+ return this.signalRedactor;
790
+ }
791
+ getSignalBeforeRecord() {
792
+ return this.signalBeforeRecord;
793
+ }
794
+ };
795
+ WebSocketTelemetryControllerImpl = class {
796
+ events;
797
+ metrics;
798
+ spans;
799
+ runtimeId;
800
+ nodeId;
801
+ traceOptions;
802
+ shutdownTimeoutMs;
803
+ shutdownCalled = false;
804
+ constructor(events, metrics, spans, traceOptions, runtimeMetadata, shutdownTimeoutMs) {
805
+ this.events = events;
806
+ this.metrics = metrics;
807
+ this.spans = spans;
808
+ this.traceOptions = traceOptions;
809
+ this.runtimeId = runtimeMetadata.runtimeId;
810
+ this.nodeId = runtimeMetadata.nodeId;
811
+ this.shutdownTimeoutMs = shutdownTimeoutMs;
812
+ const reporter = (name, level, detail) => {
813
+ this.events.dispatchInternalDiagnosticEvent(name, level, detail);
814
+ };
815
+ this.events.setInternalEventReporter(reporter);
816
+ this.metrics.setInternalEventReporter(reporter);
817
+ this.spans.setInternalEventReporter(reporter);
818
+ this.metrics.setSnapshotProvider(() => this.getMetricsSnapshot());
819
+ }
820
+ emit(input) {
821
+ try {
822
+ if (this.shutdownCalled) return;
823
+ this.events.emit(input);
824
+ } catch {}
825
+ }
826
+ recordMetric(input) {
827
+ try {
828
+ if (this.shutdownCalled) return;
829
+ this.metrics.emit(input);
830
+ } catch {}
831
+ }
832
+ recordSpan(input) {
833
+ try {
834
+ if (this.shutdownCalled) return;
835
+ this.spans.emit(input);
836
+ } catch {}
837
+ }
838
+ getMetricsSnapshot() {
839
+ try {
840
+ const base = this.metrics.getSnapshot();
841
+ base.telemetryDroppedRecords = this.events.droppedCount + this.metrics.droppedCount + this.spans.droppedCount;
842
+ base.telemetrySinkFailures = this.events.sinkFailureCount + this.metrics.sinkFailureCount + this.spans.sinkFailureCount;
843
+ return base;
844
+ } catch {
845
+ return {
846
+ ...EMPTY_METRICS_SNAPSHOT,
847
+ timestamp: Date.now()
848
+ };
849
+ }
850
+ }
851
+ getEventStore() {
852
+ try {
853
+ return this.events.store;
854
+ } catch {
855
+ return undefined;
856
+ }
857
+ }
858
+ getMetricStore() {
859
+ try {
860
+ return this.metrics.store;
861
+ } catch {
862
+ return undefined;
863
+ }
864
+ }
865
+ getSpanStore() {
866
+ try {
867
+ return this.spans.store;
868
+ } catch {
869
+ return undefined;
870
+ }
871
+ }
872
+ registerMetricSource(source) {
873
+ try {
874
+ return this.metrics.registerMetricSource(source);
875
+ } catch {
876
+ return noopUnsubscribe;
877
+ }
878
+ }
879
+ createConnectionContext(request) {
880
+ try {
881
+ if (this.traceOptions.extractTraceParent && request?.headers) {
882
+ const traceparentHeader = request.headers["traceparent"];
883
+ const traceparentValue = Array.isArray(traceparentHeader) ? traceparentHeader[0] : traceparentHeader;
884
+ if (traceparentValue) {
885
+ const parsed = parseTraceParent(traceparentValue);
886
+ if (parsed) {
887
+ const context = {
888
+ traceId: parsed.traceId,
889
+ parentSpanId: parsed.parentId,
890
+ sampled: parsed.sampled
891
+ };
892
+ if (this.traceOptions.generateConnectionTrace) {
893
+ context.spanId = generateSpanId();
894
+ }
895
+ return { ...context };
896
+ }
897
+ }
898
+ }
899
+ if (!this.traceOptions.generateConnectionTrace) {
900
+ return {};
901
+ }
902
+ return {
903
+ traceId: generateTraceId(),
904
+ spanId: generateSpanId()
905
+ };
906
+ } catch {
907
+ return {};
908
+ }
909
+ }
910
+ getTraceOptions() {
911
+ return { ...this.traceOptions };
912
+ }
913
+ async shutdown(options) {
914
+ if (this.shutdownCalled) return;
915
+ this.shutdownCalled = true;
916
+ const timeoutMs = options?.timeoutMs ?? this.shutdownTimeoutMs;
917
+ try {
918
+ await Promise.allSettled([
919
+ this.events.shutdown(timeoutMs),
920
+ this.metrics.shutdown(timeoutMs),
921
+ this.spans.shutdown(timeoutMs)
922
+ ]);
923
+ } catch {}
924
+ }
925
+ };
926
+ }));
927
+
928
+ //#endregion
929
+ init_ws_telemetry();
930
+ export { DEFAULT_TRACE_OPTIONS, EMPTY_METRICS_SNAPSHOT, NoopWebSocketTelemetryController, WebSocketTelemetryControllerImpl, createWebSocketTelemetryController, init_ws_telemetry, isPromiseLike };
931
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid3MtdGVsZW1ldHJ5LmpzIiwibmFtZXMiOlsicmVkYWN0ZWQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IiwiZXZlbnRTaW5rczogV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRTaW5rW10iLCJldmVudFN0b3JlOiBXZWJTb2NrZXRUZWxlbWV0cnlFdmVudFN0b3JlIHwgdW5kZWZpbmVkIiwiZXZlbnRzUmVzb2x2ZWQ6IFJlc29sdmVkRXZlbnRQaXBlbGluZU9wdGlvbnMiLCJtZXRyaWNTaW5rczogV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljU2lua1tdIiwibWV0cmljU3RvcmU6IFdlYlNvY2tldFRlbGVtZXRyeU1ldHJpY1N0b3JlIHwgdW5kZWZpbmVkIiwibWV0cmljc1Jlc29sdmVkOiBSZXNvbHZlZE1ldHJpY1BpcGVsaW5lT3B0aW9ucyIsInNwYW5TaW5rczogV2ViU29ja2V0VGVsZW1ldHJ5U3BhblNpbmtbXSIsInNwYW5TdG9yZTogV2ViU29ja2V0VGVsZW1ldHJ5U3BhblN0b3JlIHwgdW5kZWZpbmVkIiwic3BhbnNSZXNvbHZlZDogUmVzb2x2ZWRTcGFuUGlwZWxpbmVPcHRpb25zIiwidHJhY2VPcHRpb25zOiBXZWJTb2NrZXRUZWxlbWV0cnlUcmFjZU9wdGlvbnMiLCJFTVBUWV9NRVRSSUNTX1NOQVBTSE9UOiBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNzU25hcHNob3QiLCJERUZBVUxUX1RSQUNFX09QVElPTlM6IFdlYlNvY2tldFRlbGVtZXRyeVRyYWNlT3B0aW9ucyIsIkRFRkFVTFRfRVZFTlRfQUxXQVlTX1JFQ09SRF9MRVZFTFM6IFJlYWRvbmx5QXJyYXk8XCJ3YXJuXCIgfCBcImVycm9yXCI+IiwiREVGQVVMVF9FVkVOVF9DQVBUVVJFX1BBWUxPQUQ6IGZhbHNlIHwgXCJwcmV2aWV3XCIiLCJtYXhUb2tlbnM6IG51bWJlciIsInJlZmlsbFJhdGU6IG51bWJlciIsInJlY29yZDogVFJlY29yZCIsInByZXBhcmVkOiBUUmVjb3JkIiwicmVzdWx0OiBXZWJTb2NrZXRUZWxlbWV0cnlSZWNvcmQgfCBudWxsIiwidGltZW91dDogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD4gfCBudWxsIiwibGV2ZWxzOiBSZWFkb25seUFycmF5PHN0cmluZz4iLCJyZWNvcmQ6IFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50UmVjb3JkIiwiYmFzZTogV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljc1NuYXBzaG90IiwiaW5wdXQ6IFdlYlNvY2tldE1ldHJpY0lucHV0IiwicmVwb3J0ZXI6IEludGVybmFsRXZlbnRSZXBvcnRlciIsImNvbnRleHQ6IFdlYlNvY2tldFRlbGVtZXRyeUNvbm5lY3Rpb25Db250ZXh0Il0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3N0cmVhbS93cy10ZWxlbWV0cnkudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5NZW1vcnlFdmVudFN0b3JlLCBJbk1lbW9yeU1ldHJpY1N0b3JlLCBJbk1lbW9yeVNwYW5TdG9yZSB9IGZyb20gXCIuL3dzLXRlbGVtZXRyeS1tZW1vcnlcIjtcbmltcG9ydCB7IGdlbmVyYXRlU3BhbklkLCBnZW5lcmF0ZVRyYWNlSWQsIHBhcnNlVHJhY2VQYXJlbnQgfSBmcm9tIFwiLi93cy10ZWxlbWV0cnktdHJhY2VcIjtcblxuLy8gLS0gUmVjb3JkIHR5cGVzICh1bmNoYW5nZWQpIC0tXG5cbmV4cG9ydCB0eXBlIFdlYlNvY2tldFRlbGVtZXRyeVJlY29yZEJhc2UgPSB7XG4gIHRpbWVzdGFtcDogbnVtYmVyO1xuICBtb25vdG9uaWNUaW1lPzogbnVtYmVyO1xuICBydW50aW1lSWQ6IHN0cmluZztcbiAgbm9kZUlkOiBzdHJpbmc7XG4gIG5hbWVzcGFjZT86IHN0cmluZztcbiAgY29ubmVjdGlvbklkPzogc3RyaW5nO1xuICAvLyB1c2VySWTripQgY29ubmVjdGlvbiDshozsnKDsnpDrpbwg7Iud67OE7ZWY6riwIOychO2VnCBvcGFxdWUgaWRlbnRpZmllciAo67O07Ya1IERCIFBLKVxuICAvLyBwc2V1ZG9ueW1vdXMgaWRlbnRpZmllcuuhnOunjCDsgqzsmqntlZjrqbAsIOydtOuplOydvC/soITtmZTrsojtmLgg65OxIFBJSeuKlCDrk6TslrTqsIDsp4Ag7JWK64qU64uk6rOgIOqwgOygle2VqFxuICB1c2VySWQ/OiBzdHJpbmc7XG4gIHRyYWNlSWQ/OiBzdHJpbmc7XG4gIHNwYW5JZD86IHN0cmluZztcbiAgcGFyZW50U3BhbklkPzogc3RyaW5nO1xuICBzYW1wbGVkPzogYm9vbGVhbjtcbn07XG5cbmV4cG9ydCB0eXBlIFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50UmVjb3JkID0gV2ViU29ja2V0VGVsZW1ldHJ5UmVjb3JkQmFzZSAmIHtcbiAgdHlwZTogXCJldmVudFwiO1xuICBuYW1lOiBzdHJpbmc7XG4gIGxldmVsOiBcImRlYnVnXCIgfCBcImluZm9cIiB8IFwid2FyblwiIHwgXCJlcnJvclwiO1xuICBhdHRyaWJ1dGVzPzogUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbj47XG4gIGRldGFpbD86IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICBwYXlsb2FkUHJldmlldz86IHN0cmluZztcbn07XG5cbmV4cG9ydCB0eXBlIFdlYlNvY2tldFRlbGVtZXRyeU1ldHJpY1JlY29yZCA9IFdlYlNvY2tldFRlbGVtZXRyeVJlY29yZEJhc2UgJiB7XG4gIHR5cGU6IFwibWV0cmljXCI7XG4gIG5hbWU6IHN0cmluZztcbiAga2luZDogXCJjb3VudGVyXCIgfCBcImhpc3RvZ3JhbVwiIHwgXCJnYXVnZVwiO1xuICB2YWx1ZTogbnVtYmVyO1xuICB1bml0PzogXCIxXCIgfCBcIm1zXCIgfCBcIkJ5XCI7XG4gIHRhZ3M/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICBzbmFwc2hvdD86IFdlYlNvY2tldFRlbGVtZXRyeU1ldHJpY3NTbmFwc2hvdDtcbn07XG5cbmV4cG9ydCB0eXBlIFdlYlNvY2tldFRlbGVtZXRyeVNwYW5SZWNvcmQgPSBXZWJTb2NrZXRUZWxlbWV0cnlSZWNvcmRCYXNlICYge1xuICB0eXBlOiBcInNwYW5cIjtcbiAgb3BlcmF0aW9uTmFtZTogc3RyaW5nO1xuICBraW5kOiBcImludGVybmFsXCIgfCBcInByb2R1Y2VyXCIgfCBcImNvbnN1bWVyXCIgfCBcInNlcnZlclwiIHwgXCJjbGllbnRcIjtcbiAgZHVyYXRpb25NczogbnVtYmVyO1xuICBzdGF0dXM6IFwidW5zZXRcIiB8IFwib2tcIiB8IFwiZXJyb3JcIjtcbiAgYXR0cmlidXRlcz86IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4+O1xuICBlcnJvclR5cGU/OiBzdHJpbmc7XG4gIGV2ZW50cz86IEFycmF5PHtcbiAgICBuYW1lOiBzdHJpbmc7XG4gICAgdGltZXN0YW1wOiBudW1iZXI7XG4gICAgYXR0cmlidXRlcz86IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICB9PjtcbiAgbGlua3M/OiBBcnJheTx7XG4gICAgdHJhY2VJZDogc3RyaW5nO1xuICAgIHNwYW5JZDogc3RyaW5nO1xuICAgIGF0dHJpYnV0ZXM/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgfT47XG59O1xuXG5leHBvcnQgdHlwZSBXZWJTb2NrZXRUZWxlbWV0cnlSZWNvcmQgPVxuICB8IFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50UmVjb3JkXG4gIHwgV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljUmVjb3JkXG4gIHwgV2ViU29ja2V0VGVsZW1ldHJ5U3BhblJlY29yZDtcblxuLy8gLS0gSW5wdXQgdHlwZXMgKHVuY2hhbmdlZCkgLS1cblxuZXhwb3J0IHR5cGUgV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRJbnB1dCA9IHtcbiAgbmFtZTogc3RyaW5nO1xuICBsZXZlbDogXCJkZWJ1Z1wiIHwgXCJpbmZvXCIgfCBcIndhcm5cIiB8IFwiZXJyb3JcIjtcbiAgbmFtZXNwYWNlPzogc3RyaW5nO1xuICBjb25uZWN0aW9uSWQ/OiBzdHJpbmc7XG4gIHVzZXJJZD86IHN0cmluZztcbiAgYXR0cmlidXRlcz86IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4+O1xuICBkZXRhaWw/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgcGF5bG9hZD86IHVua25vd247XG4gIHRyYWNlSWQ/OiBzdHJpbmc7XG4gIHNwYW5JZD86IHN0cmluZztcbiAgcGFyZW50U3BhbklkPzogc3RyaW5nO1xuICBzYW1wbGVkPzogYm9vbGVhbjtcbn07XG5cbmV4cG9ydCB0eXBlIFdlYlNvY2tldE1ldHJpY0lucHV0ID0ge1xuICBuYW1lOiBzdHJpbmc7XG4gIGtpbmQ6IFwiY291bnRlclwiIHwgXCJoaXN0b2dyYW1cIiB8IFwiZ2F1Z2VcIjtcbiAgdmFsdWU6IG51bWJlcjtcbiAgdW5pdD86IFwiMVwiIHwgXCJtc1wiIHwgXCJCeVwiO1xuICB0YWdzPzogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcbiAgbmFtZXNwYWNlPzogc3RyaW5nO1xuICBjb25uZWN0aW9uSWQ/OiBzdHJpbmc7XG4gIHVzZXJJZD86IHN0cmluZztcbiAgdHJhY2VJZD86IHN0cmluZztcbiAgc3BhbklkPzogc3RyaW5nO1xuICBwYXJlbnRTcGFuSWQ/OiBzdHJpbmc7XG4gIHNhbXBsZWQ/OiBib29sZWFuO1xuICBzbmFwc2hvdD86IFdlYlNvY2tldFRlbGVtZXRyeU1ldHJpY3NTbmFwc2hvdDtcbn07XG5cbmV4cG9ydCB0eXBlIFdlYlNvY2tldFNwYW5JbnB1dCA9IHtcbiAgb3BlcmF0aW9uTmFtZTogc3RyaW5nO1xuICBraW5kOiBcImludGVybmFsXCIgfCBcInByb2R1Y2VyXCIgfCBcImNvbnN1bWVyXCIgfCBcInNlcnZlclwiIHwgXCJjbGllbnRcIjtcbiAgZHVyYXRpb25NczogbnVtYmVyO1xuICBzdGF0dXM6IFwidW5zZXRcIiB8IFwib2tcIiB8IFwiZXJyb3JcIjtcbiAgbmFtZXNwYWNlPzogc3RyaW5nO1xuICBjb25uZWN0aW9uSWQ/OiBzdHJpbmc7XG4gIHVzZXJJZD86IHN0cmluZztcbiAgYXR0cmlidXRlcz86IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4+O1xuICBlcnJvclR5cGU/OiBzdHJpbmc7XG4gIHRyYWNlSWQ/OiBzdHJpbmc7XG4gIHNwYW5JZD86IHN0cmluZztcbiAgcGFyZW50U3BhbklkPzogc3RyaW5nO1xuICBzYW1wbGVkPzogYm9vbGVhbjtcbiAgZXZlbnRzPzogQXJyYXk8e1xuICAgIG5hbWU6IHN0cmluZztcbiAgICB0aW1lc3RhbXA6IG51bWJlcjtcbiAgICBhdHRyaWJ1dGVzPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIH0+O1xuICBsaW5rcz86IEFycmF5PHtcbiAgICB0cmFjZUlkOiBzdHJpbmc7XG4gICAgc3BhbklkOiBzdHJpbmc7XG4gICAgYXR0cmlidXRlcz86IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICB9Pjtcbn07XG5cbmV4cG9ydCB0eXBlIFdlYlNvY2tldFRlbGVtZXRyeUlucHV0ID1cbiAgfCAoeyB0eXBlOiBcImV2ZW50XCIgfSAmIFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50SW5wdXQpXG4gIHwgKHsgdHlwZTogXCJtZXRyaWNcIiB9ICYgV2ViU29ja2V0TWV0cmljSW5wdXQpXG4gIHwgKHsgdHlwZTogXCJzcGFuXCIgfSAmIFdlYlNvY2tldFNwYW5JbnB1dCk7XG5cbi8vIC0tIE1ldHJpY3Mgc25hcHNob3QgLS1cblxuZXhwb3J0IHR5cGUgV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljc1NuYXBzaG90ID0ge1xuICB0aW1lc3RhbXA6IG51bWJlcjtcbiAgYWN0aXZlQ29ubmVjdGlvbnM6IG51bWJlcjtcbiAgYWN0aXZlQ29ubmVjdGlvbnNCeU5hbWVzcGFjZTogUmVjb3JkPHN0cmluZywgbnVtYmVyPjtcbiAgcm9vbUNvdW50OiBudW1iZXI7XG4gIHBlbmRpbmdJbmJvdW5kTWVzc2FnZXM6IG51bWJlcjtcbiAgcGVuZGluZ091dGJvdW5kTWVzc2FnZXM6IG51bWJlcjtcbiAgc29ja2V0QnVmZmVyZWRCeXRlczogbnVtYmVyO1xuICBwZW5kaW5nRmFuT3V0Sm9iczogbnVtYmVyO1xuICBwZW5kaW5nRmFuT3V0VGFyZ2V0czogbnVtYmVyO1xuICB0ZWxlbWV0cnlEcm9wcGVkUmVjb3JkczogbnVtYmVyO1xuICB0ZWxlbWV0cnlTaW5rRmFpbHVyZXM6IG51bWJlcjtcbn07XG5cbi8vIC0tIENvbm5lY3Rpb24gc25hcHNob3QgKFRlbGVtZXRyeUluc3BlY3RhYmxlQ29ubmVjdGlvbikgLS1cblxuZXhwb3J0IHR5cGUgV2ViU29ja2V0VGVsZW1ldHJ5Q29ubmVjdGlvblNuYXBzaG90ID0ge1xuICBwZW5kaW5nSW5ib3VuZE1lc3NhZ2VzOiBudW1iZXI7XG4gIHBlbmRpbmdPdXRib3VuZE1lc3NhZ2VzOiBudW1iZXI7XG4gIHNvY2tldEJ1ZmZlcmVkQnl0ZXM6IG51bWJlcjtcbn07XG5cbmV4cG9ydCBpbnRlcmZhY2UgVGVsZW1ldHJ5SW5zcGVjdGFibGVDb25uZWN0aW9uIHtcbiAgZ2V0VGVsZW1ldHJ5U25hcHNob3QoKTogV2ViU29ja2V0VGVsZW1ldHJ5Q29ubmVjdGlvblNuYXBzaG90O1xufVxuXG4vLyAtLSBTaWduYWwtbmFycm93ZWQgc2lua3MgLS1cblxuZXhwb3J0IGludGVyZmFjZSBXZWJTb2NrZXRUZWxlbWV0cnlFdmVudFNpbmsge1xuICBlbWl0KHJlY29yZDogV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRSZWNvcmQpOiB2b2lkIHwgUHJvbWlzZTx2b2lkPjtcbiAgc2h1dGRvd24/KG9wdGlvbnM/OiB7IHRpbWVvdXRNcz86IG51bWJlciB9KTogdm9pZCB8IFByb21pc2U8dm9pZD47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljU2luayB7XG4gIGVtaXQocmVjb3JkOiBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNSZWNvcmQpOiB2b2lkIHwgUHJvbWlzZTx2b2lkPjtcbiAgc2h1dGRvd24/KG9wdGlvbnM/OiB7IHRpbWVvdXRNcz86IG51bWJlciB9KTogdm9pZCB8IFByb21pc2U8dm9pZD47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgV2ViU29ja2V0VGVsZW1ldHJ5U3BhblNpbmsge1xuICBlbWl0KHJlY29yZDogV2ViU29ja2V0VGVsZW1ldHJ5U3BhblJlY29yZCk6IHZvaWQgfCBQcm9taXNlPHZvaWQ+O1xuICBzaHV0ZG93bj8ob3B0aW9ucz86IHsgdGltZW91dE1zPzogbnVtYmVyIH0pOiB2b2lkIHwgUHJvbWlzZTx2b2lkPjtcbn1cblxuLy8gLS0gU2lnbmFsLW5hcnJvd2VkIHF1ZXJ5IGZpbHRlcnMgLS1cblxuZXhwb3J0IHR5cGUgV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRRdWVyeUZpbHRlciA9IHtcbiAgbmFtZT86IHN0cmluZztcbiAgbGV2ZWw/OiBcImRlYnVnXCIgfCBcImluZm9cIiB8IFwid2FyblwiIHwgXCJlcnJvclwiO1xuICBjb25uZWN0aW9uSWQ/OiBzdHJpbmc7XG4gIHVzZXJJZD86IHN0cmluZztcbiAgbmFtZXNwYWNlPzogc3RyaW5nO1xuICB0cmFjZUlkPzogc3RyaW5nO1xuICBzaW5jZT86IG51bWJlcjtcbiAgdW50aWw/OiBudW1iZXI7XG4gIGxpbWl0PzogbnVtYmVyO1xufTtcblxuZXhwb3J0IHR5cGUgV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljUXVlcnlGaWx0ZXIgPSB7XG4gIG5hbWU/OiBzdHJpbmc7XG4gIGtpbmQ/OiBcImNvdW50ZXJcIiB8IFwiaGlzdG9ncmFtXCIgfCBcImdhdWdlXCI7XG4gIGNvbm5lY3Rpb25JZD86IHN0cmluZztcbiAgdXNlcklkPzogc3RyaW5nO1xuICBuYW1lc3BhY2U/OiBzdHJpbmc7XG4gIHRyYWNlSWQ/OiBzdHJpbmc7XG4gIHNpbmNlPzogbnVtYmVyO1xuICB1bnRpbD86IG51bWJlcjtcbiAgbGltaXQ/OiBudW1iZXI7XG59O1xuXG5leHBvcnQgdHlwZSBXZWJTb2NrZXRUZWxlbWV0cnlTcGFuUXVlcnlGaWx0ZXIgPSB7XG4gIG9wZXJhdGlvbk5hbWU/OiBzdHJpbmc7XG4gIGtpbmQ/OiBcImludGVybmFsXCIgfCBcInByb2R1Y2VyXCIgfCBcImNvbnN1bWVyXCIgfCBcInNlcnZlclwiIHwgXCJjbGllbnRcIjtcbiAgc3RhdHVzPzogXCJ1bnNldFwiIHwgXCJva1wiIHwgXCJlcnJvclwiO1xuICBjb25uZWN0aW9uSWQ/OiBzdHJpbmc7XG4gIHVzZXJJZD86IHN0cmluZztcbiAgbmFtZXNwYWNlPzogc3RyaW5nO1xuICB0cmFjZUlkPzogc3RyaW5nO1xuICBzaW5jZT86IG51bWJlcjtcbiAgdW50aWw/OiBudW1iZXI7XG4gIGxpbWl0PzogbnVtYmVyO1xufTtcblxuLy8gLS0gU2lnbmFsLW5hcnJvd2VkIHN0b3JlcyAtLVxuXG5leHBvcnQgaW50ZXJmYWNlIFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50U3RvcmUge1xuICByZWFkb25seSBzaW5rOiBXZWJTb2NrZXRUZWxlbWV0cnlFdmVudFNpbms7XG4gIHF1ZXJ5KGZpbHRlcjogV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRRdWVyeUZpbHRlcik6IFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50UmVjb3JkW107XG4gIGNsZWFyKCk6IHZvaWQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljU3RvcmUge1xuICByZWFkb25seSBzaW5rOiBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNTaW5rO1xuICBxdWVyeShmaWx0ZXI6IFdlYlNvY2tldFRlbGVtZXRyeU1ldHJpY1F1ZXJ5RmlsdGVyKTogV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljUmVjb3JkW107XG4gIGNsZWFyKCk6IHZvaWQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgV2ViU29ja2V0VGVsZW1ldHJ5U3BhblN0b3JlIHtcbiAgcmVhZG9ubHkgc2luazogV2ViU29ja2V0VGVsZW1ldHJ5U3BhblNpbms7XG4gIHF1ZXJ5KGZpbHRlcjogV2ViU29ja2V0VGVsZW1ldHJ5U3BhblF1ZXJ5RmlsdGVyKTogV2ViU29ja2V0VGVsZW1ldHJ5U3BhblJlY29yZFtdO1xuICBjbGVhcigpOiB2b2lkO1xufVxuXG4vLyAtLSBNZXRyaWMgc291cmNlIGludGVyZmFjZSAodW5jaGFuZ2VkKSAtLVxuXG5leHBvcnQgaW50ZXJmYWNlIFdlYlNvY2tldFRlbGVtZXRyeU1ldHJpY1NvdXJjZSB7XG4gIGNvbGxlY3Qobm93OiBudW1iZXIpOiBQYXJ0aWFsPFdlYlNvY2tldFRlbGVtZXRyeU1ldHJpY3NTbmFwc2hvdD47XG59XG5cbi8vIC0tIFJlZGFjdG9yIC8gYmVmb3JlUmVjb3JkIHR5cGVzIChzaWduYWwtbmFycm93ZWQgKyBzaGFyZWQpIC0tXG5cbmV4cG9ydCB0eXBlIFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50UmVkYWN0b3IgPSAoXG4gIHJlY29yZDogV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRSZWNvcmQsXG4pID0+IFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50UmVjb3JkIHwgbnVsbDtcblxuZXhwb3J0IHR5cGUgV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljUmVkYWN0b3IgPSAoXG4gIHJlY29yZDogV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljUmVjb3JkLFxuKSA9PiBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNSZWNvcmQgfCBudWxsO1xuXG5leHBvcnQgdHlwZSBXZWJTb2NrZXRUZWxlbWV0cnlTcGFuUmVkYWN0b3IgPSAoXG4gIHJlY29yZDogV2ViU29ja2V0VGVsZW1ldHJ5U3BhblJlY29yZCxcbikgPT4gV2ViU29ja2V0VGVsZW1ldHJ5U3BhblJlY29yZCB8IG51bGw7XG5cbmV4cG9ydCB0eXBlIFdlYlNvY2tldFRlbGVtZXRyeVJlZGFjdG9yID0gKFxuICByZWNvcmQ6IFdlYlNvY2tldFRlbGVtZXRyeVJlY29yZCxcbikgPT4gV2ViU29ja2V0VGVsZW1ldHJ5UmVjb3JkIHwgbnVsbDtcblxuZXhwb3J0IHR5cGUgV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRCZWZvcmVSZWNvcmQgPSAoXG4gIHJlY29yZDogV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRSZWNvcmQsXG4pID0+IFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50UmVjb3JkIHwgbnVsbDtcblxuZXhwb3J0IHR5cGUgV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljQmVmb3JlUmVjb3JkID0gKFxuICByZWNvcmQ6IFdlYlNvY2tldFRlbGVtZXRyeU1ldHJpY1JlY29yZCxcbikgPT4gV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljUmVjb3JkIHwgbnVsbDtcblxuZXhwb3J0IHR5cGUgV2ViU29ja2V0VGVsZW1ldHJ5U3BhbkJlZm9yZVJlY29yZCA9IChcbiAgcmVjb3JkOiBXZWJTb2NrZXRUZWxlbWV0cnlTcGFuUmVjb3JkLFxuKSA9PiBXZWJTb2NrZXRUZWxlbWV0cnlTcGFuUmVjb3JkIHwgbnVsbDtcblxuZXhwb3J0IHR5cGUgV2ViU29ja2V0VGVsZW1ldHJ5QmVmb3JlUmVjb3JkID0gKFxuICByZWNvcmQ6IFdlYlNvY2tldFRlbGVtZXRyeVJlY29yZCxcbikgPT4gV2ViU29ja2V0VGVsZW1ldHJ5UmVjb3JkIHwgbnVsbDtcblxuLy8gLS0gVHJhY2Ugb3B0aW9ucyAvIGNvbm5lY3Rpb24gY29udGV4dCAtLVxuXG5leHBvcnQgdHlwZSBXZWJTb2NrZXRUZWxlbWV0cnlUcmFjZU9wdGlvbnMgPSB7XG4gIGV4dHJhY3RUcmFjZVBhcmVudDogYm9vbGVhbjtcbiAgZ2VuZXJhdGVDb25uZWN0aW9uVHJhY2U6IGJvb2xlYW47XG4gIHByb3BhZ2F0ZU1lc3NhZ2VUcmFjZTogYm9vbGVhbjtcbiAgcmVjb3JkQ29ubmVjdGlvbkxpZmV0aW1lU3BhbjogYm9vbGVhbjtcbn07XG5cbmV4cG9ydCB0eXBlIFdlYlNvY2tldFRlbGVtZXRyeUNvbm5lY3Rpb25Db250ZXh0ID0ge1xuICB0cmFjZUlkPzogc3RyaW5nO1xuICBzcGFuSWQ/OiBzdHJpbmc7XG4gIHBhcmVudFNwYW5JZD86IHN0cmluZztcbiAgc2FtcGxlZD86IGJvb2xlYW47XG59O1xuXG5leHBvcnQgaW50ZXJmYWNlIFRlbGVtZXRyeUNvbnRleHRQcm92aWRlciB7XG4gIGdldFRlbGVtZXRyeUNvbnRleHQoKTogV2ViU29ja2V0VGVsZW1ldHJ5Q29ubmVjdGlvbkNvbnRleHQ7XG59XG5cbi8vIC0tIE9wdGlvbnMgc2NoZW1hIC0tXG5cbmV4cG9ydCB0eXBlIFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50U2FtcGxpbmdPcHRpb25zID0ge1xuICBkZWZhdWx0UmF0ZT86IG51bWJlcjtcbiAgcmF0ZUJ5RXZlbnQ/OiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+O1xuICBtYXhSZWNvcmRzUGVyU2Vjb25kPzogbnVtYmVyO1xuICBhbHdheXNSZWNvcmRMZXZlbHM/OiBBcnJheTxcIndhcm5cIiB8IFwiZXJyb3JcIj47XG59O1xuXG5leHBvcnQgdHlwZSBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNTYW1wbGluZ09wdGlvbnMgPSB7XG4gIG1heFJlY29yZHNQZXJTZWNvbmQ/OiBudW1iZXI7XG59O1xuXG5leHBvcnQgdHlwZSBXZWJTb2NrZXRUZWxlbWV0cnlTcGFuU2FtcGxpbmdPcHRpb25zID0ge1xuICBkZWZhdWx0UmF0ZT86IG51bWJlcjtcbiAgbWF4UmVjb3Jkc1BlclNlY29uZD86IG51bWJlcjtcbn07XG5cbmV4cG9ydCB0eXBlIFdlYlNvY2tldFRlbGVtZXRyeURlZmF1bHRzT3B0aW9ucyA9IHtcbiAgcmVkYWN0b3I/OiBXZWJTb2NrZXRUZWxlbWV0cnlSZWRhY3RvcjtcbiAgYmVmb3JlUmVjb3JkPzogV2ViU29ja2V0VGVsZW1ldHJ5QmVmb3JlUmVjb3JkO1xuICBtYXhSZWNvcmRzPzogbnVtYmVyO1xuICBtYXhCeXRlcz86IG51bWJlcjtcbiAgbWF4UmVjb3Jkc1BlclNlY29uZD86IG51bWJlcjtcbn07XG5cbmV4cG9ydCB0eXBlIFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50c09wdGlvbnMgPSB7XG4gIHNpbmtzPzogV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRTaW5rW107XG4gIHN0b3JlPzogV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRTdG9yZTtcbiAgbWF4UmVjb3Jkcz86IG51bWJlcjtcbiAgbWF4Qnl0ZXM/OiBudW1iZXI7XG4gIG1heEluRmxpZ2h0RW1pdHM/OiBudW1iZXI7XG4gIHJlZGFjdG9yPzogV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRSZWRhY3RvciB8IG51bGw7XG4gIGJlZm9yZVJlY29yZD86IFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50QmVmb3JlUmVjb3JkIHwgbnVsbDtcbiAgc2FtcGxpbmc/OiBXZWJTb2NrZXRUZWxlbWV0cnlFdmVudFNhbXBsaW5nT3B0aW9ucztcbiAgY2FwdHVyZVBheWxvYWQ/OiBmYWxzZSB8IFwicHJldmlld1wiO1xuICBtYXhQYXlsb2FkUHJldmlld0J5dGVzPzogbnVtYmVyO1xufTtcblxuZXhwb3J0IHR5cGUgV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljc09wdGlvbnMgPSB7XG4gIHNpbmtzPzogV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljU2lua1tdO1xuICBzdG9yZT86IFdlYlNvY2tldFRlbGVtZXRyeU1ldHJpY1N0b3JlO1xuICBtYXhSZWNvcmRzPzogbnVtYmVyO1xuICBtYXhCeXRlcz86IG51bWJlcjtcbiAgbWF4SW5GbGlnaHRFbWl0cz86IG51bWJlcjtcbiAgcmVkYWN0b3I/OiBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNSZWRhY3RvciB8IG51bGw7XG4gIGJlZm9yZVJlY29yZD86IFdlYlNvY2tldFRlbGVtZXRyeU1ldHJpY0JlZm9yZVJlY29yZCB8IG51bGw7XG4gIHNhbXBsaW5nPzogV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljU2FtcGxpbmdPcHRpb25zO1xuICBjb2xsZWN0aW9uRW5hYmxlZD86IGJvb2xlYW47XG4gIHNhbXBsZUludGVydmFsTXM/OiBudW1iZXI7XG59O1xuXG5leHBvcnQgdHlwZSBXZWJTb2NrZXRUZWxlbWV0cnlTcGFuc09wdGlvbnMgPSB7XG4gIHNpbmtzPzogV2ViU29ja2V0VGVsZW1ldHJ5U3BhblNpbmtbXTtcbiAgc3RvcmU/OiBXZWJTb2NrZXRUZWxlbWV0cnlTcGFuU3RvcmU7XG4gIG1heFJlY29yZHM/OiBudW1iZXI7XG4gIG1heEJ5dGVzPzogbnVtYmVyO1xuICBtYXhJbkZsaWdodEVtaXRzPzogbnVtYmVyO1xuICByZWRhY3Rvcj86IFdlYlNvY2tldFRlbGVtZXRyeVNwYW5SZWRhY3RvciB8IG51bGw7XG4gIGJlZm9yZVJlY29yZD86IFdlYlNvY2tldFRlbGVtZXRyeVNwYW5CZWZvcmVSZWNvcmQgfCBudWxsO1xuICBzYW1wbGluZz86IFdlYlNvY2tldFRlbGVtZXRyeVNwYW5TYW1wbGluZ09wdGlvbnM7XG59O1xuXG5leHBvcnQgdHlwZSBXZWJTb2NrZXRUZWxlbWV0cnlPcHRpb25zID0ge1xuICBlbmFibGVkPzogYm9vbGVhbjtcbiAgY29udHJvbGxlcj86IFdlYlNvY2tldFRlbGVtZXRyeUNvbnRyb2xsZXI7XG4gIGRlZmF1bHRzPzogV2ViU29ja2V0VGVsZW1ldHJ5RGVmYXVsdHNPcHRpb25zO1xuICBldmVudHM/OiBXZWJTb2NrZXRUZWxlbWV0cnlFdmVudHNPcHRpb25zO1xuICBtZXRyaWNzPzogV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljc09wdGlvbnM7XG4gIHNwYW5zPzogV2ViU29ja2V0VGVsZW1ldHJ5U3BhbnNPcHRpb25zO1xuICB0cmFjZT86IFBhcnRpYWw8V2ViU29ja2V0VGVsZW1ldHJ5VHJhY2VPcHRpb25zPjtcbiAgc2h1dGRvd25UaW1lb3V0TXM/OiBudW1iZXI7XG59O1xuXG4vLyAtLSBDb250cm9sbGVyIGludGVyZmFjZSAtLVxuXG5leHBvcnQgaW50ZXJmYWNlIFdlYlNvY2tldFRlbGVtZXRyeUNvbnRyb2xsZXIge1xuICBlbWl0KGlucHV0OiBXZWJTb2NrZXRUZWxlbWV0cnlFdmVudElucHV0KTogdm9pZDtcbiAgcmVjb3JkTWV0cmljKGlucHV0OiBXZWJTb2NrZXRNZXRyaWNJbnB1dCk6IHZvaWQ7XG4gIHJlY29yZFNwYW4oaW5wdXQ6IFdlYlNvY2tldFNwYW5JbnB1dCk6IHZvaWQ7XG4gIGdldE1ldHJpY3NTbmFwc2hvdCgpOiBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNzU25hcHNob3Q7XG4gIGdldEV2ZW50U3RvcmUoKTogV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRTdG9yZSB8IHVuZGVmaW5lZDtcbiAgZ2V0TWV0cmljU3RvcmUoKTogV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljU3RvcmUgfCB1bmRlZmluZWQ7XG4gIGdldFNwYW5TdG9yZSgpOiBXZWJTb2NrZXRUZWxlbWV0cnlTcGFuU3RvcmUgfCB1bmRlZmluZWQ7XG4gIHJlZ2lzdGVyTWV0cmljU291cmNlKHNvdXJjZTogV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljU291cmNlKTogKCkgPT4gdm9pZDtcbiAgY3JlYXRlQ29ubmVjdGlvbkNvbnRleHQocmVxdWVzdD86IHtcbiAgICBoZWFkZXJzPzogUmVhZG9ubHk8UmVjb3JkPHN0cmluZywgc3RyaW5nIHwgc3RyaW5nW10gfCB1bmRlZmluZWQ+PjtcbiAgfSk6IFdlYlNvY2tldFRlbGVtZXRyeUNvbm5lY3Rpb25Db250ZXh0O1xuICBnZXRUcmFjZU9wdGlvbnMoKTogV2ViU29ja2V0VGVsZW1ldHJ5VHJhY2VPcHRpb25zO1xuICBzaHV0ZG93bihvcHRpb25zPzogeyB0aW1lb3V0TXM/OiBudW1iZXIgfSk6IFByb21pc2U8dm9pZD47XG59XG5cbi8vIC0tIENvbnN0YW50cyBhbmQgc2hhcmVkIGhlbHBlcnMgKHByZXNlcnZlZC1iZWhhdmlvcikgLS1cblxuZXhwb3J0IGNvbnN0IEVNUFRZX01FVFJJQ1NfU05BUFNIT1Q6IFdlYlNvY2tldFRlbGVtZXRyeU1ldHJpY3NTbmFwc2hvdCA9IHtcbiAgdGltZXN0YW1wOiAwLFxuICBhY3RpdmVDb25uZWN0aW9uczogMCxcbiAgYWN0aXZlQ29ubmVjdGlvbnNCeU5hbWVzcGFjZToge30sXG4gIHJvb21Db3VudDogMCxcbiAgcGVuZGluZ0luYm91bmRNZXNzYWdlczogMCxcbiAgcGVuZGluZ091dGJvdW5kTWVzc2FnZXM6IDAsXG4gIHNvY2tldEJ1ZmZlcmVkQnl0ZXM6IDAsXG4gIHBlbmRpbmdGYW5PdXRKb2JzOiAwLFxuICBwZW5kaW5nRmFuT3V0VGFyZ2V0czogMCxcbiAgdGVsZW1ldHJ5RHJvcHBlZFJlY29yZHM6IDAsXG4gIHRlbGVtZXRyeVNpbmtGYWlsdXJlczogMCxcbn07XG5cbmV4cG9ydCBjb25zdCBERUZBVUxUX1RSQUNFX09QVElPTlM6IFdlYlNvY2tldFRlbGVtZXRyeVRyYWNlT3B0aW9ucyA9IHtcbiAgZXh0cmFjdFRyYWNlUGFyZW50OiB0cnVlLFxuICBnZW5lcmF0ZUNvbm5lY3Rpb25UcmFjZTogdHJ1ZSxcbiAgcHJvcGFnYXRlTWVzc2FnZVRyYWNlOiB0cnVlLFxuICByZWNvcmRDb25uZWN0aW9uTGlmZXRpbWVTcGFuOiBmYWxzZSxcbn07XG5cbmNvbnN0IERFRkFVTFRfTUFYX1JFQ09SRFNfUEVSX1NFQ09ORCA9IDEwXzAwMDtcbmNvbnN0IERFRkFVTFRfU0hVVERPV05fVElNRU9VVF9NUyA9IDJfMDAwO1xuY29uc3QgREVGQVVMVF9FVkVOVF9TQU1QTElOR19ERUZBVUxUX1JBVEUgPSAxLjA7XG5jb25zdCBERUZBVUxUX0VWRU5UX0FMV0FZU19SRUNPUkRfTEVWRUxTOiBSZWFkb25seUFycmF5PFwid2FyblwiIHwgXCJlcnJvclwiPiA9IFtcIndhcm5cIiwgXCJlcnJvclwiXTtcbmNvbnN0IERFRkFVTFRfRVZFTlRfQ0FQVFVSRV9QQVlMT0FEOiBmYWxzZSB8IFwicHJldmlld1wiID0gZmFsc2U7XG5jb25zdCBERUZBVUxUX0VWRU5UX01BWF9QQVlMT0FEX1BSRVZJRVdfQllURVMgPSAxMDI0O1xuY29uc3QgREVGQVVMVF9NRVRSSUNfQ09MTEVDVElPTl9FTkFCTEVEID0gdHJ1ZTtcbmNvbnN0IERFRkFVTFRfTUVUUklDX1NBTVBMRV9JTlRFUlZBTF9NUyA9IDEwXzAwMDtcbmNvbnN0IERFRkFVTFRfU1BBTl9TQU1QTElOR19ERUZBVUxUX1JBVEUgPSAxLjA7XG5jb25zdCBERUZBVUxUX01BWF9JTl9GTElHSFRfRU1JVFNfUEVSX1NJTksgPSAxMDA7XG5cbmNvbnN0IFNFTlNJVElWRV9LRVlfUEFUVEVSTlMgPSBbXG4gIFwiYXV0aG9yaXphdGlvblwiLFxuICBcImNvb2tpZVwiLFxuICBcInRva2VuXCIsXG4gIFwicGFzc3dvcmRcIixcbiAgXCJzZWNyZXRcIixcbiAgXCJhcGlrZXlcIixcbiAgXCJzZXNzaW9uXCIsXG4gIFwiZW1haWxcIixcbl0gYXMgY29uc3Q7XG5jb25zdCBSRURBQ1RFRF9WQUxVRSA9IFwiW3JlZGFjdGVkXVwiO1xuXG5mdW5jdGlvbiBpc1NlbnNpdGl2ZUtleShrZXk6IHN0cmluZyk6IGJvb2xlYW4ge1xuICBjb25zdCBub3JtYWxpemVkID0ga2V5LnJlcGxhY2UoL1teYS16QS1aMC05XS9nLCBcIlwiKS50b0xvd2VyQ2FzZSgpO1xuICByZXR1cm4gU0VOU0lUSVZFX0tFWV9QQVRURVJOUy5zb21lKChwYXR0ZXJuKSA9PiBub3JtYWxpemVkLmluY2x1ZGVzKHBhdHRlcm4pKTtcbn1cblxuZnVuY3Rpb24gcmVkYWN0VmFsdWUodmFsdWU6IHVua25vd24sIGtleT86IHN0cmluZyk6IHVua25vd24ge1xuICBpZiAoa2V5ICE9PSB1bmRlZmluZWQgJiYgaXNTZW5zaXRpdmVLZXkoa2V5KSkge1xuICAgIHJldHVybiBSRURBQ1RFRF9WQUxVRTtcbiAgfVxuXG4gIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgIHJldHVybiB2YWx1ZS5tYXAoKGl0ZW0pID0+IHJlZGFjdFZhbHVlKGl0ZW0pKTtcbiAgfVxuXG4gIGlmICh2YWx1ZSBpbnN0YW5jZW9mIERhdGUpIHtcbiAgICByZXR1cm4gdmFsdWU7XG4gIH1cblxuICBpZiAodmFsdWUgJiYgdHlwZW9mIHZhbHVlID09PSBcIm9iamVjdFwiKSB7XG4gICAgY29uc3QgcmVkYWN0ZWQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XG4gICAgZm9yIChjb25zdCBbY2hpbGRLZXksIGNoaWxkVmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHZhbHVlKSkge1xuICAgICAgcmVkYWN0ZWRbY2hpbGRLZXldID0gcmVkYWN0VmFsdWUoY2hpbGRWYWx1ZSwgY2hpbGRLZXkpO1xuICAgIH1cbiAgICByZXR1cm4gcmVkYWN0ZWQ7XG4gIH1cblxuICByZXR1cm4gdmFsdWU7XG59XG5cbi8qKlxuICogZGVmYXVsdFNlbnNpdGl2ZUtleVJlZGFjdCDigJQgc2Vuc2l0aXZlIGtleSDtjKjthLQg6riw67CYIGJ1aWx0LWluIHJlZGFjdG9yLlxuICogcGlwZWxpbmUgZW1pdCBmbG937J2YIOyyqyDri6jqs4Tsl5DshJwg7ZWt7IOBIOyggeyaqeuQnOuLpC5cbiAqL1xuZnVuY3Rpb24gZGVmYXVsdFNlbnNpdGl2ZUtleVJlZGFjdChyZWNvcmQ6IFdlYlNvY2tldFRlbGVtZXRyeVJlY29yZCk6IFdlYlNvY2tldFRlbGVtZXRyeVJlY29yZCB7XG4gIGlmIChyZWNvcmQudHlwZSA9PT0gXCJldmVudFwiKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLnJlY29yZCxcbiAgICAgIGF0dHJpYnV0ZXM6IHJlY29yZC5hdHRyaWJ1dGVzXG4gICAgICAgID8gKHJlZGFjdFZhbHVlKHJlY29yZC5hdHRyaWJ1dGVzKSBhcyBXZWJTb2NrZXRUZWxlbWV0cnlFdmVudFJlY29yZFtcImF0dHJpYnV0ZXNcIl0pXG4gICAgICAgIDogdW5kZWZpbmVkLFxuICAgICAgZGV0YWlsOiByZWNvcmQuZGV0YWlsXG4gICAgICAgID8gKHJlZGFjdFZhbHVlKHJlY29yZC5kZXRhaWwpIGFzIFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50UmVjb3JkW1wiZGV0YWlsXCJdKVxuICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICAgIHBheWxvYWRQcmV2aWV3OiByZWNvcmQucGF5bG9hZFByZXZpZXcsXG4gICAgfTtcbiAgfVxuXG4gIGlmIChyZWNvcmQudHlwZSA9PT0gXCJtZXRyaWNcIikge1xuICAgIHJldHVybiB7XG4gICAgICAuLi5yZWNvcmQsXG4gICAgICB0YWdzOiByZWNvcmQudGFnc1xuICAgICAgICA/IChyZWRhY3RWYWx1ZShyZWNvcmQudGFncykgYXMgV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljUmVjb3JkW1widGFnc1wiXSlcbiAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgICBzbmFwc2hvdDogcmVjb3JkLnNuYXBzaG90ID8geyAuLi5yZWNvcmQuc25hcHNob3QgfSA6IHVuZGVmaW5lZCxcbiAgICB9O1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICAuLi5yZWNvcmQsXG4gICAgYXR0cmlidXRlczogcmVjb3JkLmF0dHJpYnV0ZXNcbiAgICAgID8gKHJlZGFjdFZhbHVlKHJlY29yZC5hdHRyaWJ1dGVzKSBhcyBXZWJTb2NrZXRUZWxlbWV0cnlTcGFuUmVjb3JkW1wiYXR0cmlidXRlc1wiXSlcbiAgICAgIDogdW5kZWZpbmVkLFxuICAgIGV2ZW50czogcmVjb3JkLmV2ZW50cz8ubWFwKChldmVudCkgPT4gKHtcbiAgICAgIC4uLmV2ZW50LFxuICAgICAgYXR0cmlidXRlczogZXZlbnQuYXR0cmlidXRlc1xuICAgICAgICA/IChyZWRhY3RWYWx1ZShldmVudC5hdHRyaWJ1dGVzKSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPilcbiAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgfSkpLFxuICAgIGxpbmtzOiByZWNvcmQubGlua3M/Lm1hcCgobGluaykgPT4gKHtcbiAgICAgIC4uLmxpbmssXG4gICAgICBhdHRyaWJ1dGVzOiBsaW5rLmF0dHJpYnV0ZXNcbiAgICAgICAgPyAocmVkYWN0VmFsdWUobGluay5hdHRyaWJ1dGVzKSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPilcbiAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgfSkpLFxuICB9O1xufVxuXG5mdW5jdGlvbiB0cnVuY2F0ZVBheWxvYWRQcmV2aWV3KHBheWxvYWQ6IHVua25vd24sIG1heEJ5dGVzOiBudW1iZXIpOiBzdHJpbmcge1xuICB0cnkge1xuICAgIGNvbnN0IHNlcmlhbGl6ZWQgPSBKU09OLnN0cmluZ2lmeShyZWRhY3RWYWx1ZShwYXlsb2FkKSk7XG4gICAgaWYgKEJ1ZmZlci5ieXRlTGVuZ3RoKHNlcmlhbGl6ZWQsIFwidXRmLThcIikgPD0gbWF4Qnl0ZXMpIHtcbiAgICAgIHJldHVybiBzZXJpYWxpemVkO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1bmNhdGVVdGY4U3RyaW5nKHNlcmlhbGl6ZWQsIG1heEJ5dGVzKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIFwiW3Vuc2VyaWFsaXphYmxlXVwiO1xuICB9XG59XG5cbmZ1bmN0aW9uIHRydW5jYXRlVXRmOFN0cmluZyh2YWx1ZTogc3RyaW5nLCBtYXhCeXRlczogbnVtYmVyKTogc3RyaW5nIHtcbiAgaWYgKG1heEJ5dGVzIDw9IDApIHJldHVybiBcIlwiO1xuXG4gIGNvbnN0IHN1ZmZpeCA9IG1heEJ5dGVzID49IDMgPyBcIi4uLlwiIDogXCJcIjtcbiAgY29uc3QgY29udGVudEJ1ZGdldCA9IG1heEJ5dGVzIC0gQnVmZmVyLmJ5dGVMZW5ndGgoc3VmZml4LCBcInV0Zi04XCIpO1xuICBsZXQgcmVzdWx0ID0gXCJcIjtcbiAgbGV0IHVzZWRCeXRlcyA9IDA7XG5cbiAgZm9yIChjb25zdCBjaGFyIG9mIHZhbHVlKSB7XG4gICAgY29uc3QgY2hhckJ5dGVzID0gQnVmZmVyLmJ5dGVMZW5ndGgoY2hhciwgXCJ1dGYtOFwiKTtcbiAgICBpZiAodXNlZEJ5dGVzICsgY2hhckJ5dGVzID4gY29udGVudEJ1ZGdldCkgYnJlYWs7XG4gICAgcmVzdWx0ICs9IGNoYXI7XG4gICAgdXNlZEJ5dGVzICs9IGNoYXJCeXRlcztcbiAgfVxuXG4gIHJldHVybiByZXN1bHQgKyBzdWZmaXg7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc1Byb21pc2VMaWtlKHZhbHVlOiB1bmtub3duKTogdmFsdWUgaXMgUHJvbWlzZTx2b2lkPiB7XG4gIHJldHVybiB0eXBlb2YgdmFsdWUgPT09IFwib2JqZWN0XCIgJiYgdmFsdWUgIT09IG51bGwgJiYgXCJ0aGVuXCIgaW4gdmFsdWUgJiYgXCJjYXRjaFwiIGluIHZhbHVlO1xufVxuXG4vLyAtLSBUb2tlbkJ1Y2tldCAodW5jaGFuZ2VkKSAtLVxuXG5jbGFzcyBUb2tlbkJ1Y2tldCB7XG4gIHByaXZhdGUgdG9rZW5zOiBudW1iZXI7XG4gIHByaXZhdGUgbGFzdFJlZmlsbDogbnVtYmVyO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgbWF4VG9rZW5zOiBudW1iZXIsXG4gICAgcHJpdmF0ZSByZWFkb25seSByZWZpbGxSYXRlOiBudW1iZXIsXG4gICkge1xuICAgIHRoaXMudG9rZW5zID0gbWF4VG9rZW5zO1xuICAgIHRoaXMubGFzdFJlZmlsbCA9IERhdGUubm93KCk7XG4gIH1cblxuICB0cnlDb25zdW1lKCk6IGJvb2xlYW4ge1xuICAgIHRoaXMucmVmaWxsKCk7XG4gICAgaWYgKHRoaXMudG9rZW5zIDwgMSkgcmV0dXJuIGZhbHNlO1xuICAgIHRoaXMudG9rZW5zIC09IDE7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBwcml2YXRlIHJlZmlsbCgpOiB2b2lkIHtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgIGNvbnN0IGVsYXBzZWQgPSAobm93IC0gdGhpcy5sYXN0UmVmaWxsKSAvIDEwMDA7XG4gICAgdGhpcy50b2tlbnMgPSBNYXRoLm1pbih0aGlzLm1heFRva2VucywgdGhpcy50b2tlbnMgKyBlbGFwc2VkICogdGhpcy5yZWZpbGxSYXRlKTtcbiAgICB0aGlzLmxhc3RSZWZpbGwgPSBub3c7XG4gIH1cbn1cblxuLy8gLS0gTm9vcFdlYlNvY2tldFRlbGVtZXRyeUNvbnRyb2xsZXIgKHByZXNlcnZlZC1iZWhhdmlvcikgLS1cblxuY29uc3Qgbm9vcFVuc3Vic2NyaWJlID0gKCk6IHZvaWQgPT4ge307XG5cbmV4cG9ydCBjbGFzcyBOb29wV2ViU29ja2V0VGVsZW1ldHJ5Q29udHJvbGxlciBpbXBsZW1lbnRzIFdlYlNvY2tldFRlbGVtZXRyeUNvbnRyb2xsZXIge1xuICBlbWl0KF9pbnB1dDogV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRJbnB1dCk6IHZvaWQge1xuICAgIC8vIG5vb3BcbiAgfVxuXG4gIHJlY29yZE1ldHJpYyhfaW5wdXQ6IFdlYlNvY2tldE1ldHJpY0lucHV0KTogdm9pZCB7XG4gICAgLy8gbm9vcFxuICB9XG5cbiAgcmVjb3JkU3BhbihfaW5wdXQ6IFdlYlNvY2tldFNwYW5JbnB1dCk6IHZvaWQge1xuICAgIC8vIG5vb3BcbiAgfVxuXG4gIGdldE1ldHJpY3NTbmFwc2hvdCgpOiBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNzU25hcHNob3Qge1xuICAgIHJldHVybiB7IC4uLkVNUFRZX01FVFJJQ1NfU05BUFNIT1QsIHRpbWVzdGFtcDogRGF0ZS5ub3coKSB9O1xuICB9XG5cbiAgZ2V0RXZlbnRTdG9yZSgpOiBXZWJTb2NrZXRUZWxlbWV0cnlFdmVudFN0b3JlIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgZ2V0TWV0cmljU3RvcmUoKTogV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljU3RvcmUgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBnZXRTcGFuU3RvcmUoKTogV2ViU29ja2V0VGVsZW1ldHJ5U3BhblN0b3JlIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgcmVnaXN0ZXJNZXRyaWNTb3VyY2UoX3NvdXJjZTogV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljU291cmNlKTogKCkgPT4gdm9pZCB7XG4gICAgcmV0dXJuIG5vb3BVbnN1YnNjcmliZTtcbiAgfVxuXG4gIGNyZWF0ZUNvbm5lY3Rpb25Db250ZXh0KF9yZXF1ZXN0Pzoge1xuICAgIGhlYWRlcnM/OiBSZWFkb25seTxSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCBzdHJpbmdbXSB8IHVuZGVmaW5lZD4+O1xuICB9KTogV2ViU29ja2V0VGVsZW1ldHJ5Q29ubmVjdGlvbkNvbnRleHQge1xuICAgIHJldHVybiB7fTtcbiAgfVxuXG4gIGdldFRyYWNlT3B0aW9ucygpOiBXZWJTb2NrZXRUZWxlbWV0cnlUcmFjZU9wdGlvbnMge1xuICAgIHJldHVybiB7IC4uLkRFRkFVTFRfVFJBQ0VfT1BUSU9OUyB9O1xuICB9XG5cbiAgc2h1dGRvd24oX29wdGlvbnM/OiB7IHRpbWVvdXRNcz86IG51bWJlciB9KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICB9XG59XG5cbi8vIC0tIFJlc29sdmVkIHBlci1waXBlbGluZSBvcHRpb24gdHlwZXMgKGludGVybmFsKSAtLVxuXG50eXBlIFJ1bnRpbWVNZXRhZGF0YSA9IHtcbiAgcnVudGltZUlkOiBzdHJpbmc7XG4gIG5vZGVJZDogc3RyaW5nO1xufTtcblxudHlwZSBSZXNvbHZlZEV2ZW50UGlwZWxpbmVPcHRpb25zID0ge1xuICBzaW5rczogV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRTaW5rW107XG4gIHN0b3JlOiBXZWJTb2NrZXRUZWxlbWV0cnlFdmVudFN0b3JlIHwgdW5kZWZpbmVkO1xuICBtYXhSZWNvcmRzUGVyU2Vjb25kOiBudW1iZXI7XG4gIG1heEluRmxpZ2h0RW1pdHM6IG51bWJlcjtcbiAgc2hhcmVkUmVkYWN0b3I6IFdlYlNvY2tldFRlbGVtZXRyeVJlZGFjdG9yIHwgdW5kZWZpbmVkO1xuICBzaWduYWxSZWRhY3RvcjogV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRSZWRhY3RvciB8IHVuZGVmaW5lZDtcbiAgc2hhcmVkQmVmb3JlUmVjb3JkOiBXZWJTb2NrZXRUZWxlbWV0cnlCZWZvcmVSZWNvcmQgfCB1bmRlZmluZWQ7XG4gIHNpZ25hbEJlZm9yZVJlY29yZDogV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRCZWZvcmVSZWNvcmQgfCB1bmRlZmluZWQ7XG4gIHNhbXBsaW5nOiB7XG4gICAgZGVmYXVsdFJhdGU6IG51bWJlcjtcbiAgICByYXRlQnlFdmVudDogUmVjb3JkPHN0cmluZywgbnVtYmVyPjtcbiAgICBhbHdheXNSZWNvcmRMZXZlbHM6IEFycmF5PFwid2FyblwiIHwgXCJlcnJvclwiPjtcbiAgfTtcbiAgY2FwdHVyZVBheWxvYWQ6IGZhbHNlIHwgXCJwcmV2aWV3XCI7XG4gIG1heFBheWxvYWRQcmV2aWV3Qnl0ZXM6IG51bWJlcjtcbn07XG5cbnR5cGUgUmVzb2x2ZWRNZXRyaWNQaXBlbGluZU9wdGlvbnMgPSB7XG4gIHNpbmtzOiBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNTaW5rW107XG4gIHN0b3JlOiBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNTdG9yZSB8IHVuZGVmaW5lZDtcbiAgbWF4UmVjb3Jkc1BlclNlY29uZDogbnVtYmVyO1xuICBtYXhJbkZsaWdodEVtaXRzOiBudW1iZXI7XG4gIHNoYXJlZFJlZGFjdG9yOiBXZWJTb2NrZXRUZWxlbWV0cnlSZWRhY3RvciB8IHVuZGVmaW5lZDtcbiAgc2lnbmFsUmVkYWN0b3I6IFdlYlNvY2tldFRlbGVtZXRyeU1ldHJpY1JlZGFjdG9yIHwgdW5kZWZpbmVkO1xuICBzaGFyZWRCZWZvcmVSZWNvcmQ6IFdlYlNvY2tldFRlbGVtZXRyeUJlZm9yZVJlY29yZCB8IHVuZGVmaW5lZDtcbiAgc2lnbmFsQmVmb3JlUmVjb3JkOiBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNCZWZvcmVSZWNvcmQgfCB1bmRlZmluZWQ7XG4gIGNvbGxlY3Rpb25FbmFibGVkOiBib29sZWFuO1xuICBzYW1wbGVJbnRlcnZhbE1zOiBudW1iZXI7XG59O1xuXG50eXBlIFJlc29sdmVkU3BhblBpcGVsaW5lT3B0aW9ucyA9IHtcbiAgc2lua3M6IFdlYlNvY2tldFRlbGVtZXRyeVNwYW5TaW5rW107XG4gIHN0b3JlOiBXZWJTb2NrZXRUZWxlbWV0cnlTcGFuU3RvcmUgfCB1bmRlZmluZWQ7XG4gIG1heFJlY29yZHNQZXJTZWNvbmQ6IG51bWJlcjtcbiAgbWF4SW5GbGlnaHRFbWl0czogbnVtYmVyO1xuICBzaGFyZWRSZWRhY3RvcjogV2ViU29ja2V0VGVsZW1ldHJ5UmVkYWN0b3IgfCB1bmRlZmluZWQ7XG4gIHNpZ25hbFJlZGFjdG9yOiBXZWJTb2NrZXRUZWxlbWV0cnlTcGFuUmVkYWN0b3IgfCB1bmRlZmluZWQ7XG4gIHNoYXJlZEJlZm9yZVJlY29yZDogV2ViU29ja2V0VGVsZW1ldHJ5QmVmb3JlUmVjb3JkIHwgdW5kZWZpbmVkO1xuICBzaWduYWxCZWZvcmVSZWNvcmQ6IFdlYlNvY2tldFRlbGVtZXRyeVNwYW5CZWZvcmVSZWNvcmQgfCB1bmRlZmluZWQ7XG4gIHNhbXBsaW5nOiB7XG4gICAgZGVmYXVsdFJhdGU6IG51bWJlcjtcbiAgfTtcbn07XG5cbi8vIC0tIEludGVybmFsIGV2ZW50IHJlcG9ydGVyIHR5cGUgLS1cbi8vIEV2ZW50UGlwZWxpbmUg7J6Q7Iug6rO8IGNvbnRyb2xsZXLqsIAg64K067aAIOynhOuLqCDsnbTrsqTtirjrpbwg67Cc7ZaJ7ZWgIOuVjCDsgqzsmqntlZzri6QuXG4vLyB0eXBlLW1pc21hdGNoIC8gc2h1dGRvd24udGltZW91dCAvIHNpbmsuZmFpbGVkIOuTseydhCBldmVudHMgcGlwZWxpbmUg6rK966Gc66GcIOuztOuCuOuLpC5cbnR5cGUgSW50ZXJuYWxFdmVudFJlcG9ydGVyID0gKFxuICBuYW1lOiBzdHJpbmcsXG4gIGxldmVsOiBXZWJTb2NrZXRUZWxlbWV0cnlFdmVudFJlY29yZFtcImxldmVsXCJdLFxuICBkZXRhaWw/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbikgPT4gdm9pZDtcblxuLy8gLS0gVGVsZW1ldHJ5UGlwZWxpbmUgKGFic3RyYWN0KSAtLVxuXG5hYnN0cmFjdCBjbGFzcyBUZWxlbWV0cnlQaXBlbGluZTxcbiAgVFJlY29yZCBleHRlbmRzIFdlYlNvY2tldFRlbGVtZXRyeVJlY29yZCxcbiAgVElucHV0LFxuICBUU2luayBleHRlbmRzIHtcbiAgICBlbWl0KHJlY29yZDogVFJlY29yZCk6IHZvaWQgfCBQcm9taXNlPHZvaWQ+O1xuICAgIHNodXRkb3duPyhvcHRpb25zPzogeyB0aW1lb3V0TXM/OiBudW1iZXIgfSk6IHZvaWQgfCBQcm9taXNlPHZvaWQ+O1xuICB9LFxuICBUU3RvcmUgZXh0ZW5kcyB7IHJlYWRvbmx5IHNpbms6IFRTaW5rOyBjbGVhcigpOiB2b2lkIH0gfCB1bmRlZmluZWQsXG4+IHtcbiAgYWJzdHJhY3QgcmVhZG9ubHkgc2lnbmFsOiBcImV2ZW50XCIgfCBcIm1ldHJpY1wiIHwgXCJzcGFuXCI7XG4gIHByb3RlY3RlZCByZWFkb25seSBzaW5rczogVFNpbmtbXTtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IF9zdG9yZTogVFN0b3JlO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgdG9rZW5CdWNrZXQ6IFRva2VuQnVja2V0O1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgbWF4SW5GbGlnaHRFbWl0czogbnVtYmVyO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgcnVudGltZU1ldGFkYXRhOiBSdW50aW1lTWV0YWRhdGE7XG4gIHByb3RlY3RlZCByZWFkb25seSBzaGFyZWRSZWRhY3RvcjogV2ViU29ja2V0VGVsZW1ldHJ5UmVkYWN0b3IgfCB1bmRlZmluZWQ7XG4gIHByb3RlY3RlZCByZWFkb25seSBzaGFyZWRCZWZvcmVSZWNvcmQ6IFdlYlNvY2tldFRlbGVtZXRyeUJlZm9yZVJlY29yZCB8IHVuZGVmaW5lZDtcbiAgcHJvdGVjdGVkIGludGVybmFsRXZlbnRSZXBvcnRlcjogSW50ZXJuYWxFdmVudFJlcG9ydGVyIHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIHJlYWRvbmx5IGluRmxpZ2h0RW1pdHMgPSBuZXcgV2Vha01hcDxUU2luaywgbnVtYmVyPigpO1xuICBkcm9wcGVkQ291bnQgPSAwO1xuICBzaW5rRmFpbHVyZUNvdW50ID0gMDtcbiAgc2h1dGRvd25DYWxsZWQgPSBmYWxzZTtcblxuICBwcm90ZWN0ZWQgY29uc3RydWN0b3IoXG4gICAgc2lua3M6IFRTaW5rW10sXG4gICAgc3RvcmU6IFRTdG9yZSxcbiAgICBtYXhSZWNvcmRzUGVyU2Vjb25kOiBudW1iZXIsXG4gICAgbWF4SW5GbGlnaHRFbWl0czogbnVtYmVyLFxuICAgIHNoYXJlZFJlZGFjdG9yOiBXZWJTb2NrZXRUZWxlbWV0cnlSZWRhY3RvciB8IHVuZGVmaW5lZCxcbiAgICBzaGFyZWRCZWZvcmVSZWNvcmQ6IFdlYlNvY2tldFRlbGVtZXRyeUJlZm9yZVJlY29yZCB8IHVuZGVmaW5lZCxcbiAgICBydW50aW1lTWV0YWRhdGE6IFJ1bnRpbWVNZXRhZGF0YSxcbiAgKSB7XG4gICAgdGhpcy5zaW5rcyA9IHNpbmtzO1xuICAgIHRoaXMuX3N0b3JlID0gc3RvcmU7XG4gICAgdGhpcy50b2tlbkJ1Y2tldCA9IG5ldyBUb2tlbkJ1Y2tldChtYXhSZWNvcmRzUGVyU2Vjb25kLCBtYXhSZWNvcmRzUGVyU2Vjb25kKTtcbiAgICB0aGlzLm1heEluRmxpZ2h0RW1pdHMgPSBtYXhJbkZsaWdodEVtaXRzO1xuICAgIHRoaXMuc2hhcmVkUmVkYWN0b3IgPSBzaGFyZWRSZWRhY3RvcjtcbiAgICB0aGlzLnNoYXJlZEJlZm9yZVJlY29yZCA9IHNoYXJlZEJlZm9yZVJlY29yZDtcbiAgICB0aGlzLnJ1bnRpbWVNZXRhZGF0YSA9IHJ1bnRpbWVNZXRhZGF0YTtcbiAgfVxuXG4gIGdldCBzdG9yZSgpOiBUU3RvcmUge1xuICAgIHJldHVybiB0aGlzLl9zdG9yZTtcbiAgfVxuXG4gIHNldEludGVybmFsRXZlbnRSZXBvcnRlcihyZXBvcnRlcjogSW50ZXJuYWxFdmVudFJlcG9ydGVyKTogdm9pZCB7XG4gICAgdGhpcy5pbnRlcm5hbEV2ZW50UmVwb3J0ZXIgPSByZXBvcnRlcjtcbiAgfVxuXG4gIGFic3RyYWN0IGVtaXQoaW5wdXQ6IFRJbnB1dCk6IHZvaWQ7XG5cbiAgcHJvdGVjdGVkIGFic3RyYWN0IGJ1aWxkUmVjb3JkKGlucHV0OiBUSW5wdXQpOiBUUmVjb3JkO1xuXG4gIHByb3RlY3RlZCBhYnN0cmFjdCBzaG91bGRCeXBhc3NSYXRlTGltaXQocmVjb3JkOiBUUmVjb3JkKTogYm9vbGVhbjtcblxuICBwcm90ZWN0ZWQgYWJzdHJhY3QgaXNDcml0aWNhbFJlY29yZChyZWNvcmQ6IFRSZWNvcmQpOiBib29sZWFuO1xuXG4gIHByb3RlY3RlZCBhYnN0cmFjdCBnZXRTaWduYWxSZWRhY3RvcigpOiAoKHJlY29yZDogVFJlY29yZCkgPT4gVFJlY29yZCB8IG51bGwpIHwgdW5kZWZpbmVkO1xuXG4gIHByb3RlY3RlZCBhYnN0cmFjdCBnZXRTaWduYWxCZWZvcmVSZWNvcmQoKTogKChyZWNvcmQ6IFRSZWNvcmQpID0+IFRSZWNvcmQgfCBudWxsKSB8IHVuZGVmaW5lZDtcblxuICAvLyDqs7XthrUgZW1pdCDtnZDrpoQuIOuqqOuToCDsi6DtmLjrs4QgcGlwZWxpbmXsnZggZW1pdOydtCDsnbQg66mU7ISc65Oc66GcIOychOyehO2VnOuLpC5cbiAgcHJvdGVjdGVkIGVtaXRJbnRlcm5hbChpbnB1dDogVElucHV0KTogdm9pZCB7XG4gICAgaWYgKHRoaXMuc2h1dGRvd25DYWxsZWQpIHJldHVybjtcblxuICAgIGxldCByZWNvcmQ6IFRSZWNvcmQ7XG4gICAgdHJ5IHtcbiAgICAgIHJlY29yZCA9IHRoaXMuYnVpbGRSZWNvcmQoaW5wdXQpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgdGhpcy5kcm9wcGVkQ291bnQgKz0gMTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBza2lwUmF0ZUxpbWl0ID0gdGhpcy5zaG91bGRCeXBhc3NSYXRlTGltaXQocmVjb3JkKTtcbiAgICBpZiAoIXNraXBSYXRlTGltaXQgJiYgIXRoaXMudG9rZW5CdWNrZXQudHJ5Q29uc3VtZSgpKSB7XG4gICAgICB0aGlzLmRyb3BwZWRDb3VudCArPSAxO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIHN0ZXAgMTogZGVmYXVsdFNlbnNpdGl2ZUtleVJlZGFjdCDtla3sg4Eg7KCB7JqpXG4gICAgbGV0IHByZXBhcmVkOiBUUmVjb3JkO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBhZnRlckRlZmF1bHQgPSBkZWZhdWx0U2Vuc2l0aXZlS2V5UmVkYWN0KHJlY29yZCk7XG4gICAgICBpZiAoYWZ0ZXJEZWZhdWx0LnR5cGUgIT09IHJlY29yZC50eXBlKSB7XG4gICAgICAgIC8vIOuwqeyWtCDroZzsp4Eg4oCUIOuzuCDqtaztmITsl5DshJzripQg67Cc7IOd7ZWY7KeAIOyViuyngOunjCB0eXBlLW5hcnJvd+ulvCDsnITtlbQg6rKA7KadXG4gICAgICAgIHRoaXMuZHJvcHBlZENvdW50ICs9IDE7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHByZXBhcmVkID0gYWZ0ZXJEZWZhdWx0IGFzIFRSZWNvcmQ7XG4gICAgfSBjYXRjaCB7XG4gICAgICB0aGlzLmRyb3BwZWRDb3VudCArPSAxO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIHN0ZXAgMjogc2hhcmVkUmVkYWN0b3IgKOydtOuvuCBidWlsZENvbnRyb2xsZXLsl5DshJwgc2lnbmFsUmVkYWN0b3I9PT1udWxs7J2066m0IHNoYXJlZFJlZGFjdG9yPXVuZGVmaW5lZOuhnCDrja7slrTsk7Qg7IOB7YOcKVxuICAgIGlmICh0aGlzLnNoYXJlZFJlZGFjdG9yICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IHNoYXJlZFJlZGFjdG9yID0gdGhpcy5zaGFyZWRSZWRhY3RvcjtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IHRoaXMuYXBwbHlUcmFuc2Zvcm0ocHJlcGFyZWQsIChyKSA9PiBzaGFyZWRSZWRhY3RvcihyKSwgXCJzaGFyZWRcIiwgXCJyZWRhY3RvclwiKTtcbiAgICAgIGlmIChyZXN1bHQgPT09IG51bGwpIHJldHVybjtcbiAgICAgIHByZXBhcmVkID0gcmVzdWx0O1xuICAgIH1cblxuICAgIC8vIHN0ZXAgMzogc2lnbmFsUmVkYWN0b3JcbiAgICBjb25zdCBzaWduYWxSZWRhY3RvciA9IHRoaXMuZ2V0U2lnbmFsUmVkYWN0b3IoKTtcbiAgICBpZiAoc2lnbmFsUmVkYWN0b3IgIT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gdGhpcy5hcHBseVRyYW5zZm9ybShwcmVwYXJlZCwgKHIpID0+IHNpZ25hbFJlZGFjdG9yKHIpLCBcInNpZ25hbFwiLCBcInJlZGFjdG9yXCIpO1xuICAgICAgaWYgKHJlc3VsdCA9PT0gbnVsbCkgcmV0dXJuO1xuICAgICAgcHJlcGFyZWQgPSByZXN1bHQ7XG4gICAgfVxuXG4gICAgLy8gc3RlcCA0OiBzaGFyZWRCZWZvcmVSZWNvcmRcbiAgICBpZiAodGhpcy5zaGFyZWRCZWZvcmVSZWNvcmQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3Qgc2hhcmVkQmVmb3JlUmVjb3JkID0gdGhpcy5zaGFyZWRCZWZvcmVSZWNvcmQ7XG4gICAgICBjb25zdCByZXN1bHQgPSB0aGlzLmFwcGx5VHJhbnNmb3JtKFxuICAgICAgICBwcmVwYXJlZCxcbiAgICAgICAgKHIpID0+IHNoYXJlZEJlZm9yZVJlY29yZChyKSxcbiAgICAgICAgXCJzaGFyZWRcIixcbiAgICAgICAgXCJiZWZvcmVSZWNvcmRcIixcbiAgICAgICk7XG4gICAgICBpZiAocmVzdWx0ID09PSBudWxsKSByZXR1cm47XG4gICAgICBwcmVwYXJlZCA9IHJlc3VsdDtcbiAgICB9XG5cbiAgICAvLyBzdGVwIDU6IHNpZ25hbEJlZm9yZVJlY29yZFxuICAgIGNvbnN0IHNpZ25hbEJlZm9yZVJlY29yZCA9IHRoaXMuZ2V0U2lnbmFsQmVmb3JlUmVjb3JkKCk7XG4gICAgaWYgKHNpZ25hbEJlZm9yZVJlY29yZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCByZXN1bHQgPSB0aGlzLmFwcGx5VHJhbnNmb3JtKFxuICAgICAgICBwcmVwYXJlZCxcbiAgICAgICAgKHIpID0+IHNpZ25hbEJlZm9yZVJlY29yZChyKSxcbiAgICAgICAgXCJzaWduYWxcIixcbiAgICAgICAgXCJiZWZvcmVSZWNvcmRcIixcbiAgICAgICk7XG4gICAgICBpZiAocmVzdWx0ID09PSBudWxsKSByZXR1cm47XG4gICAgICBwcmVwYXJlZCA9IHJlc3VsdDtcbiAgICB9XG5cbiAgICB0aGlzLmRpc3BhdGNoVG9TaW5rcyhwcmVwYXJlZCk7XG4gIH1cblxuICAvLyByZWRhY3RvciDrmJDripQgYmVmb3JlUmVjb3JkIDHtmowg7KCB7JqpLiDrsJjtmZjqsJLsnbQgbnVsbOydtOuptCBkcm9wLCB0eXBlIOu2iOydvOy5mOuptCBkcm9wICsgaW50ZXJuYWwgZXZlbnQuXG4gIC8vIHNoYXJlZCDrs4DtmZjsnYAgd2lkZXIgcmVjb3Jk66W8IOuwm+yVhCB3aWRlciByZWNvcmTrpbwg67CY7ZmY7ZWY7KeA66eMLCBzaWduYWwg67OA7ZmY7J2AIG5hcnJvd2VkIFRSZWNvcmTrgbzrpqwg67OA7ZmY7ZWc64ukLlxuICAvLyDslpHsqr0g66qo65GQIOuPmeydvO2VnCB0eXBlLW1pc21hdGNoIGRlZmVuc2l2ZSDqsoDsgqzrpbwg6rGw7Lmc64ukLlxuICBwcml2YXRlIGFwcGx5VHJhbnNmb3JtKFxuICAgIHJlY29yZDogVFJlY29yZCxcbiAgICBydW5uZXI6IChyZWNvcmQ6IFRSZWNvcmQpID0+IFdlYlNvY2tldFRlbGVtZXRyeVJlY29yZCB8IG51bGwsXG4gICAgc291cmNlOiBcInNoYXJlZFwiIHwgXCJzaWduYWxcIixcbiAgICBraW5kOiBcInJlZGFjdG9yXCIgfCBcImJlZm9yZVJlY29yZFwiLFxuICApOiBUUmVjb3JkIHwgbnVsbCB7XG4gICAgbGV0IHJlc3VsdDogV2ViU29ja2V0VGVsZW1ldHJ5UmVjb3JkIHwgbnVsbDtcbiAgICB0cnkge1xuICAgICAgcmVzdWx0ID0gcnVubmVyKHJlY29yZCk7XG4gICAgfSBjYXRjaCB7XG4gICAgICB0aGlzLmRyb3BwZWRDb3VudCArPSAxO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgaWYgKHJlc3VsdCA9PT0gbnVsbCkge1xuICAgICAgdGhpcy5kcm9wcGVkQ291bnQgKz0gMTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGlmIChyZXN1bHQudHlwZSAhPT0gcmVjb3JkLnR5cGUpIHtcbiAgICAgIHRoaXMuZHJvcHBlZENvdW50ICs9IDE7XG4gICAgICBjb25zdCBldmVudE5hbWUgPVxuICAgICAgICBraW5kID09PSBcInJlZGFjdG9yXCJcbiAgICAgICAgICA/IFwid3MudGVsZW1ldHJ5LnJlZGFjdG9yLnR5cGVfbWlzbWF0Y2hcIlxuICAgICAgICAgIDogXCJ3cy50ZWxlbWV0cnkuYmVmb3JlUmVjb3JkLnR5cGVfbWlzbWF0Y2hcIjtcbiAgICAgIHRoaXMuZGlzcGF0Y2hJbnRlcm5hbEV2ZW50KGV2ZW50TmFtZSwgXCJ3YXJuXCIsIHtcbiAgICAgICAgZXhwZWN0ZWQ6IHJlY29yZC50eXBlLFxuICAgICAgICBhY3R1YWw6IHJlc3VsdC50eXBlLFxuICAgICAgICBzb3VyY2UsXG4gICAgICB9KTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8vIHJlc3VsdC50eXBlID09PSByZWNvcmQudHlwZSA9PT0gVFJlY29yZFtcInR5cGVcIl3snbTrr4DroZwgbmFycm93ZWQgVFJlY29yZOuhnCDslYjsoITtlZjqsowg7KKB7Z6QIOyImCDsnojri6QuXG4gICAgcmV0dXJuIHJlc3VsdCBhcyBUUmVjb3JkO1xuICB9XG5cbiAgcHJvdGVjdGVkIGRpc3BhdGNoVG9TaW5rcyhyZWNvcmQ6IFRSZWNvcmQsIHNlbGZPYnNlcnZlRmFpbHVyZXMgPSB0cnVlKTogdm9pZCB7XG4gICAgY29uc3QgY3JpdGljYWwgPSB0aGlzLmlzQ3JpdGljYWxSZWNvcmQocmVjb3JkKTtcbiAgICBsZXQgZHJvcHBlZEZvclJlY29yZCA9IGZhbHNlO1xuXG4gICAgZm9yIChjb25zdCBzaW5rIG9mIHRoaXMuc2lua3MpIHtcbiAgICAgIGNvbnN0IGluRmxpZ2h0ID0gdGhpcy5pbkZsaWdodEVtaXRzLmdldChzaW5rKSA/PyAwO1xuICAgICAgaWYgKCFjcml0aWNhbCAmJiBpbkZsaWdodCA+PSB0aGlzLm1heEluRmxpZ2h0RW1pdHMpIHtcbiAgICAgICAgaWYgKCFkcm9wcGVkRm9yUmVjb3JkKSB7XG4gICAgICAgICAgdGhpcy5kcm9wcGVkQ291bnQgKz0gMTtcbiAgICAgICAgICBkcm9wcGVkRm9yUmVjb3JkID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gc2luay5lbWl0KHJlY29yZCk7XG4gICAgICAgIGlmIChpc1Byb21pc2VMaWtlKHJlc3VsdCkpIHtcbiAgICAgICAgICB0aGlzLmluRmxpZ2h0RW1pdHMuc2V0KHNpbmssIGluRmxpZ2h0ICsgMSk7XG4gICAgICAgICAgcmVzdWx0LnRoZW4oXG4gICAgICAgICAgICAoKSA9PiB7XG4gICAgICAgICAgICAgIHRoaXMuZGVjcmVtZW50SW5GbGlnaHRFbWl0KHNpbmspO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIChlcnJvcjogdW5rbm93bikgPT4ge1xuICAgICAgICAgICAgICB0aGlzLmRlY3JlbWVudEluRmxpZ2h0RW1pdChzaW5rKTtcbiAgICAgICAgICAgICAgdGhpcy5vYnNlcnZlU2lua0ZhaWx1cmUoXCJlbWl0XCIsIGVycm9yLCBzZWxmT2JzZXJ2ZUZhaWx1cmVzKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgdGhpcy5vYnNlcnZlU2lua0ZhaWx1cmUoXCJlbWl0XCIsIGVycm9yLCBzZWxmT2JzZXJ2ZUZhaWx1cmVzKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGRlY3JlbWVudEluRmxpZ2h0RW1pdChzaW5rOiBUU2luayk6IHZvaWQge1xuICAgIGNvbnN0IGN1cnJlbnQgPSB0aGlzLmluRmxpZ2h0RW1pdHMuZ2V0KHNpbmspID8/IDA7XG4gICAgaWYgKGN1cnJlbnQgPD0gMSkge1xuICAgICAgdGhpcy5pbkZsaWdodEVtaXRzLmRlbGV0ZShzaW5rKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5pbkZsaWdodEVtaXRzLnNldChzaW5rLCBjdXJyZW50IC0gMSk7XG4gIH1cblxuICBwcml2YXRlIG9ic2VydmVTaW5rRmFpbHVyZShcbiAgICBwaGFzZTogXCJlbWl0XCIgfCBcInNodXRkb3duXCIsXG4gICAgZXJyb3I6IHVua25vd24sXG4gICAgc2VsZk9ic2VydmVGYWlsdXJlOiBib29sZWFuLFxuICApOiB2b2lkIHtcbiAgICB0aGlzLnNpbmtGYWlsdXJlQ291bnQgKz0gMTtcbiAgICBpZiAoIXNlbGZPYnNlcnZlRmFpbHVyZSkgcmV0dXJuO1xuICAgIHRoaXMuZGlzcGF0Y2hJbnRlcm5hbEV2ZW50KFwid3MudGVsZW1ldHJ5LnNpbmsuZmFpbGVkXCIsIFwid2FyblwiLCB7XG4gICAgICBwaGFzZSxcbiAgICAgIHNpZ25hbDogdGhpcy5zaWduYWwsXG4gICAgICBlcnJvclR5cGU6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5uYW1lIDogdHlwZW9mIGVycm9yLFxuICAgIH0pO1xuICB9XG5cbiAgcHJvdGVjdGVkIGRpc3BhdGNoSW50ZXJuYWxFdmVudChcbiAgICBuYW1lOiBzdHJpbmcsXG4gICAgbGV2ZWw6IFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50UmVjb3JkW1wibGV2ZWxcIl0sXG4gICAgZGV0YWlsPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gICk6IHZvaWQge1xuICAgIGlmICh0aGlzLmludGVybmFsRXZlbnRSZXBvcnRlciA9PT0gdW5kZWZpbmVkKSByZXR1cm47XG4gICAgdHJ5IHtcbiAgICAgIHRoaXMuaW50ZXJuYWxFdmVudFJlcG9ydGVyKG5hbWUsIGxldmVsLCBkZXRhaWwpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8g7KeE64uoIOydtOuypO2KuCDsnpDssrTqsIAg7Iuk7Yyo7ZWY66m0IHN3YWxsb3dcbiAgICB9XG4gIH1cblxuICBhc3luYyBzaHV0ZG93bih0aW1lb3V0TXM6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLnNodXRkb3duQ2FsbGVkKSByZXR1cm47XG4gICAgdGhpcy5zaHV0ZG93bkNhbGxlZCA9IHRydWU7XG5cbiAgICBjb25zdCBzaW5rU2h1dGRvd25zID0gdGhpcy5zaW5rcy5tYXAoKHNpbmspID0+IHRoaXMuc2h1dGRvd25TaW5rKHNpbmssIHRpbWVvdXRNcykpO1xuICAgIGlmIChzaW5rU2h1dGRvd25zLmxlbmd0aCA+IDApIHtcbiAgICAgIGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChzaW5rU2h1dGRvd25zKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHNodXRkb3duU2luayhzaW5rOiBUU2luaywgdGltZW91dE1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXNpbmsuc2h1dGRvd24pIHJldHVybjtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBzaW5rLnNodXRkb3duKHsgdGltZW91dE1zIH0pO1xuICAgICAgaWYgKCFpc1Byb21pc2VMaWtlKHJlc3VsdCkpIHJldHVybjtcblxuICAgICAgbGV0IHRpbWVvdXQ6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgbnVsbCA9IG51bGw7XG4gICAgICBjb25zdCBzaHV0ZG93blByb21pc2UgPSByZXN1bHQudGhlbihcbiAgICAgICAgKCkgPT4gXCJjb21wbGV0ZWRcIiBhcyBjb25zdCxcbiAgICAgICAgKGVycm9yOiB1bmtub3duKSA9PiB7XG4gICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgIH0sXG4gICAgICApO1xuICAgICAgY29uc3QgdGltZW91dFByb21pc2UgPSBuZXcgUHJvbWlzZTxcInRpbWVvdXRcIj4oKHJlc29sdmUpID0+IHtcbiAgICAgICAgdGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgIHJlc29sdmUoXCJ0aW1lb3V0XCIpO1xuICAgICAgICB9LCB0aW1lb3V0TXMpO1xuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IG91dGNvbWUgPSBhd2FpdCBQcm9taXNlLnJhY2UoW3NodXRkb3duUHJvbWlzZSwgdGltZW91dFByb21pc2VdKTtcbiAgICAgIGlmICh0aW1lb3V0KSB7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcbiAgICAgIH1cblxuICAgICAgaWYgKG91dGNvbWUgPT09IFwidGltZW91dFwiKSB7XG4gICAgICAgIHNodXRkb3duUHJvbWlzZS5jYXRjaCgoKSA9PiB7fSk7XG4gICAgICAgIHRoaXMuc2lua0ZhaWx1cmVDb3VudCArPSAxO1xuICAgICAgICB0aGlzLmRpc3BhdGNoSW50ZXJuYWxFdmVudChcIndzLnRlbGVtZXRyeS5zaHV0ZG93bi50aW1lb3V0XCIsIFwid2FyblwiLCB7XG4gICAgICAgICAgdGltZW91dE1zLFxuICAgICAgICAgIHNpZ25hbDogdGhpcy5zaWduYWwsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLm9ic2VydmVTaW5rRmFpbHVyZShcInNodXRkb3duXCIsIGVycm9yLCB0cnVlKTtcbiAgICB9XG4gIH1cbn1cblxuLy8gLS0gRXZlbnRQaXBlbGluZSAtLVxuXG5jbGFzcyBFdmVudFBpcGVsaW5lIGV4dGVuZHMgVGVsZW1ldHJ5UGlwZWxpbmU8XG4gIFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50UmVjb3JkLFxuICBXZWJTb2NrZXRUZWxlbWV0cnlFdmVudElucHV0LFxuICBXZWJTb2NrZXRUZWxlbWV0cnlFdmVudFNpbmssXG4gIFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50U3RvcmUgfCB1bmRlZmluZWRcbj4ge1xuICByZWFkb25seSBzaWduYWwgPSBcImV2ZW50XCIgYXMgY29uc3Q7XG4gIHByb3RlY3RlZCByZWFkb25seSBzaWduYWxSZWRhY3RvcjogV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRSZWRhY3RvciB8IHVuZGVmaW5lZDtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHNpZ25hbEJlZm9yZVJlY29yZDogV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRCZWZvcmVSZWNvcmQgfCB1bmRlZmluZWQ7XG4gIHByb3RlY3RlZCByZWFkb25seSBzYW1wbGluZzoge1xuICAgIGRlZmF1bHRSYXRlOiBudW1iZXI7XG4gICAgcmF0ZUJ5RXZlbnQ6IFJlY29yZDxzdHJpbmcsIG51bWJlcj47XG4gICAgYWx3YXlzUmVjb3JkTGV2ZWxzOiBBcnJheTxcIndhcm5cIiB8IFwiZXJyb3JcIj47XG4gIH07XG4gIHByb3RlY3RlZCByZWFkb25seSBjYXB0dXJlUGF5bG9hZDogZmFsc2UgfCBcInByZXZpZXdcIjtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IG1heFBheWxvYWRQcmV2aWV3Qnl0ZXM6IG51bWJlcjtcbiAgLy8gYWx3YXlzUmVjb3JkIGxldmVsIOqyveuhnOyXkOyEnCBwcmVwYXJlUmVjb3JkKHNraXBSYXRlTGltaXQ9dHJ1ZSkg7J2Y66+466W8IOuztOyhtO2VmOq4sCDsnITtlZwg7ZSM656Y6re4LlxuICBwcml2YXRlIGN1cnJlbnRFbWl0QWx3YXlzUmVjb3JkID0gZmFsc2U7XG5cbiAgY29uc3RydWN0b3Iob3B0aW9uczogUmVzb2x2ZWRFdmVudFBpcGVsaW5lT3B0aW9ucywgcnVudGltZU1ldGFkYXRhOiBSdW50aW1lTWV0YWRhdGEpIHtcbiAgICBzdXBlcihcbiAgICAgIG9wdGlvbnMuc2lua3MsXG4gICAgICBvcHRpb25zLnN0b3JlLFxuICAgICAgb3B0aW9ucy5tYXhSZWNvcmRzUGVyU2Vjb25kLFxuICAgICAgb3B0aW9ucy5tYXhJbkZsaWdodEVtaXRzLFxuICAgICAgb3B0aW9ucy5zaGFyZWRSZWRhY3RvcixcbiAgICAgIG9wdGlvbnMuc2hhcmVkQmVmb3JlUmVjb3JkLFxuICAgICAgcnVudGltZU1ldGFkYXRhLFxuICAgICk7XG4gICAgdGhpcy5zaWduYWxSZWRhY3RvciA9IG9wdGlvbnMuc2lnbmFsUmVkYWN0b3I7XG4gICAgdGhpcy5zaWduYWxCZWZvcmVSZWNvcmQgPSBvcHRpb25zLnNpZ25hbEJlZm9yZVJlY29yZDtcbiAgICB0aGlzLnNhbXBsaW5nID0gb3B0aW9ucy5zYW1wbGluZztcbiAgICB0aGlzLmNhcHR1cmVQYXlsb2FkID0gb3B0aW9ucy5jYXB0dXJlUGF5bG9hZDtcbiAgICB0aGlzLm1heFBheWxvYWRQcmV2aWV3Qnl0ZXMgPSBvcHRpb25zLm1heFBheWxvYWRQcmV2aWV3Qnl0ZXM7XG4gIH1cblxuICBlbWl0KGlucHV0OiBXZWJTb2NrZXRUZWxlbWV0cnlFdmVudElucHV0KTogdm9pZCB7XG4gICAgdHJ5IHtcbiAgICAgIGlmICh0aGlzLnNodXRkb3duQ2FsbGVkKSByZXR1cm47XG5cbiAgICAgIC8vIHNhbXBsaW5nOiBhbHdheXNSZWNvcmRMZXZlbHMg7Jqw7ISgXG4gICAgICBjb25zdCBsZXZlbHM6IFJlYWRvbmx5QXJyYXk8c3RyaW5nPiA9IHRoaXMuc2FtcGxpbmcuYWx3YXlzUmVjb3JkTGV2ZWxzO1xuICAgICAgY29uc3QgYWx3YXlzUmVjb3JkID0gbGV2ZWxzLmluY2x1ZGVzKGlucHV0LmxldmVsKTtcblxuICAgICAgaWYgKCFhbHdheXNSZWNvcmQpIHtcbiAgICAgICAgY29uc3QgcmF0ZSA9IHRoaXMuc2FtcGxpbmcucmF0ZUJ5RXZlbnRbaW5wdXQubmFtZV0gPz8gdGhpcy5zYW1wbGluZy5kZWZhdWx0UmF0ZTtcbiAgICAgICAgaWYgKHJhdGUgPD0gMCkge1xuICAgICAgICAgIHRoaXMuZHJvcHBlZENvdW50ICs9IDE7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGlmIChyYXRlIDwgMSAmJiBNYXRoLnJhbmRvbSgpID49IHJhdGUpIHtcbiAgICAgICAgICB0aGlzLmRyb3BwZWRDb3VudCArPSAxO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICB0aGlzLmN1cnJlbnRFbWl0QWx3YXlzUmVjb3JkID0gYWx3YXlzUmVjb3JkO1xuICAgICAgdHJ5IHtcbiAgICAgICAgdGhpcy5lbWl0SW50ZXJuYWwoaW5wdXQpO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgdGhpcy5jdXJyZW50RW1pdEFsd2F5c1JlY29yZCA9IGZhbHNlO1xuICAgICAgfVxuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gcGlwZWxpbmUgZW1pdCDrmJDtlZwgdGhyb3ctZnJlZSDsoJXssYVcbiAgICB9XG4gIH1cblxuICAvLyDrgrTrtoAg7KeE64uoIOydtOuypO2KuCDigJQgc2FtcGxpbmcvcmF0ZS1saW1pdCDsmrDtmowuIHNodXRkb3duIOykkeyXkOuPhCDrsJztlontlbQgdGltZW91dC/si6TtjKgg7KeE64uo7J20IOycoOyLpOuQmOyngCDslYrrj4TroZ0g7ZWc64ukLlxuICAvLyDsgqzsmqnsnpAgcmVkYWN0b3LsnZggdHlwZS1taXNtYXRjaCDsnITtl5jsnYQg7ZS87ZWY6riwIOychO2VtCBkZWZhdWx0IHJlZGFjdG9y66eMIOyggeyaqe2VnOuLpC5cbiAgZGlzcGF0Y2hJbnRlcm5hbERpYWdub3N0aWNFdmVudChcbiAgICBuYW1lOiBzdHJpbmcsXG4gICAgbGV2ZWw6IFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50UmVjb3JkW1wibGV2ZWxcIl0sXG4gICAgZGV0YWlsPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IHJlY29yZDogV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRSZWNvcmQgPSB7XG4gICAgICB0eXBlOiBcImV2ZW50XCIsXG4gICAgICB0aW1lc3RhbXA6IERhdGUubm93KCksXG4gICAgICBtb25vdG9uaWNUaW1lOiBwZXJmb3JtYW5jZS5ub3coKSxcbiAgICAgIHJ1bnRpbWVJZDogdGhpcy5ydW50aW1lTWV0YWRhdGEucnVudGltZUlkLFxuICAgICAgbm9kZUlkOiB0aGlzLnJ1bnRpbWVNZXRhZGF0YS5ub2RlSWQsXG4gICAgICBuYW1lLFxuICAgICAgbGV2ZWwsXG4gICAgICBkZXRhaWwsXG4gICAgfTtcblxuICAgIC8vIOynhOuLqCDsnbTrsqTtirjripQg7ZWt7IOBIGRlZmF1bHQgcmVkYWN0b3Lrp4wg7KCB7Jqp7ZW0IHNpbmvsl5Ag7KeB7KCRIOyghOuLrO2VnOuLpC5cbiAgICAvLyAo7IKs7Jqp7J6QIHJlZGFjdG9y6rCAIOynhOuLqCDsnbTrsqTtirjsnZggdHlwZeydhCDsnpjrqrsg67CU6r+UIOustO2VnCDro6jtlITrpbwg7J287Jy87YKk64qUIOydvOydhCDrp4nripTri6QuKVxuICAgIHRyeSB7XG4gICAgICBjb25zdCBzYW5pdGl6ZWQgPSBkZWZhdWx0U2Vuc2l0aXZlS2V5UmVkYWN0KHJlY29yZCk7XG4gICAgICBpZiAoc2FuaXRpemVkLnR5cGUgIT09IFwiZXZlbnRcIikgcmV0dXJuO1xuICAgICAgdGhpcy5kaXNwYXRjaFRvU2lua3Moc2FuaXRpemVkLCBmYWxzZSk7XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBzd2FsbG93XG4gICAgfVxuICB9XG5cbiAgcHJvdGVjdGVkIGJ1aWxkUmVjb3JkKGlucHV0OiBXZWJTb2NrZXRUZWxlbWV0cnlFdmVudElucHV0KTogV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRSZWNvcmQge1xuICAgIGxldCByZWNvcmQ6IFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50UmVjb3JkID0ge1xuICAgICAgdHlwZTogXCJldmVudFwiLFxuICAgICAgdGltZXN0YW1wOiBEYXRlLm5vdygpLFxuICAgICAgbW9ub3RvbmljVGltZTogcGVyZm9ybWFuY2Uubm93KCksXG4gICAgICBydW50aW1lSWQ6IHRoaXMucnVudGltZU1ldGFkYXRhLnJ1bnRpbWVJZCxcbiAgICAgIG5vZGVJZDogdGhpcy5ydW50aW1lTWV0YWRhdGEubm9kZUlkLFxuICAgICAgbmFtZTogaW5wdXQubmFtZSxcbiAgICAgIGxldmVsOiBpbnB1dC5sZXZlbCxcbiAgICAgIG5hbWVzcGFjZTogaW5wdXQubmFtZXNwYWNlLFxuICAgICAgY29ubmVjdGlvbklkOiBpbnB1dC5jb25uZWN0aW9uSWQsXG4gICAgICB1c2VySWQ6IGlucHV0LnVzZXJJZCxcbiAgICAgIGF0dHJpYnV0ZXM6IGlucHV0LmF0dHJpYnV0ZXMsXG4gICAgICBkZXRhaWw6IGlucHV0LmRldGFpbCxcbiAgICAgIHRyYWNlSWQ6IGlucHV0LnRyYWNlSWQsXG4gICAgICBzcGFuSWQ6IGlucHV0LnNwYW5JZCxcbiAgICAgIHBhcmVudFNwYW5JZDogaW5wdXQucGFyZW50U3BhbklkLFxuICAgICAgc2FtcGxlZDogaW5wdXQuc2FtcGxlZCxcbiAgICB9O1xuXG4gICAgaWYgKHRoaXMuY2FwdHVyZVBheWxvYWQgPT09IFwicHJldmlld1wiICYmIGlucHV0LnBheWxvYWQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgcmVjb3JkID0ge1xuICAgICAgICAuLi5yZWNvcmQsXG4gICAgICAgIHBheWxvYWRQcmV2aWV3OiB0cnVuY2F0ZVBheWxvYWRQcmV2aWV3KGlucHV0LnBheWxvYWQsIHRoaXMubWF4UGF5bG9hZFByZXZpZXdCeXRlcyksXG4gICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiByZWNvcmQ7XG4gIH1cblxuICBwcm90ZWN0ZWQgc2hvdWxkQnlwYXNzUmF0ZUxpbWl0KF9yZWNvcmQ6IFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50UmVjb3JkKTogYm9vbGVhbiB7XG4gICAgLy8gYWx3YXlzUmVjb3JkTGV2ZWxz7JeQIO2VtOuLue2VmOuKlCByZWNvcmTripQgc2FtcGxpbmfsnYQg6rGw7LmY7KeAIOyViuqzoCDrk6TslrTsmZTsnLzrqbAsXG4gICAgLy8g6riw7KG0IGNvbnRyb2xsZXIg64+Z7J6R7J2EIOuztOyhtO2VmOq4sCDsnITtlbQgdG9rZW4gYnVja2V064+EIHNraXDtlZzri6QuXG4gICAgcmV0dXJuIHRoaXMuY3VycmVudEVtaXRBbHdheXNSZWNvcmQ7XG4gIH1cblxuICBwcm90ZWN0ZWQgaXNDcml0aWNhbFJlY29yZChyZWNvcmQ6IFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50UmVjb3JkKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHJlY29yZC5sZXZlbCA9PT0gXCJ3YXJuXCIgfHwgcmVjb3JkLmxldmVsID09PSBcImVycm9yXCI7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2V0U2lnbmFsUmVkYWN0b3IoKTpcbiAgICB8ICgocmVjb3JkOiBXZWJTb2NrZXRUZWxlbWV0cnlFdmVudFJlY29yZCkgPT4gV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRSZWNvcmQgfCBudWxsKVxuICAgIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5zaWduYWxSZWRhY3RvcjtcbiAgfVxuXG4gIHByb3RlY3RlZCBnZXRTaWduYWxCZWZvcmVSZWNvcmQoKTpcbiAgICB8ICgocmVjb3JkOiBXZWJTb2NrZXRUZWxlbWV0cnlFdmVudFJlY29yZCkgPT4gV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRSZWNvcmQgfCBudWxsKVxuICAgIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5zaWduYWxCZWZvcmVSZWNvcmQ7XG4gIH1cbn1cblxuLy8gLS0gTWV0cmljUGlwZWxpbmUgLS1cblxuY2xhc3MgTWV0cmljUGlwZWxpbmUgZXh0ZW5kcyBUZWxlbWV0cnlQaXBlbGluZTxcbiAgV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljUmVjb3JkLFxuICBXZWJTb2NrZXRNZXRyaWNJbnB1dCxcbiAgV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljU2luayxcbiAgV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljU3RvcmUgfCB1bmRlZmluZWRcbj4ge1xuICByZWFkb25seSBzaWduYWwgPSBcIm1ldHJpY1wiIGFzIGNvbnN0O1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgc2lnbmFsUmVkYWN0b3I6IFdlYlNvY2tldFRlbGVtZXRyeU1ldHJpY1JlZGFjdG9yIHwgdW5kZWZpbmVkO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgc2lnbmFsQmVmb3JlUmVjb3JkOiBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNCZWZvcmVSZWNvcmQgfCB1bmRlZmluZWQ7XG4gIHByb3RlY3RlZCByZWFkb25seSBtZXRyaWNTb3VyY2VzOiBTZXQ8V2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljU291cmNlPiA9IG5ldyBTZXQoKTtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGNvbGxlY3Rpb25FbmFibGVkOiBib29sZWFuO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgc2FtcGxlSW50ZXJ2YWxNczogbnVtYmVyO1xuICBwcm90ZWN0ZWQgY29sbGVjdGlvbkludGVydmFsOiBSZXR1cm5UeXBlPHR5cGVvZiBzZXRJbnRlcnZhbD4gfCBudWxsID0gbnVsbDtcbiAgcHJvdGVjdGVkIHNuYXBzaG90UHJvdmlkZXI6ICgoKSA9PiBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNzU25hcHNob3QpIHwgdW5kZWZpbmVkO1xuXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnM6IFJlc29sdmVkTWV0cmljUGlwZWxpbmVPcHRpb25zLCBydW50aW1lTWV0YWRhdGE6IFJ1bnRpbWVNZXRhZGF0YSkge1xuICAgIHN1cGVyKFxuICAgICAgb3B0aW9ucy5zaW5rcyxcbiAgICAgIG9wdGlvbnMuc3RvcmUsXG4gICAgICBvcHRpb25zLm1heFJlY29yZHNQZXJTZWNvbmQsXG4gICAgICBvcHRpb25zLm1heEluRmxpZ2h0RW1pdHMsXG4gICAgICBvcHRpb25zLnNoYXJlZFJlZGFjdG9yLFxuICAgICAgb3B0aW9ucy5zaGFyZWRCZWZvcmVSZWNvcmQsXG4gICAgICBydW50aW1lTWV0YWRhdGEsXG4gICAgKTtcbiAgICB0aGlzLnNpZ25hbFJlZGFjdG9yID0gb3B0aW9ucy5zaWduYWxSZWRhY3RvcjtcbiAgICB0aGlzLnNpZ25hbEJlZm9yZVJlY29yZCA9IG9wdGlvbnMuc2lnbmFsQmVmb3JlUmVjb3JkO1xuICAgIHRoaXMuY29sbGVjdGlvbkVuYWJsZWQgPSBvcHRpb25zLmNvbGxlY3Rpb25FbmFibGVkO1xuICAgIHRoaXMuc2FtcGxlSW50ZXJ2YWxNcyA9IG9wdGlvbnMuc2FtcGxlSW50ZXJ2YWxNcztcblxuICAgIGlmICh0aGlzLmNvbGxlY3Rpb25FbmFibGVkICYmIHRoaXMuc2FtcGxlSW50ZXJ2YWxNcyA+IDApIHtcbiAgICAgIHRoaXMuY29sbGVjdGlvbkludGVydmFsID0gc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICAgICAgICB0aGlzLmNvbGxlY3RBbmRFbWl0KCk7XG4gICAgICB9LCB0aGlzLnNhbXBsZUludGVydmFsTXMpO1xuXG4gICAgICBpZiAoXG4gICAgICAgIHRoaXMuY29sbGVjdGlvbkludGVydmFsICYmXG4gICAgICAgIHR5cGVvZiB0aGlzLmNvbGxlY3Rpb25JbnRlcnZhbCA9PT0gXCJvYmplY3RcIiAmJlxuICAgICAgICBcInVucmVmXCIgaW4gdGhpcy5jb2xsZWN0aW9uSW50ZXJ2YWxcbiAgICAgICkge1xuICAgICAgICB0aGlzLmNvbGxlY3Rpb25JbnRlcnZhbC51bnJlZigpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGVtaXQoaW5wdXQ6IFdlYlNvY2tldE1ldHJpY0lucHV0KTogdm9pZCB7XG4gICAgdHJ5IHtcbiAgICAgIHRoaXMuZW1pdEludGVybmFsKGlucHV0KTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIHBpcGVsaW5lIGVtaXQgdGhyb3ctZnJlZSDsoJXssYVcbiAgICB9XG4gIH1cblxuICBwcm90ZWN0ZWQgYnVpbGRSZWNvcmQoaW5wdXQ6IFdlYlNvY2tldE1ldHJpY0lucHV0KTogV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljUmVjb3JkIHtcbiAgICByZXR1cm4ge1xuICAgICAgdHlwZTogXCJtZXRyaWNcIixcbiAgICAgIHRpbWVzdGFtcDogRGF0ZS5ub3coKSxcbiAgICAgIG1vbm90b25pY1RpbWU6IHBlcmZvcm1hbmNlLm5vdygpLFxuICAgICAgcnVudGltZUlkOiB0aGlzLnJ1bnRpbWVNZXRhZGF0YS5ydW50aW1lSWQsXG4gICAgICBub2RlSWQ6IHRoaXMucnVudGltZU1ldGFkYXRhLm5vZGVJZCxcbiAgICAgIG5hbWU6IGlucHV0Lm5hbWUsXG4gICAgICBraW5kOiBpbnB1dC5raW5kLFxuICAgICAgdmFsdWU6IGlucHV0LnZhbHVlLFxuICAgICAgdW5pdDogaW5wdXQudW5pdCxcbiAgICAgIHRhZ3M6IGlucHV0LnRhZ3MsXG4gICAgICBuYW1lc3BhY2U6IGlucHV0Lm5hbWVzcGFjZSxcbiAgICAgIGNvbm5lY3Rpb25JZDogaW5wdXQuY29ubmVjdGlvbklkLFxuICAgICAgdXNlcklkOiBpbnB1dC51c2VySWQsXG4gICAgICB0cmFjZUlkOiBpbnB1dC50cmFjZUlkLFxuICAgICAgc3BhbklkOiBpbnB1dC5zcGFuSWQsXG4gICAgICBwYXJlbnRTcGFuSWQ6IGlucHV0LnBhcmVudFNwYW5JZCxcbiAgICAgIHNhbXBsZWQ6IGlucHV0LnNhbXBsZWQsXG4gICAgICBzbmFwc2hvdDogaW5wdXQuc25hcHNob3QsXG4gICAgfTtcbiAgfVxuXG4gIHByb3RlY3RlZCBzaG91bGRCeXBhc3NSYXRlTGltaXQocmVjb3JkOiBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNSZWNvcmQpOiBib29sZWFuIHtcbiAgICBjb25zdCBvdXRjb21lID0gcmVjb3JkLnRhZ3M/Lm91dGNvbWU7XG4gICAgaWYgKG91dGNvbWUgPT09IFwiZmFpbGVkXCIgfHwgb3V0Y29tZSA9PT0gXCJyZWplY3RlZFwiIHx8IG91dGNvbWUgPT09IFwiZHJvcHBlZFwiKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICByZXR1cm4gKFxuICAgICAgcmVjb3JkLm5hbWUuZW5kc1dpdGgoXCIuZmFpbHVyZXNcIikgfHxcbiAgICAgIHJlY29yZC5uYW1lLmVuZHNXaXRoKFwiLmZhaWx1cmVcIikgfHxcbiAgICAgIHJlY29yZC5uYW1lLmVuZHNXaXRoKFwiLmRyb3BwZWRcIikgfHxcbiAgICAgIHJlY29yZC5uYW1lLmluY2x1ZGVzKFwiLmZhaWx1cmVzLlwiKSB8fFxuICAgICAgcmVjb3JkLm5hbWUuaW5jbHVkZXMoXCIuZHJvcHBlZC5cIilcbiAgICApO1xuICB9XG5cbiAgcHJvdGVjdGVkIGlzQ3JpdGljYWxSZWNvcmQocmVjb3JkOiBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNSZWNvcmQpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5zaG91bGRCeXBhc3NSYXRlTGltaXQocmVjb3JkKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBnZXRTaWduYWxSZWRhY3RvcigpOlxuICAgIHwgKChyZWNvcmQ6IFdlYlNvY2tldFRlbGVtZXRyeU1ldHJpY1JlY29yZCkgPT4gV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljUmVjb3JkIHwgbnVsbClcbiAgICB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuc2lnbmFsUmVkYWN0b3I7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2V0U2lnbmFsQmVmb3JlUmVjb3JkKCk6XG4gICAgfCAoKHJlY29yZDogV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljUmVjb3JkKSA9PiBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNSZWNvcmQgfCBudWxsKVxuICAgIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5zaWduYWxCZWZvcmVSZWNvcmQ7XG4gIH1cblxuICByZWdpc3Rlck1ldHJpY1NvdXJjZShzb3VyY2U6IFdlYlNvY2tldFRlbGVtZXRyeU1ldHJpY1NvdXJjZSk6ICgpID0+IHZvaWQge1xuICAgIHRoaXMubWV0cmljU291cmNlcy5hZGQoc291cmNlKTtcbiAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgdGhpcy5tZXRyaWNTb3VyY2VzLmRlbGV0ZShzb3VyY2UpO1xuICAgIH07XG4gIH1cblxuICBzZXRTbmFwc2hvdFByb3ZpZGVyKHByb3ZpZGVyOiAoKSA9PiBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNzU25hcHNob3QpOiB2b2lkIHtcbiAgICB0aGlzLnNuYXBzaG90UHJvdmlkZXIgPSBwcm92aWRlcjtcbiAgfVxuXG4gIGdldFNuYXBzaG90KCk6IFdlYlNvY2tldFRlbGVtZXRyeU1ldHJpY3NTbmFwc2hvdCB7XG4gICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgICBjb25zdCBiYXNlOiBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNzU25hcHNob3QgPSB7XG4gICAgICAuLi5FTVBUWV9NRVRSSUNTX1NOQVBTSE9ULFxuICAgICAgdGltZXN0YW1wOiBub3csXG4gICAgICBhY3RpdmVDb25uZWN0aW9uc0J5TmFtZXNwYWNlOiB7fSxcbiAgICAgIHRlbGVtZXRyeURyb3BwZWRSZWNvcmRzOiB0aGlzLmRyb3BwZWRDb3VudCxcbiAgICAgIHRlbGVtZXRyeVNpbmtGYWlsdXJlczogdGhpcy5zaW5rRmFpbHVyZUNvdW50LFxuICAgIH07XG5cbiAgICBmb3IgKGNvbnN0IHNvdXJjZSBvZiB0aGlzLm1ldHJpY1NvdXJjZXMpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHBhcnRpYWwgPSBzb3VyY2UuY29sbGVjdChub3cpO1xuICAgICAgICBiYXNlLmFjdGl2ZUNvbm5lY3Rpb25zICs9IHBhcnRpYWwuYWN0aXZlQ29ubmVjdGlvbnMgPz8gMDtcbiAgICAgICAgYmFzZS5yb29tQ291bnQgKz0gcGFydGlhbC5yb29tQ291bnQgPz8gMDtcbiAgICAgICAgYmFzZS5wZW5kaW5nSW5ib3VuZE1lc3NhZ2VzICs9IHBhcnRpYWwucGVuZGluZ0luYm91bmRNZXNzYWdlcyA/PyAwO1xuICAgICAgICBiYXNlLnBlbmRpbmdPdXRib3VuZE1lc3NhZ2VzICs9IHBhcnRpYWwucGVuZGluZ091dGJvdW5kTWVzc2FnZXMgPz8gMDtcbiAgICAgICAgYmFzZS5zb2NrZXRCdWZmZXJlZEJ5dGVzICs9IHBhcnRpYWwuc29ja2V0QnVmZmVyZWRCeXRlcyA/PyAwO1xuICAgICAgICBiYXNlLnBlbmRpbmdGYW5PdXRKb2JzICs9IHBhcnRpYWwucGVuZGluZ0Zhbk91dEpvYnMgPz8gMDtcbiAgICAgICAgYmFzZS5wZW5kaW5nRmFuT3V0VGFyZ2V0cyArPSBwYXJ0aWFsLnBlbmRpbmdGYW5PdXRUYXJnZXRzID8/IDA7XG4gICAgICAgIGlmIChwYXJ0aWFsLmFjdGl2ZUNvbm5lY3Rpb25zQnlOYW1lc3BhY2UpIHtcbiAgICAgICAgICBmb3IgKGNvbnN0IFtucywgY291bnRdIG9mIE9iamVjdC5lbnRyaWVzKHBhcnRpYWwuYWN0aXZlQ29ubmVjdGlvbnNCeU5hbWVzcGFjZSkpIHtcbiAgICAgICAgICAgIGJhc2UuYWN0aXZlQ29ubmVjdGlvbnNCeU5hbWVzcGFjZVtuc10gPVxuICAgICAgICAgICAgICAoYmFzZS5hY3RpdmVDb25uZWN0aW9uc0J5TmFtZXNwYWNlW25zXSA/PyAwKSArIGNvdW50O1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIC8vIG1ldHJpYyBzb3VyY2Ug7Iuk7Yyo64qUIOyZuOu2gOuhnCDsoITtjIzrkJjslrTshKAg7JWIIOuQqFxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBiYXNlO1xuICB9XG5cbiAgY29sbGVjdEFuZEVtaXQoKTogdm9pZCB7XG4gICAgdHJ5IHtcbiAgICAgIGlmICh0aGlzLnNodXRkb3duQ2FsbGVkKSByZXR1cm47XG4gICAgICBjb25zdCBzbmFwc2hvdCA9IHRoaXMuc25hcHNob3RQcm92aWRlcj8uKCkgPz8gdGhpcy5nZXRTbmFwc2hvdCgpO1xuICAgICAgY29uc3QgaW5wdXQ6IFdlYlNvY2tldE1ldHJpY0lucHV0ID0ge1xuICAgICAgICBuYW1lOiBcIndzLmNvbm5lY3Rpb25zLmFjdGl2ZVwiLFxuICAgICAgICBraW5kOiBcImdhdWdlXCIsXG4gICAgICAgIHZhbHVlOiBzbmFwc2hvdC5hY3RpdmVDb25uZWN0aW9ucyxcbiAgICAgICAgdW5pdDogXCIxXCIsXG4gICAgICAgIHNuYXBzaG90LFxuICAgICAgfTtcbiAgICAgIHRoaXMuZW1pdChpbnB1dCk7XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBtZXRyaWNzIOyImOynkSDsi6TtjKjripQg7Jm467aA66GcIOyghO2MjOuQmOyWtOyEoCDslYgg65CoXG4gICAgfVxuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgc2h1dGRvd24odGltZW91dE1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5jb2xsZWN0aW9uSW50ZXJ2YWwgIT09IG51bGwpIHtcbiAgICAgIGNsZWFySW50ZXJ2YWwodGhpcy5jb2xsZWN0aW9uSW50ZXJ2YWwpO1xuICAgICAgdGhpcy5jb2xsZWN0aW9uSW50ZXJ2YWwgPSBudWxsO1xuICAgIH1cbiAgICBhd2FpdCBzdXBlci5zaHV0ZG93bih0aW1lb3V0TXMpO1xuICB9XG59XG5cbi8vIC0tIFNwYW5QaXBlbGluZSAtLVxuXG5jbGFzcyBTcGFuUGlwZWxpbmUgZXh0ZW5kcyBUZWxlbWV0cnlQaXBlbGluZTxcbiAgV2ViU29ja2V0VGVsZW1ldHJ5U3BhblJlY29yZCxcbiAgV2ViU29ja2V0U3BhbklucHV0LFxuICBXZWJTb2NrZXRUZWxlbWV0cnlTcGFuU2luayxcbiAgV2ViU29ja2V0VGVsZW1ldHJ5U3BhblN0b3JlIHwgdW5kZWZpbmVkXG4+IHtcbiAgcmVhZG9ubHkgc2lnbmFsID0gXCJzcGFuXCIgYXMgY29uc3Q7XG4gIHByb3RlY3RlZCByZWFkb25seSBzaWduYWxSZWRhY3RvcjogV2ViU29ja2V0VGVsZW1ldHJ5U3BhblJlZGFjdG9yIHwgdW5kZWZpbmVkO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgc2lnbmFsQmVmb3JlUmVjb3JkOiBXZWJTb2NrZXRUZWxlbWV0cnlTcGFuQmVmb3JlUmVjb3JkIHwgdW5kZWZpbmVkO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgc2FtcGxpbmc6IHtcbiAgICBkZWZhdWx0UmF0ZTogbnVtYmVyO1xuICB9O1xuXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnM6IFJlc29sdmVkU3BhblBpcGVsaW5lT3B0aW9ucywgcnVudGltZU1ldGFkYXRhOiBSdW50aW1lTWV0YWRhdGEpIHtcbiAgICBzdXBlcihcbiAgICAgIG9wdGlvbnMuc2lua3MsXG4gICAgICBvcHRpb25zLnN0b3JlLFxuICAgICAgb3B0aW9ucy5tYXhSZWNvcmRzUGVyU2Vjb25kLFxuICAgICAgb3B0aW9ucy5tYXhJbkZsaWdodEVtaXRzLFxuICAgICAgb3B0aW9ucy5zaGFyZWRSZWRhY3RvcixcbiAgICAgIG9wdGlvbnMuc2hhcmVkQmVmb3JlUmVjb3JkLFxuICAgICAgcnVudGltZU1ldGFkYXRhLFxuICAgICk7XG4gICAgdGhpcy5zaWduYWxSZWRhY3RvciA9IG9wdGlvbnMuc2lnbmFsUmVkYWN0b3I7XG4gICAgdGhpcy5zaWduYWxCZWZvcmVSZWNvcmQgPSBvcHRpb25zLnNpZ25hbEJlZm9yZVJlY29yZDtcbiAgICB0aGlzLnNhbXBsaW5nID0geyBkZWZhdWx0UmF0ZTogb3B0aW9ucy5zYW1wbGluZy5kZWZhdWx0UmF0ZSB9O1xuICB9XG5cbiAgZW1pdChpbnB1dDogV2ViU29ja2V0U3BhbklucHV0KTogdm9pZCB7XG4gICAgdHJ5IHtcbiAgICAgIGlmICh0aGlzLnNodXRkb3duQ2FsbGVkKSByZXR1cm47XG5cbiAgICAgIC8vIHN0YXR1cyA9PT0gXCJlcnJvclwi64qUIHNhbXBsaW5nIOyasO2ajFxuICAgICAgaWYgKGlucHV0LnN0YXR1cyAhPT0gXCJlcnJvclwiKSB7XG4gICAgICAgIGNvbnN0IHJhdGUgPSB0aGlzLnNhbXBsaW5nLmRlZmF1bHRSYXRlO1xuICAgICAgICBpZiAocmF0ZSA8PSAwKSB7XG4gICAgICAgICAgdGhpcy5kcm9wcGVkQ291bnQgKz0gMTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHJhdGUgPCAxICYmIE1hdGgucmFuZG9tKCkgPj0gcmF0ZSkge1xuICAgICAgICAgIHRoaXMuZHJvcHBlZENvdW50ICs9IDE7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHRoaXMuZW1pdEludGVybmFsKGlucHV0KTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIHBpcGVsaW5lIGVtaXQgdGhyb3ctZnJlZSDsoJXssYVcbiAgICB9XG4gIH1cblxuICBwcm90ZWN0ZWQgYnVpbGRSZWNvcmQoaW5wdXQ6IFdlYlNvY2tldFNwYW5JbnB1dCk6IFdlYlNvY2tldFRlbGVtZXRyeVNwYW5SZWNvcmQge1xuICAgIHJldHVybiB7XG4gICAgICB0eXBlOiBcInNwYW5cIixcbiAgICAgIHRpbWVzdGFtcDogRGF0ZS5ub3coKSxcbiAgICAgIG1vbm90b25pY1RpbWU6IHBlcmZvcm1hbmNlLm5vdygpLFxuICAgICAgcnVudGltZUlkOiB0aGlzLnJ1bnRpbWVNZXRhZGF0YS5ydW50aW1lSWQsXG4gICAgICBub2RlSWQ6IHRoaXMucnVudGltZU1ldGFkYXRhLm5vZGVJZCxcbiAgICAgIG9wZXJhdGlvbk5hbWU6IGlucHV0Lm9wZXJhdGlvbk5hbWUsXG4gICAgICBraW5kOiBpbnB1dC5raW5kLFxuICAgICAgZHVyYXRpb25NczogaW5wdXQuZHVyYXRpb25NcyxcbiAgICAgIHN0YXR1czogaW5wdXQuc3RhdHVzLFxuICAgICAgbmFtZXNwYWNlOiBpbnB1dC5uYW1lc3BhY2UsXG4gICAgICBjb25uZWN0aW9uSWQ6IGlucHV0LmNvbm5lY3Rpb25JZCxcbiAgICAgIHVzZXJJZDogaW5wdXQudXNlcklkLFxuICAgICAgYXR0cmlidXRlczogaW5wdXQuYXR0cmlidXRlcyxcbiAgICAgIGVycm9yVHlwZTogaW5wdXQuZXJyb3JUeXBlLFxuICAgICAgdHJhY2VJZDogaW5wdXQudHJhY2VJZCxcbiAgICAgIHNwYW5JZDogaW5wdXQuc3BhbklkLFxuICAgICAgcGFyZW50U3BhbklkOiBpbnB1dC5wYXJlbnRTcGFuSWQsXG4gICAgICBzYW1wbGVkOiBpbnB1dC5zYW1wbGVkLFxuICAgICAgZXZlbnRzOiBpbnB1dC5ldmVudHMsXG4gICAgICBsaW5rczogaW5wdXQubGlua3MsXG4gICAgfTtcbiAgfVxuXG4gIHByb3RlY3RlZCBzaG91bGRCeXBhc3NSYXRlTGltaXQocmVjb3JkOiBXZWJTb2NrZXRUZWxlbWV0cnlTcGFuUmVjb3JkKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHJlY29yZC5zdGF0dXMgPT09IFwiZXJyb3JcIjtcbiAgfVxuXG4gIHByb3RlY3RlZCBpc0NyaXRpY2FsUmVjb3JkKHJlY29yZDogV2ViU29ja2V0VGVsZW1ldHJ5U3BhblJlY29yZCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiByZWNvcmQuc3RhdHVzID09PSBcImVycm9yXCI7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2V0U2lnbmFsUmVkYWN0b3IoKTpcbiAgICB8ICgocmVjb3JkOiBXZWJTb2NrZXRUZWxlbWV0cnlTcGFuUmVjb3JkKSA9PiBXZWJTb2NrZXRUZWxlbWV0cnlTcGFuUmVjb3JkIHwgbnVsbClcbiAgICB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuc2lnbmFsUmVkYWN0b3I7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2V0U2lnbmFsQmVmb3JlUmVjb3JkKCk6XG4gICAgfCAoKHJlY29yZDogV2ViU29ja2V0VGVsZW1ldHJ5U3BhblJlY29yZCkgPT4gV2ViU29ja2V0VGVsZW1ldHJ5U3BhblJlY29yZCB8IG51bGwpXG4gICAgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLnNpZ25hbEJlZm9yZVJlY29yZDtcbiAgfVxufVxuXG4vLyAtLSBXZWJTb2NrZXRUZWxlbWV0cnlDb250cm9sbGVySW1wbCAtLVxuXG5leHBvcnQgY2xhc3MgV2ViU29ja2V0VGVsZW1ldHJ5Q29udHJvbGxlckltcGwgaW1wbGVtZW50cyBXZWJTb2NrZXRUZWxlbWV0cnlDb250cm9sbGVyIHtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGV2ZW50czogRXZlbnRQaXBlbGluZTtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IG1ldHJpY3M6IE1ldHJpY1BpcGVsaW5lO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgc3BhbnM6IFNwYW5QaXBlbGluZTtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHJ1bnRpbWVJZDogc3RyaW5nO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgbm9kZUlkOiBzdHJpbmc7XG4gIHByb3RlY3RlZCByZWFkb25seSB0cmFjZU9wdGlvbnM6IFdlYlNvY2tldFRlbGVtZXRyeVRyYWNlT3B0aW9ucztcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHNodXRkb3duVGltZW91dE1zOiBudW1iZXI7XG4gIHByb3RlY3RlZCBzaHV0ZG93bkNhbGxlZCA9IGZhbHNlO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIGV2ZW50czogRXZlbnRQaXBlbGluZSxcbiAgICBtZXRyaWNzOiBNZXRyaWNQaXBlbGluZSxcbiAgICBzcGFuczogU3BhblBpcGVsaW5lLFxuICAgIHRyYWNlT3B0aW9uczogV2ViU29ja2V0VGVsZW1ldHJ5VHJhY2VPcHRpb25zLFxuICAgIHJ1bnRpbWVNZXRhZGF0YTogUnVudGltZU1ldGFkYXRhLFxuICAgIHNodXRkb3duVGltZW91dE1zOiBudW1iZXIsXG4gICkge1xuICAgIHRoaXMuZXZlbnRzID0gZXZlbnRzO1xuICAgIHRoaXMubWV0cmljcyA9IG1ldHJpY3M7XG4gICAgdGhpcy5zcGFucyA9IHNwYW5zO1xuICAgIHRoaXMudHJhY2VPcHRpb25zID0gdHJhY2VPcHRpb25zO1xuICAgIHRoaXMucnVudGltZUlkID0gcnVudGltZU1ldGFkYXRhLnJ1bnRpbWVJZDtcbiAgICB0aGlzLm5vZGVJZCA9IHJ1bnRpbWVNZXRhZGF0YS5ub2RlSWQ7XG4gICAgdGhpcy5zaHV0ZG93blRpbWVvdXRNcyA9IHNodXRkb3duVGltZW91dE1zO1xuXG4gICAgLy8g66qo65OgIHBpcGVsaW5lIOynhOuLqCDsnbTrsqTtirjripQgZXZlbnRzIHBpcGVsaW5lIOqyveuhnOuhnCDrnbzsmrDtjIXtlZzri6QuXG4gICAgY29uc3QgcmVwb3J0ZXI6IEludGVybmFsRXZlbnRSZXBvcnRlciA9IChuYW1lLCBsZXZlbCwgZGV0YWlsKSA9PiB7XG4gICAgICB0aGlzLmV2ZW50cy5kaXNwYXRjaEludGVybmFsRGlhZ25vc3RpY0V2ZW50KG5hbWUsIGxldmVsLCBkZXRhaWwpO1xuICAgIH07XG4gICAgdGhpcy5ldmVudHMuc2V0SW50ZXJuYWxFdmVudFJlcG9ydGVyKHJlcG9ydGVyKTtcbiAgICB0aGlzLm1ldHJpY3Muc2V0SW50ZXJuYWxFdmVudFJlcG9ydGVyKHJlcG9ydGVyKTtcbiAgICB0aGlzLnNwYW5zLnNldEludGVybmFsRXZlbnRSZXBvcnRlcihyZXBvcnRlcik7XG4gICAgdGhpcy5tZXRyaWNzLnNldFNuYXBzaG90UHJvdmlkZXIoKCkgPT4gdGhpcy5nZXRNZXRyaWNzU25hcHNob3QoKSk7XG4gIH1cblxuICBlbWl0KGlucHV0OiBXZWJTb2NrZXRUZWxlbWV0cnlFdmVudElucHV0KTogdm9pZCB7XG4gICAgdHJ5IHtcbiAgICAgIGlmICh0aGlzLnNodXRkb3duQ2FsbGVkKSByZXR1cm47XG4gICAgICB0aGlzLmV2ZW50cy5lbWl0KGlucHV0KTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIGNvbnRyb2xsZXIgdGhyb3ctZnJlZVxuICAgIH1cbiAgfVxuXG4gIHJlY29yZE1ldHJpYyhpbnB1dDogV2ViU29ja2V0TWV0cmljSW5wdXQpOiB2b2lkIHtcbiAgICB0cnkge1xuICAgICAgaWYgKHRoaXMuc2h1dGRvd25DYWxsZWQpIHJldHVybjtcbiAgICAgIHRoaXMubWV0cmljcy5lbWl0KGlucHV0KTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIGNvbnRyb2xsZXIgdGhyb3ctZnJlZVxuICAgIH1cbiAgfVxuXG4gIHJlY29yZFNwYW4oaW5wdXQ6IFdlYlNvY2tldFNwYW5JbnB1dCk6IHZvaWQge1xuICAgIHRyeSB7XG4gICAgICBpZiAodGhpcy5zaHV0ZG93bkNhbGxlZCkgcmV0dXJuO1xuICAgICAgdGhpcy5zcGFucy5lbWl0KGlucHV0KTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIGNvbnRyb2xsZXIgdGhyb3ctZnJlZVxuICAgIH1cbiAgfVxuXG4gIGdldE1ldHJpY3NTbmFwc2hvdCgpOiBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNzU25hcHNob3Qge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBiYXNlID0gdGhpcy5tZXRyaWNzLmdldFNuYXBzaG90KCk7XG4gICAgICBiYXNlLnRlbGVtZXRyeURyb3BwZWRSZWNvcmRzID1cbiAgICAgICAgdGhpcy5ldmVudHMuZHJvcHBlZENvdW50ICsgdGhpcy5tZXRyaWNzLmRyb3BwZWRDb3VudCArIHRoaXMuc3BhbnMuZHJvcHBlZENvdW50O1xuICAgICAgYmFzZS50ZWxlbWV0cnlTaW5rRmFpbHVyZXMgPVxuICAgICAgICB0aGlzLmV2ZW50cy5zaW5rRmFpbHVyZUNvdW50ICsgdGhpcy5tZXRyaWNzLnNpbmtGYWlsdXJlQ291bnQgKyB0aGlzLnNwYW5zLnNpbmtGYWlsdXJlQ291bnQ7XG4gICAgICByZXR1cm4gYmFzZTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiB7IC4uLkVNUFRZX01FVFJJQ1NfU05BUFNIT1QsIHRpbWVzdGFtcDogRGF0ZS5ub3coKSB9O1xuICAgIH1cbiAgfVxuXG4gIGdldEV2ZW50U3RvcmUoKTogV2ViU29ja2V0VGVsZW1ldHJ5RXZlbnRTdG9yZSB8IHVuZGVmaW5lZCB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiB0aGlzLmV2ZW50cy5zdG9yZTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgZ2V0TWV0cmljU3RvcmUoKTogV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljU3RvcmUgfCB1bmRlZmluZWQge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gdGhpcy5tZXRyaWNzLnN0b3JlO1xuICAgIH0gY2F0Y2gge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gIH1cblxuICBnZXRTcGFuU3RvcmUoKTogV2ViU29ja2V0VGVsZW1ldHJ5U3BhblN0b3JlIHwgdW5kZWZpbmVkIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIHRoaXMuc3BhbnMuc3RvcmU7XG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgfVxuXG4gIHJlZ2lzdGVyTWV0cmljU291cmNlKHNvdXJjZTogV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljU291cmNlKTogKCkgPT4gdm9pZCB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiB0aGlzLm1ldHJpY3MucmVnaXN0ZXJNZXRyaWNTb3VyY2Uoc291cmNlKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBub29wVW5zdWJzY3JpYmU7XG4gICAgfVxuICB9XG5cbiAgY3JlYXRlQ29ubmVjdGlvbkNvbnRleHQocmVxdWVzdD86IHtcbiAgICBoZWFkZXJzPzogUmVhZG9ubHk8UmVjb3JkPHN0cmluZywgc3RyaW5nIHwgc3RyaW5nW10gfCB1bmRlZmluZWQ+PjtcbiAgfSk6IFdlYlNvY2tldFRlbGVtZXRyeUNvbm5lY3Rpb25Db250ZXh0IHtcbiAgICB0cnkge1xuICAgICAgaWYgKHRoaXMudHJhY2VPcHRpb25zLmV4dHJhY3RUcmFjZVBhcmVudCAmJiByZXF1ZXN0Py5oZWFkZXJzKSB7XG4gICAgICAgIGNvbnN0IHRyYWNlcGFyZW50SGVhZGVyID0gcmVxdWVzdC5oZWFkZXJzW1widHJhY2VwYXJlbnRcIl07XG4gICAgICAgIGNvbnN0IHRyYWNlcGFyZW50VmFsdWUgPSBBcnJheS5pc0FycmF5KHRyYWNlcGFyZW50SGVhZGVyKVxuICAgICAgICAgID8gdHJhY2VwYXJlbnRIZWFkZXJbMF1cbiAgICAgICAgICA6IHRyYWNlcGFyZW50SGVhZGVyO1xuICAgICAgICBpZiAodHJhY2VwYXJlbnRWYWx1ZSkge1xuICAgICAgICAgIGNvbnN0IHBhcnNlZCA9IHBhcnNlVHJhY2VQYXJlbnQodHJhY2VwYXJlbnRWYWx1ZSk7XG4gICAgICAgICAgaWYgKHBhcnNlZCkge1xuICAgICAgICAgICAgY29uc3QgY29udGV4dDogV2ViU29ja2V0VGVsZW1ldHJ5Q29ubmVjdGlvbkNvbnRleHQgPSB7XG4gICAgICAgICAgICAgIHRyYWNlSWQ6IHBhcnNlZC50cmFjZUlkLFxuICAgICAgICAgICAgICBwYXJlbnRTcGFuSWQ6IHBhcnNlZC5wYXJlbnRJZCxcbiAgICAgICAgICAgICAgc2FtcGxlZDogcGFyc2VkLnNhbXBsZWQsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgaWYgKHRoaXMudHJhY2VPcHRpb25zLmdlbmVyYXRlQ29ubmVjdGlvblRyYWNlKSB7XG4gICAgICAgICAgICAgIGNvbnRleHQuc3BhbklkID0gZ2VuZXJhdGVTcGFuSWQoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB7IC4uLmNvbnRleHQgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKCF0aGlzLnRyYWNlT3B0aW9ucy5nZW5lcmF0ZUNvbm5lY3Rpb25UcmFjZSkge1xuICAgICAgICByZXR1cm4ge307XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB7IHRyYWNlSWQ6IGdlbmVyYXRlVHJhY2VJZCgpLCBzcGFuSWQ6IGdlbmVyYXRlU3BhbklkKCkgfTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiB7fTtcbiAgICB9XG4gIH1cblxuICBnZXRUcmFjZU9wdGlvbnMoKTogV2ViU29ja2V0VGVsZW1ldHJ5VHJhY2VPcHRpb25zIHtcbiAgICByZXR1cm4geyAuLi50aGlzLnRyYWNlT3B0aW9ucyB9O1xuICB9XG5cbiAgYXN5bmMgc2h1dGRvd24ob3B0aW9ucz86IHsgdGltZW91dE1zPzogbnVtYmVyIH0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5zaHV0ZG93bkNhbGxlZCkgcmV0dXJuO1xuICAgIHRoaXMuc2h1dGRvd25DYWxsZWQgPSB0cnVlO1xuXG4gICAgY29uc3QgdGltZW91dE1zID0gb3B0aW9ucz8udGltZW91dE1zID8/IHRoaXMuc2h1dGRvd25UaW1lb3V0TXM7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChbXG4gICAgICAgIHRoaXMuZXZlbnRzLnNodXRkb3duKHRpbWVvdXRNcyksXG4gICAgICAgIHRoaXMubWV0cmljcy5zaHV0ZG93bih0aW1lb3V0TXMpLFxuICAgICAgICB0aGlzLnNwYW5zLnNodXRkb3duKHRpbWVvdXRNcyksXG4gICAgICBdKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIGNvbnRyb2xsZXIgc2h1dGRvd27snYAgdGhyb3ctZnJlZVxuICAgIH1cbiAgfVxufVxuXG4vLyAtLSBGYWN0b3J5IC0tXG5cbmZ1bmN0aW9uIGJ1aWxkQ29udHJvbGxlcihcbiAgb3B0aW9uczogV2ViU29ja2V0VGVsZW1ldHJ5T3B0aW9ucyxcbiAgcnVudGltZU1ldGFkYXRhOiBSdW50aW1lTWV0YWRhdGEsXG4pOiBXZWJTb2NrZXRUZWxlbWV0cnlDb250cm9sbGVyIHtcbiAgY29uc3QgZGVmYXVsdHMgPSBvcHRpb25zLmRlZmF1bHRzID8/IHt9O1xuICBjb25zdCBldmVudHNPcHQgPSBvcHRpb25zLmV2ZW50cyA/PyB7fTtcbiAgY29uc3QgbWV0cmljc09wdCA9IG9wdGlvbnMubWV0cmljcyA/PyB7fTtcbiAgY29uc3Qgc3BhbnNPcHQgPSBvcHRpb25zLnNwYW5zID8/IHt9O1xuXG4gIGNvbnN0IGRlZmF1bHRzTWF4UmVjb3Jkc1BlclNlY29uZCA9XG4gICAgZGVmYXVsdHMubWF4UmVjb3Jkc1BlclNlY29uZCA/PyBERUZBVUxUX01BWF9SRUNPUkRTX1BFUl9TRUNPTkQ7XG5cbiAgLy8g7Iug7Zi467OEIHJlZGFjdG9yIC8gYmVmb3JlUmVjb3JkIO2VtOyEnS5cbiAgLy8gbnVsbOydtOuptCBzaGFyZWRSZWRhY3RvcuulvCB1bmRlZmluZWTroZwg642u7Ja07I2oIHN0ZXAgMiDsnpDssrTrpbwgc2tpcO2VnOuLpC5cbiAgY29uc3QgZXZlbnRzU2hhcmVkUmVkYWN0b3IgPSBldmVudHNPcHQucmVkYWN0b3IgPT09IG51bGwgPyB1bmRlZmluZWQgOiBkZWZhdWx0cy5yZWRhY3RvcjtcbiAgY29uc3QgZXZlbnRzU2lnbmFsUmVkYWN0b3IgPVxuICAgIHR5cGVvZiBldmVudHNPcHQucmVkYWN0b3IgPT09IFwiZnVuY3Rpb25cIiA/IGV2ZW50c09wdC5yZWRhY3RvciA6IHVuZGVmaW5lZDtcbiAgY29uc3QgZXZlbnRzU2hhcmVkQmVmb3JlUmVjb3JkID1cbiAgICBldmVudHNPcHQuYmVmb3JlUmVjb3JkID09PSBudWxsID8gdW5kZWZpbmVkIDogZGVmYXVsdHMuYmVmb3JlUmVjb3JkO1xuICBjb25zdCBldmVudHNTaWduYWxCZWZvcmVSZWNvcmQgPVxuICAgIHR5cGVvZiBldmVudHNPcHQuYmVmb3JlUmVjb3JkID09PSBcImZ1bmN0aW9uXCIgPyBldmVudHNPcHQuYmVmb3JlUmVjb3JkIDogdW5kZWZpbmVkO1xuXG4gIGNvbnN0IG1ldHJpY3NTaGFyZWRSZWRhY3RvciA9IG1ldHJpY3NPcHQucmVkYWN0b3IgPT09IG51bGwgPyB1bmRlZmluZWQgOiBkZWZhdWx0cy5yZWRhY3RvcjtcbiAgY29uc3QgbWV0cmljc1NpZ25hbFJlZGFjdG9yID1cbiAgICB0eXBlb2YgbWV0cmljc09wdC5yZWRhY3RvciA9PT0gXCJmdW5jdGlvblwiID8gbWV0cmljc09wdC5yZWRhY3RvciA6IHVuZGVmaW5lZDtcbiAgY29uc3QgbWV0cmljc1NoYXJlZEJlZm9yZVJlY29yZCA9XG4gICAgbWV0cmljc09wdC5iZWZvcmVSZWNvcmQgPT09IG51bGwgPyB1bmRlZmluZWQgOiBkZWZhdWx0cy5iZWZvcmVSZWNvcmQ7XG4gIGNvbnN0IG1ldHJpY3NTaWduYWxCZWZvcmVSZWNvcmQgPVxuICAgIHR5cGVvZiBtZXRyaWNzT3B0LmJlZm9yZVJlY29yZCA9PT0gXCJmdW5jdGlvblwiID8gbWV0cmljc09wdC5iZWZvcmVSZWNvcmQgOiB1bmRlZmluZWQ7XG5cbiAgY29uc3Qgc3BhbnNTaGFyZWRSZWRhY3RvciA9IHNwYW5zT3B0LnJlZGFjdG9yID09PSBudWxsID8gdW5kZWZpbmVkIDogZGVmYXVsdHMucmVkYWN0b3I7XG4gIGNvbnN0IHNwYW5zU2lnbmFsUmVkYWN0b3IgPVxuICAgIHR5cGVvZiBzcGFuc09wdC5yZWRhY3RvciA9PT0gXCJmdW5jdGlvblwiID8gc3BhbnNPcHQucmVkYWN0b3IgOiB1bmRlZmluZWQ7XG4gIGNvbnN0IHNwYW5zU2hhcmVkQmVmb3JlUmVjb3JkID1cbiAgICBzcGFuc09wdC5iZWZvcmVSZWNvcmQgPT09IG51bGwgPyB1bmRlZmluZWQgOiBkZWZhdWx0cy5iZWZvcmVSZWNvcmQ7XG4gIGNvbnN0IHNwYW5zU2lnbmFsQmVmb3JlUmVjb3JkID1cbiAgICB0eXBlb2Ygc3BhbnNPcHQuYmVmb3JlUmVjb3JkID09PSBcImZ1bmN0aW9uXCIgPyBzcGFuc09wdC5iZWZvcmVSZWNvcmQgOiB1bmRlZmluZWQ7XG5cbiAgLy8gZXZlbnRzXG4gIGNvbnN0IGV2ZW50U2lua3M6IFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50U2lua1tdID0gZXZlbnRzT3B0LnNpbmtzID8gWy4uLmV2ZW50c09wdC5zaW5rc10gOiBbXTtcbiAgbGV0IGV2ZW50U3RvcmU6IFdlYlNvY2tldFRlbGVtZXRyeUV2ZW50U3RvcmUgfCB1bmRlZmluZWQgPSBldmVudHNPcHQuc3RvcmU7XG4gIGlmIChldmVudFNpbmtzLmxlbmd0aCA9PT0gMCAmJiBldmVudFN0b3JlID09PSB1bmRlZmluZWQpIHtcbiAgICBldmVudFN0b3JlID0gbmV3IEluTWVtb3J5RXZlbnRTdG9yZSh7XG4gICAgICBtYXhSZWNvcmRzOiBldmVudHNPcHQubWF4UmVjb3JkcyA/PyBkZWZhdWx0cy5tYXhSZWNvcmRzLFxuICAgICAgbWF4Qnl0ZXM6IGV2ZW50c09wdC5tYXhCeXRlcyA/PyBkZWZhdWx0cy5tYXhCeXRlcyxcbiAgICB9KTtcbiAgICBldmVudFNpbmtzLnB1c2goZXZlbnRTdG9yZS5zaW5rKTtcbiAgfSBlbHNlIGlmIChldmVudFN0b3JlICE9PSB1bmRlZmluZWQgJiYgIWV2ZW50U2lua3MuaW5jbHVkZXMoZXZlbnRTdG9yZS5zaW5rKSkge1xuICAgIGV2ZW50U2lua3MucHVzaChldmVudFN0b3JlLnNpbmspO1xuICB9XG5cbiAgY29uc3QgZXZlbnRzUmVzb2x2ZWQ6IFJlc29sdmVkRXZlbnRQaXBlbGluZU9wdGlvbnMgPSB7XG4gICAgc2lua3M6IGV2ZW50U2lua3MsXG4gICAgc3RvcmU6IGV2ZW50U3RvcmUsXG4gICAgbWF4UmVjb3Jkc1BlclNlY29uZDogZXZlbnRzT3B0LnNhbXBsaW5nPy5tYXhSZWNvcmRzUGVyU2Vjb25kID8/IGRlZmF1bHRzTWF4UmVjb3Jkc1BlclNlY29uZCxcbiAgICBtYXhJbkZsaWdodEVtaXRzOiBldmVudHNPcHQubWF4SW5GbGlnaHRFbWl0cyA/PyBERUZBVUxUX01BWF9JTl9GTElHSFRfRU1JVFNfUEVSX1NJTkssXG4gICAgc2hhcmVkUmVkYWN0b3I6IGV2ZW50c1NoYXJlZFJlZGFjdG9yLFxuICAgIHNpZ25hbFJlZGFjdG9yOiBldmVudHNTaWduYWxSZWRhY3RvcixcbiAgICBzaGFyZWRCZWZvcmVSZWNvcmQ6IGV2ZW50c1NoYXJlZEJlZm9yZVJlY29yZCxcbiAgICBzaWduYWxCZWZvcmVSZWNvcmQ6IGV2ZW50c1NpZ25hbEJlZm9yZVJlY29yZCxcbiAgICBzYW1wbGluZzoge1xuICAgICAgZGVmYXVsdFJhdGU6IGV2ZW50c09wdC5zYW1wbGluZz8uZGVmYXVsdFJhdGUgPz8gREVGQVVMVF9FVkVOVF9TQU1QTElOR19ERUZBVUxUX1JBVEUsXG4gICAgICByYXRlQnlFdmVudDogZXZlbnRzT3B0LnNhbXBsaW5nPy5yYXRlQnlFdmVudCA/PyB7fSxcbiAgICAgIGFsd2F5c1JlY29yZExldmVsczogZXZlbnRzT3B0LnNhbXBsaW5nPy5hbHdheXNSZWNvcmRMZXZlbHMgPz8gW1xuICAgICAgICAuLi5ERUZBVUxUX0VWRU5UX0FMV0FZU19SRUNPUkRfTEVWRUxTLFxuICAgICAgXSxcbiAgICB9LFxuICAgIGNhcHR1cmVQYXlsb2FkOiBldmVudHNPcHQuY2FwdHVyZVBheWxvYWQgPz8gREVGQVVMVF9FVkVOVF9DQVBUVVJFX1BBWUxPQUQsXG4gICAgbWF4UGF5bG9hZFByZXZpZXdCeXRlczpcbiAgICAgIGV2ZW50c09wdC5tYXhQYXlsb2FkUHJldmlld0J5dGVzID8/IERFRkFVTFRfRVZFTlRfTUFYX1BBWUxPQURfUFJFVklFV19CWVRFUyxcbiAgfTtcblxuICAvLyBtZXRyaWNzXG4gIGNvbnN0IG1ldHJpY1NpbmtzOiBXZWJTb2NrZXRUZWxlbWV0cnlNZXRyaWNTaW5rW10gPSBtZXRyaWNzT3B0LnNpbmtzID8gWy4uLm1ldHJpY3NPcHQuc2lua3NdIDogW107XG4gIGxldCBtZXRyaWNTdG9yZTogV2ViU29ja2V0VGVsZW1ldHJ5TWV0cmljU3RvcmUgfCB1bmRlZmluZWQgPSBtZXRyaWNzT3B0LnN0b3JlO1xuICBpZiAobWV0cmljU2lua3MubGVuZ3RoID09PSAwICYmIG1ldHJpY1N0b3JlID09PSB1bmRlZmluZWQpIHtcbiAgICBtZXRyaWNTdG9yZSA9IG5ldyBJbk1lbW9yeU1ldHJpY1N0b3JlKHtcbiAgICAgIG1heFJlY29yZHM6IG1ldHJpY3NPcHQubWF4UmVjb3JkcyA/PyBkZWZhdWx0cy5tYXhSZWNvcmRzLFxuICAgICAgbWF4Qnl0ZXM6IG1ldHJpY3NPcHQubWF4Qnl0ZXMgPz8gZGVmYXVsdHMubWF4Qnl0ZXMsXG4gICAgfSk7XG4gICAgbWV0cmljU2lua3MucHVzaChtZXRyaWNTdG9yZS5zaW5rKTtcbiAgfSBlbHNlIGlmIChtZXRyaWNTdG9yZSAhPT0gdW5kZWZpbmVkICYmICFtZXRyaWNTaW5rcy5pbmNsdWRlcyhtZXRyaWNTdG9yZS5zaW5rKSkge1xuICAgIG1ldHJpY1NpbmtzLnB1c2gobWV0cmljU3RvcmUuc2luayk7XG4gIH1cblxuICBjb25zdCBtZXRyaWNzUmVzb2x2ZWQ6IFJlc29sdmVkTWV0cmljUGlwZWxpbmVPcHRpb25zID0ge1xuICAgIHNpbmtzOiBtZXRyaWNTaW5rcyxcbiAgICBzdG9yZTogbWV0cmljU3RvcmUsXG4gICAgbWF4UmVjb3Jkc1BlclNlY29uZDogbWV0cmljc09wdC5zYW1wbGluZz8ubWF4UmVjb3Jkc1BlclNlY29uZCA/PyBkZWZhdWx0c01heFJlY29yZHNQZXJTZWNvbmQsXG4gICAgbWF4SW5GbGlnaHRFbWl0czogbWV0cmljc09wdC5tYXhJbkZsaWdodEVtaXRzID8/IERFRkFVTFRfTUFYX0lOX0ZMSUdIVF9FTUlUU19QRVJfU0lOSyxcbiAgICBzaGFyZWRSZWRhY3RvcjogbWV0cmljc1NoYXJlZFJlZGFjdG9yLFxuICAgIHNpZ25hbFJlZGFjdG9yOiBtZXRyaWNzU2lnbmFsUmVkYWN0b3IsXG4gICAgc2hhcmVkQmVmb3JlUmVjb3JkOiBtZXRyaWNzU2hhcmVkQmVmb3JlUmVjb3JkLFxuICAgIHNpZ25hbEJlZm9yZVJlY29yZDogbWV0cmljc1NpZ25hbEJlZm9yZVJlY29yZCxcbiAgICBjb2xsZWN0aW9uRW5hYmxlZDogbWV0cmljc09wdC5jb2xsZWN0aW9uRW5hYmxlZCA/PyBERUZBVUxUX01FVFJJQ19DT0xMRUNUSU9OX0VOQUJMRUQsXG4gICAgc2FtcGxlSW50ZXJ2YWxNczogbWV0cmljc09wdC5zYW1wbGVJbnRlcnZhbE1zID8/IERFRkFVTFRfTUVUUklDX1NBTVBMRV9JTlRFUlZBTF9NUyxcbiAgfTtcblxuICAvLyBzcGFuc1xuICBjb25zdCBzcGFuU2lua3M6IFdlYlNvY2tldFRlbGVtZXRyeVNwYW5TaW5rW10gPSBzcGFuc09wdC5zaW5rcyA/IFsuLi5zcGFuc09wdC5zaW5rc10gOiBbXTtcbiAgbGV0IHNwYW5TdG9yZTogV2ViU29ja2V0VGVsZW1ldHJ5U3BhblN0b3JlIHwgdW5kZWZpbmVkID0gc3BhbnNPcHQuc3RvcmU7XG4gIGlmIChzcGFuU2lua3MubGVuZ3RoID09PSAwICYmIHNwYW5TdG9yZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgc3BhblN0b3JlID0gbmV3IEluTWVtb3J5U3BhblN0b3JlKHtcbiAgICAgIG1heFJlY29yZHM6IHNwYW5zT3B0Lm1heFJlY29yZHMgPz8gZGVmYXVsdHMubWF4UmVjb3JkcyxcbiAgICAgIG1heEJ5dGVzOiBzcGFuc09wdC5tYXhCeXRlcyA/PyBkZWZhdWx0cy5tYXhCeXRlcyxcbiAgICB9KTtcbiAgICBzcGFuU2lua3MucHVzaChzcGFuU3RvcmUuc2luayk7XG4gIH0gZWxzZSBpZiAoc3BhblN0b3JlICE9PSB1bmRlZmluZWQgJiYgIXNwYW5TaW5rcy5pbmNsdWRlcyhzcGFuU3RvcmUuc2luaykpIHtcbiAgICBzcGFuU2lua3MucHVzaChzcGFuU3RvcmUuc2luayk7XG4gIH1cblxuICBjb25zdCBzcGFuc1Jlc29sdmVkOiBSZXNvbHZlZFNwYW5QaXBlbGluZU9wdGlvbnMgPSB7XG4gICAgc2lua3M6IHNwYW5TaW5rcyxcbiAgICBzdG9yZTogc3BhblN0b3JlLFxuICAgIG1heFJlY29yZHNQZXJTZWNvbmQ6IHNwYW5zT3B0LnNhbXBsaW5nPy5tYXhSZWNvcmRzUGVyU2Vjb25kID8/IGRlZmF1bHRzTWF4UmVjb3Jkc1BlclNlY29uZCxcbiAgICBtYXhJbkZsaWdodEVtaXRzOiBzcGFuc09wdC5tYXhJbkZsaWdodEVtaXRzID8/IERFRkFVTFRfTUFYX0lOX0ZMSUdIVF9FTUlUU19QRVJfU0lOSyxcbiAgICBzaGFyZWRSZWRhY3Rvcjogc3BhbnNTaGFyZWRSZWRhY3RvcixcbiAgICBzaWduYWxSZWRhY3Rvcjogc3BhbnNTaWduYWxSZWRhY3RvcixcbiAgICBzaGFyZWRCZWZvcmVSZWNvcmQ6IHNwYW5zU2hhcmVkQmVmb3JlUmVjb3JkLFxuICAgIHNpZ25hbEJlZm9yZVJlY29yZDogc3BhbnNTaWduYWxCZWZvcmVSZWNvcmQsXG4gICAgc2FtcGxpbmc6IHtcbiAgICAgIGRlZmF1bHRSYXRlOiBzcGFuc09wdC5zYW1wbGluZz8uZGVmYXVsdFJhdGUgPz8gREVGQVVMVF9TUEFOX1NBTVBMSU5HX0RFRkFVTFRfUkFURSxcbiAgICB9LFxuICB9O1xuXG4gIGNvbnN0IGV2ZW50UGlwZWxpbmUgPSBuZXcgRXZlbnRQaXBlbGluZShldmVudHNSZXNvbHZlZCwgcnVudGltZU1ldGFkYXRhKTtcbiAgY29uc3QgbWV0cmljUGlwZWxpbmUgPSBuZXcgTWV0cmljUGlwZWxpbmUobWV0cmljc1Jlc29sdmVkLCBydW50aW1lTWV0YWRhdGEpO1xuICBjb25zdCBzcGFuUGlwZWxpbmUgPSBuZXcgU3BhblBpcGVsaW5lKHNwYW5zUmVzb2x2ZWQsIHJ1bnRpbWVNZXRhZGF0YSk7XG5cbiAgY29uc3QgdHJhY2VPcHRpb25zOiBXZWJTb2NrZXRUZWxlbWV0cnlUcmFjZU9wdGlvbnMgPSB7XG4gICAgZXh0cmFjdFRyYWNlUGFyZW50OlxuICAgICAgb3B0aW9ucy50cmFjZT8uZXh0cmFjdFRyYWNlUGFyZW50ID8/IERFRkFVTFRfVFJBQ0VfT1BUSU9OUy5leHRyYWN0VHJhY2VQYXJlbnQsXG4gICAgZ2VuZXJhdGVDb25uZWN0aW9uVHJhY2U6XG4gICAgICBvcHRpb25zLnRyYWNlPy5nZW5lcmF0ZUNvbm5lY3Rpb25UcmFjZSA/PyBERUZBVUxUX1RSQUNFX09QVElPTlMuZ2VuZXJhdGVDb25uZWN0aW9uVHJhY2UsXG4gICAgcHJvcGFnYXRlTWVzc2FnZVRyYWNlOlxuICAgICAgb3B0aW9ucy50cmFjZT8ucHJvcGFnYXRlTWVzc2FnZVRyYWNlID8/IERFRkFVTFRfVFJBQ0VfT1BUSU9OUy5wcm9wYWdhdGVNZXNzYWdlVHJhY2UsXG4gICAgcmVjb3JkQ29ubmVjdGlvbkxpZmV0aW1lU3BhbjpcbiAgICAgIG9wdGlvbnMudHJhY2U/LnJlY29yZENvbm5lY3Rpb25MaWZldGltZVNwYW4gPz9cbiAgICAgIERFRkFVTFRfVFJBQ0VfT1BUSU9OUy5yZWNvcmRDb25uZWN0aW9uTGlmZXRpbWVTcGFuLFxuICB9O1xuXG4gIGNvbnN0IHNodXRkb3duVGltZW91dE1zID0gb3B0aW9ucy5zaHV0ZG93blRpbWVvdXRNcyA/PyBERUZBVUxUX1NIVVRET1dOX1RJTUVPVVRfTVM7XG5cbiAgcmV0dXJuIG5ldyBXZWJTb2NrZXRUZWxlbWV0cnlDb250cm9sbGVySW1wbChcbiAgICBldmVudFBpcGVsaW5lLFxuICAgIG1ldHJpY1BpcGVsaW5lLFxuICAgIHNwYW5QaXBlbGluZSxcbiAgICB0cmFjZU9wdGlvbnMsXG4gICAgcnVudGltZU1ldGFkYXRhLFxuICAgIHNodXRkb3duVGltZW91dE1zLFxuICApO1xufVxuXG5mdW5jdGlvbiBhc3NlcnRDb250cm9sbGVyT3B0aW9uSXNFeGNsdXNpdmUob3B0aW9uczogV2ViU29ja2V0VGVsZW1ldHJ5T3B0aW9ucyk6IHZvaWQge1xuICBjb25zdCBpZ25vcmVkS2V5cyA9IE9iamVjdC5lbnRyaWVzKG9wdGlvbnMpXG4gICAgLmZpbHRlcigoW2tleSwgdmFsdWVdKSA9PiBrZXkgIT09IFwiZW5hYmxlZFwiICYmIGtleSAhPT0gXCJjb250cm9sbGVyXCIgJiYgdmFsdWUgIT09IHVuZGVmaW5lZClcbiAgICAubWFwKChba2V5XSkgPT4ga2V5KTtcblxuICBpZiAoaWdub3JlZEtleXMubGVuZ3RoID09PSAwKSByZXR1cm47XG5cbiAgdGhyb3cgbmV3IEVycm9yKFxuICAgIGBXZWJTb2NrZXQgdGVsZW1ldHJ5IGNvbnRyb2xsZXIgb3B0aW9uIGNhbm5vdCBiZSBjb21iaW5lZCB3aXRoIG90aGVyIHRlbGVtZXRyeSBvcHRpb25zOiAke2lnbm9yZWRLZXlzLmpvaW4oXG4gICAgICBcIiwgXCIsXG4gICAgKX1gLFxuICApO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlV2ViU29ja2V0VGVsZW1ldHJ5Q29udHJvbGxlcihcbiAgdGVsZW1ldHJ5T3B0aW9uOiBib29sZWFuIHwgV2ViU29ja2V0VGVsZW1ldHJ5T3B0aW9ucyB8IHVuZGVmaW5lZCxcbiAgcnVudGltZU1ldGFkYXRhOiBSdW50aW1lTWV0YWRhdGEsXG4pOiBXZWJTb2NrZXRUZWxlbWV0cnlDb250cm9sbGVyIHtcbiAgaWYgKHRlbGVtZXRyeU9wdGlvbiA9PT0gdW5kZWZpbmVkIHx8IHRlbGVtZXRyeU9wdGlvbiA9PT0gZmFsc2UpIHtcbiAgICByZXR1cm4gbmV3IE5vb3BXZWJTb2NrZXRUZWxlbWV0cnlDb250cm9sbGVyKCk7XG4gIH1cblxuICBpZiAodGVsZW1ldHJ5T3B0aW9uID09PSB0cnVlKSB7XG4gICAgcmV0dXJuIGJ1aWxkQ29udHJvbGxlcih7fSwgcnVudGltZU1ldGFkYXRhKTtcbiAgfVxuXG4gIGlmICh0ZWxlbWV0cnlPcHRpb24uZW5hYmxlZCA9PT0gZmFsc2UpIHtcbiAgICByZXR1cm4gbmV3IE5vb3BXZWJTb2NrZXRUZWxlbWV0cnlDb250cm9sbGVyKCk7XG4gIH1cblxuICBpZiAodGVsZW1ldHJ5T3B0aW9uLmNvbnRyb2xsZXIpIHtcbiAgICBhc3NlcnRDb250cm9sbGVyT3B0aW9uSXNFeGNsdXNpdmUodGVsZW1ldHJ5T3B0aW9uKTtcbiAgICByZXR1cm4gdGVsZW1ldHJ5T3B0aW9uLmNvbnRyb2xsZXI7XG4gIH1cblxuICByZXR1cm4gYnVpbGRDb250cm9sbGVyKHRlbGVtZXRyeU9wdGlvbiwgcnVudGltZU1ldGFkYXRhKTtcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7QUErYUEsU0FBUyxlQUFlLEtBQXNCO0NB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