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.
- package/dist/ai/agents/agent.d.ts.map +1 -1
- package/dist/ai/agents/agent.js +4 -2
- package/dist/ai/providers/rtzr/api.d.ts +1 -1
- package/dist/api/decorators.d.ts +0 -1
- package/dist/api/decorators.d.ts.map +1 -1
- package/dist/api/decorators.js +8 -6
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +123 -12
- package/dist/api/websocket-helpers.d.ts +1 -3
- package/dist/api/websocket-helpers.d.ts.map +1 -1
- package/dist/api/websocket-helpers.js +2 -15
- package/dist/stream/index.d.ts +3 -0
- package/dist/stream/index.d.ts.map +1 -1
- package/dist/stream/index.js +8 -2
- package/dist/stream/ws-core.d.ts +1 -0
- package/dist/stream/ws-core.d.ts.map +1 -1
- package/dist/stream/ws-delivery.d.ts +8 -0
- package/dist/stream/ws-delivery.d.ts.map +1 -1
- package/dist/stream/ws-delivery.js +160 -14
- package/dist/stream/ws-local-connection-store.d.ts +2 -0
- package/dist/stream/ws-local-connection-store.d.ts.map +1 -1
- package/dist/stream/ws-local-connection-store.js +21 -1
- package/dist/stream/ws-registry.d.ts +6 -2
- package/dist/stream/ws-registry.d.ts.map +1 -1
- package/dist/stream/ws-registry.js +170 -6
- package/dist/stream/ws-telemetry-memory.d.ts +28 -0
- package/dist/stream/ws-telemetry-memory.d.ts.map +1 -0
- package/dist/stream/ws-telemetry-memory.js +180 -0
- package/dist/stream/ws-telemetry-trace.d.ts +12 -0
- package/dist/stream/ws-telemetry-trace.d.ts.map +1 -0
- package/dist/stream/ws-telemetry-trace.js +41 -0
- package/dist/stream/ws-telemetry.d.ts +509 -0
- package/dist/stream/ws-telemetry.d.ts.map +1 -0
- package/dist/stream/ws-telemetry.js +931 -0
- package/dist/stream/ws.d.ts +10 -3
- package/dist/stream/ws.d.ts.map +1 -1
- package/dist/stream/ws.js +306 -27
- package/dist/syncer/file-patterns.js +2 -2
- package/dist/syncer/syncer-actions.d.ts +2 -8
- package/dist/syncer/syncer-actions.d.ts.map +1 -1
- package/dist/syncer/syncer-actions.js +4 -11
- package/dist/syncer/syncer.d.ts +1 -1
- package/dist/syncer/syncer.d.ts.map +1 -1
- package/dist/syncer/syncer.js +8 -6
- package/dist/template/template.d.ts +1 -2
- package/dist/template/template.d.ts.map +1 -1
- package/dist/template/template.js +3 -4
- package/dist/template/zod-converter.d.ts +2 -2
- package/dist/testing/dev-vitest-manager.d.ts +1 -1
- package/dist/testing/dev-vitest-manager.js +2 -2
- package/dist/types/types.d.ts +11 -5
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/types.js +2 -2
- package/dist/utils/class-name.d.ts +6 -0
- package/dist/utils/class-name.d.ts.map +1 -0
- package/dist/utils/class-name.js +19 -0
- package/package.json +2 -2
- package/src/ai/agents/agent.ts +2 -1
- package/src/api/__tests__/sonamu.websocket.test.ts +84 -10
- package/src/api/decorators.ts +6 -6
- package/src/api/sonamu.ts +142 -7
- package/src/api/websocket-helpers.ts +2 -28
- package/src/shared/app.shared.ts.txt +16 -8
- package/src/shared/web.shared.ts.txt +8 -7
- package/src/skills/sonamu/testing-devrunner.md +1 -1
- package/src/stream/__tests__/ws-telemetry.test.ts +821 -0
- package/src/stream/__tests__/ws.test.ts +362 -2
- package/src/stream/index.ts +3 -0
- package/src/stream/ws-core.ts +2 -0
- package/src/stream/ws-delivery.ts +161 -19
- package/src/stream/ws-local-connection-store.ts +33 -0
- package/src/stream/ws-registry.ts +186 -5
- package/src/stream/ws-telemetry-memory.ts +246 -0
- package/src/stream/ws-telemetry-trace.ts +52 -0
- package/src/stream/ws-telemetry.ts +1772 -0
- package/src/stream/ws.ts +332 -34
- package/src/syncer/file-patterns.ts +3 -3
- package/src/syncer/syncer-actions.ts +3 -15
- package/src/syncer/syncer.ts +9 -13
- package/src/template/__tests__/services.template.websocket.test.ts +2 -0
- package/src/template/template.ts +2 -3
- package/src/testing/dev-vitest-manager.ts +1 -1
- package/src/types/types.ts +10 -3
- 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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
|