@garrix82/reactgenie-lib 1.3.0
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/.env.example +22 -0
- package/.github/workflows/publish.yml +20 -0
- package/LICENSE.txt +201 -0
- package/README.md +621 -0
- package/babel.config.js +29 -0
- package/dist/adapters/__tests__/expo-router-adapter.test.d.ts +1 -0
- package/dist/adapters/expo-router-adapter.d.ts +16 -0
- package/dist/adapters/expo-router-adapter.js +521 -0
- package/dist/adapters/navigation-adapter.d.ts +20 -0
- package/dist/adapters/navigation-adapter.js +137 -0
- package/dist/audio-visualizer.d.ts +14 -0
- package/dist/audio-visualizer.js +123 -0
- package/dist/current-selection.d.ts +27 -0
- package/dist/current-selection.js +94 -0
- package/dist/errors.d.ts +19 -0
- package/dist/errors.js +37 -0
- package/dist/genie/DateTime.d.ts +66 -0
- package/dist/genie/DateTime.js +399 -0
- package/dist/genie/TimeDelta.d.ts +35 -0
- package/dist/genie/TimeDelta.js +169 -0
- package/dist/genie-view-wrapper.d.ts +1 -0
- package/dist/genie-view-wrapper.js +377 -0
- package/dist/hooks/__tests__/useSpeechRecognition.test.d.ts +1 -0
- package/dist/hooks/useSpeechRecognition.d.ts +28 -0
- package/dist/hooks/useSpeechRecognition.js +118 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +469 -0
- package/dist/logger.d.ts +23 -0
- package/dist/logger.js +597 -0
- package/dist/logger.remote.test.d.ts +0 -0
- package/dist/modality-provider-v2.d.ts +28 -0
- package/dist/modality-provider-v2.js +1321 -0
- package/dist/modality-provider.d.ts +22 -0
- package/dist/modality-provider.js +373 -0
- package/dist/native-visibility.d.ts +28 -0
- package/dist/native-visibility.js +50 -0
- package/dist/platform/VoiceRecognitionBar.d.ts +17 -0
- package/dist/platform/VoiceRecognitionBar.js +332 -0
- package/dist/platform/components.d.ts +32 -0
- package/dist/platform/components.js +351 -0
- package/dist/platform/events.d.ts +31 -0
- package/dist/platform/events.js +274 -0
- package/dist/platform/index.d.ts +3 -0
- package/dist/platform/index.js +39 -0
- package/dist/platform/types.d.ts +79 -0
- package/dist/platform/types.js +97 -0
- package/dist/react-decorators.d.ts +87 -0
- package/dist/react-decorators.js +368 -0
- package/dist/shared-store.d.ts +74 -0
- package/dist/shared-store.js +589 -0
- package/dist/speech-recognition/__tests__/speech-recognition-groq-transport.test.d.ts +1 -0
- package/dist/speech-recognition/__tests__/speech-recognition-native.test.d.ts +1 -0
- package/dist/speech-recognition/__tests__/speech-recognition-openai-native.test.d.ts +1 -0
- package/dist/speech-recognition/__tests__/speech-recognition-openai.test.d.ts +1 -0
- package/dist/speech-recognition/__tests__/speech-recognition-unified-import.test.d.ts +0 -0
- package/dist/speech-recognition/__tests__/speech-recognition-unified.test.d.ts +1 -0
- package/dist/speech-recognition/speech-recognition-groq.d.ts +21 -0
- package/dist/speech-recognition/speech-recognition-groq.js +409 -0
- package/dist/speech-recognition/speech-recognition-mlx.d.ts +15 -0
- package/dist/speech-recognition/speech-recognition-mlx.js +393 -0
- package/dist/speech-recognition/speech-recognition-native.d.ts +24 -0
- package/dist/speech-recognition/speech-recognition-native.js +632 -0
- package/dist/speech-recognition/speech-recognition-openai-native.d.ts +40 -0
- package/dist/speech-recognition/speech-recognition-openai-native.js +653 -0
- package/dist/speech-recognition/speech-recognition-openai.d.ts +39 -0
- package/dist/speech-recognition/speech-recognition-openai.js +718 -0
- package/dist/speech-recognition/speech-recognition-unified.d.ts +93 -0
- package/dist/speech-recognition/speech-recognition-unified.js +589 -0
- package/dist/speech-recognition/utils/groq-transcription.d.ts +41 -0
- package/dist/speech-recognition/utils/groq-transcription.js +382 -0
- package/dist/speech-recognition.d.ts +7 -0
- package/dist/speech-recognition.js +61 -0
- package/dist/voice-pipeline-telemetry.d.ts +26 -0
- package/dist/voice-pipeline-telemetry.js +15 -0
- package/garrix82-reactgenie-lib-1.3.0.tgz +0 -0
- package/metro/index.js +3 -0
- package/metro/with-genie-registry.js +47 -0
- package/package.json +111 -0
- package/scripts/dry-run.js +23 -0
- package/scripts/generate-genie-registry.js +278 -0
- package/scripts/log-file-test.js +51 -0
- package/scripts/parse.js +26 -0
- package/scripts/prompt.js +19 -0
- package/scripts/set-script.js +200 -0
- package/tsconfig.json +36 -0
|
@@ -0,0 +1,653 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = exports.OpenAINativeSpeechRecognizer = void 0;
|
|
7
|
+
exports.getOpenAINativeSpeechCapabilities = getOpenAINativeSpeechCapabilities;
|
|
8
|
+
exports.isOpenAINativeSpeechAvailable = isOpenAINativeSpeechAvailable;
|
|
9
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
10
|
+
var _reactNative = require("react-native");
|
|
11
|
+
var _logger = _interopRequireDefault(require("../logger"));
|
|
12
|
+
var _groqTranscription = require("./utils/groq-transcription");
|
|
13
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
15
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
16
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
17
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
18
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
19
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
20
|
+
function loadReactNativeWebRTC() {
|
|
21
|
+
try {
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
23
|
+
const module = require("react-native-webrtc");
|
|
24
|
+
const resolved = module?.default || module;
|
|
25
|
+
if (resolved?.RTCPeerConnection && resolved?.mediaDevices?.getUserMedia) {
|
|
26
|
+
return resolved;
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
} catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const nativeWebRTC = loadReactNativeWebRTC();
|
|
34
|
+
const DEFAULT_REALTIME_MODEL = "gpt-4o-transcribe";
|
|
35
|
+
const DEFAULT_REALTIME_WEBRTC_URL = "https://api.openai.com/v1/realtime?intent=transcription";
|
|
36
|
+
const DATA_CHANNEL_OPEN_TIMEOUT_MS = 6000;
|
|
37
|
+
const OpenAINativeSpeechRecognizer = ({
|
|
38
|
+
shouldListen,
|
|
39
|
+
speechStatusCallback,
|
|
40
|
+
speechResultCallback,
|
|
41
|
+
speechTranslationCallback,
|
|
42
|
+
speechReadyCallback,
|
|
43
|
+
clientSecret,
|
|
44
|
+
openaiTranscriptionSessionEndpoint,
|
|
45
|
+
openaiTranslationEndpoint,
|
|
46
|
+
openaiRealtimeWebRtcUrl = DEFAULT_REALTIME_WEBRTC_URL,
|
|
47
|
+
openaiRealtimeModel = DEFAULT_REALTIME_MODEL,
|
|
48
|
+
openaiTranslationModel = "gpt-4.1-mini",
|
|
49
|
+
openaiVadEnabled = true,
|
|
50
|
+
openaiAutoStopOnVadSilence = false,
|
|
51
|
+
openaiVadThreshold = 0.7,
|
|
52
|
+
openaiVadPrefixPaddingMs = 400,
|
|
53
|
+
openaiVadSilenceDurationMs = 1000,
|
|
54
|
+
openaiVadIdleTimeoutMs = 6000,
|
|
55
|
+
openaiPrewarmOnMount = false,
|
|
56
|
+
language = "en",
|
|
57
|
+
requestContextProvider,
|
|
58
|
+
onError
|
|
59
|
+
}) => {
|
|
60
|
+
const proxyAuthToken = clientSecret;
|
|
61
|
+
const [isRecording, setIsRecording] = (0, _react.useState)(false);
|
|
62
|
+
const [sessionRecoveryToken, setSessionRecoveryToken] = (0, _react.useState)(0);
|
|
63
|
+
const pcRef = (0, _react.useRef)(null);
|
|
64
|
+
const dataChannelRef = (0, _react.useRef)(null);
|
|
65
|
+
const streamRef = (0, _react.useRef)(null);
|
|
66
|
+
const sessionInitRef = (0, _react.useRef)(null);
|
|
67
|
+
const finalTranscriptRef = (0, _react.useRef)("");
|
|
68
|
+
const interimTranscriptRef = (0, _react.useRef)("");
|
|
69
|
+
const stopInFlightRef = (0, _react.useRef)(false);
|
|
70
|
+
const finalizedRef = (0, _react.useRef)(false);
|
|
71
|
+
const awaitingCommitFinalRef = (0, _react.useRef)(false);
|
|
72
|
+
const commitFinalTimeoutRef = (0, _react.useRef)(null);
|
|
73
|
+
const didPrewarmRef = (0, _react.useRef)(false);
|
|
74
|
+
const isRecordingRef = (0, _react.useRef)(false);
|
|
75
|
+
const shouldListenRef = (0, _react.useRef)(shouldListen);
|
|
76
|
+
const openaiPrewarmOnMountRef = (0, _react.useRef)(openaiPrewarmOnMount);
|
|
77
|
+
const sessionRecoveryModeRef = (0, _react.useRef)(null);
|
|
78
|
+
const sessionRecoveryInFlightRef = (0, _react.useRef)(false);
|
|
79
|
+
const suppressedChannelErrorRef = (0, _react.useRef)(null);
|
|
80
|
+
const emitError = (0, _react.useCallback)(error => {
|
|
81
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
82
|
+
_logger.default.error("[OpenAI Native SR] error:", err);
|
|
83
|
+
onError?.(err);
|
|
84
|
+
}, [onError]);
|
|
85
|
+
const buildTurnDetection = (0, _react.useCallback)(() => {
|
|
86
|
+
if (!openaiVadEnabled) return null;
|
|
87
|
+
return {
|
|
88
|
+
type: "server_vad",
|
|
89
|
+
threshold: openaiVadThreshold,
|
|
90
|
+
prefix_padding_ms: openaiVadPrefixPaddingMs,
|
|
91
|
+
silence_duration_ms: openaiVadSilenceDurationMs
|
|
92
|
+
};
|
|
93
|
+
}, [openaiVadEnabled, openaiVadThreshold, openaiVadPrefixPaddingMs, openaiVadSilenceDurationMs]);
|
|
94
|
+
const waitForDataChannelOpen = (0, _react.useCallback)(async channel => {
|
|
95
|
+
if (channel?.readyState === "open") {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const start = Date.now();
|
|
99
|
+
while (Date.now() - start < DATA_CHANNEL_OPEN_TIMEOUT_MS) {
|
|
100
|
+
if (channel?.readyState === "open") {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
104
|
+
}
|
|
105
|
+
throw new Error(`OpenAI native realtime data channel did not open within ${DATA_CHANNEL_OPEN_TIMEOUT_MS}ms (state=${String(channel?.readyState ?? "unknown")})`);
|
|
106
|
+
}, []);
|
|
107
|
+
const resetTranscriptRefs = (0, _react.useCallback)(() => {
|
|
108
|
+
finalTranscriptRef.current = "";
|
|
109
|
+
interimTranscriptRef.current = "";
|
|
110
|
+
finalizedRef.current = false;
|
|
111
|
+
}, []);
|
|
112
|
+
const getBufferedTranscript = (0, _react.useCallback)(() => {
|
|
113
|
+
return (finalTranscriptRef.current || interimTranscriptRef.current).trim();
|
|
114
|
+
}, []);
|
|
115
|
+
const clearCommitFinalWait = (0, _react.useCallback)(() => {
|
|
116
|
+
awaitingCommitFinalRef.current = false;
|
|
117
|
+
if (commitFinalTimeoutRef.current) {
|
|
118
|
+
clearTimeout(commitFinalTimeoutRef.current);
|
|
119
|
+
commitFinalTimeoutRef.current = null;
|
|
120
|
+
}
|
|
121
|
+
}, []);
|
|
122
|
+
const notifyReady = (0, _react.useCallback)(ready => {
|
|
123
|
+
speechReadyCallback?.(ready);
|
|
124
|
+
}, [speechReadyCallback]);
|
|
125
|
+
(0, _react.useEffect)(() => {
|
|
126
|
+
isRecordingRef.current = isRecording;
|
|
127
|
+
}, [isRecording]);
|
|
128
|
+
(0, _react.useEffect)(() => {
|
|
129
|
+
shouldListenRef.current = shouldListen;
|
|
130
|
+
}, [shouldListen]);
|
|
131
|
+
(0, _react.useEffect)(() => {
|
|
132
|
+
openaiPrewarmOnMountRef.current = openaiPrewarmOnMount;
|
|
133
|
+
}, [openaiPrewarmOnMount]);
|
|
134
|
+
const setAudioCaptureEnabled = (0, _react.useCallback)(enabled => {
|
|
135
|
+
const stream = streamRef.current;
|
|
136
|
+
if (!stream || typeof stream.getTracks !== "function") {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
const tracks = stream.getTracks().filter(track => track?.kind === "audio");
|
|
141
|
+
tracks.forEach(track => {
|
|
142
|
+
try {
|
|
143
|
+
track.enabled = enabled;
|
|
144
|
+
} catch (error) {
|
|
145
|
+
_logger.default.warn("[OpenAI Native SR] toggle audio track warning:", error);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
} catch (error) {
|
|
149
|
+
_logger.default.warn("[OpenAI Native SR] enumerate audio tracks warning:", error);
|
|
150
|
+
}
|
|
151
|
+
}, []);
|
|
152
|
+
const handleExpiredSession = (0, _react.useCallback)((channel, pc) => {
|
|
153
|
+
if (sessionRecoveryInFlightRef.current) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (dataChannelRef.current !== channel) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
sessionRecoveryInFlightRef.current = true;
|
|
160
|
+
suppressedChannelErrorRef.current = channel;
|
|
161
|
+
sessionRecoveryModeRef.current = shouldListenRef.current ? "listen" : openaiPrewarmOnMountRef.current ? "prewarm" : null;
|
|
162
|
+
clearCommitFinalWait();
|
|
163
|
+
resetTranscriptRefs();
|
|
164
|
+
setAudioCaptureEnabled(false);
|
|
165
|
+
sessionInitRef.current = null;
|
|
166
|
+
try {
|
|
167
|
+
channel?.close?.();
|
|
168
|
+
} catch (error) {
|
|
169
|
+
_logger.default.warn("[OpenAI Native SR] close data channel warning:", error);
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
pc?.close?.();
|
|
173
|
+
} catch (error) {
|
|
174
|
+
_logger.default.warn("[OpenAI Native SR] close peer warning:", error);
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
streamRef.current?.getTracks?.().forEach(track => track.stop?.());
|
|
178
|
+
} catch (error) {
|
|
179
|
+
_logger.default.warn("[OpenAI Native SR] stop stream warning:", error);
|
|
180
|
+
}
|
|
181
|
+
if (dataChannelRef.current === channel) {
|
|
182
|
+
dataChannelRef.current = null;
|
|
183
|
+
}
|
|
184
|
+
if (pcRef.current === pc) {
|
|
185
|
+
pcRef.current = null;
|
|
186
|
+
}
|
|
187
|
+
streamRef.current = null;
|
|
188
|
+
setIsRecording(false);
|
|
189
|
+
notifyReady(false);
|
|
190
|
+
speechStatusCallback(false, "");
|
|
191
|
+
if (sessionRecoveryModeRef.current) {
|
|
192
|
+
setSessionRecoveryToken(value => value + 1);
|
|
193
|
+
} else {
|
|
194
|
+
sessionRecoveryInFlightRef.current = false;
|
|
195
|
+
suppressedChannelErrorRef.current = null;
|
|
196
|
+
}
|
|
197
|
+
}, [clearCommitFinalWait, notifyReady, resetTranscriptRefs, setAudioCaptureEnabled, speechStatusCallback]);
|
|
198
|
+
const clearRealtimeInputBuffer = (0, _react.useCallback)(reason => {
|
|
199
|
+
if (dataChannelRef.current?.readyState !== "open") {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
203
|
+
dataChannelRef.current.send(JSON.stringify({
|
|
204
|
+
type: "input_audio_buffer.clear"
|
|
205
|
+
}));
|
|
206
|
+
_logger.default.debug(`[OpenAI Native SR] cleared input buffer (${reason})`);
|
|
207
|
+
} catch (error) {
|
|
208
|
+
_logger.default.warn("[OpenAI Native SR] clear input buffer warning:", error);
|
|
209
|
+
}
|
|
210
|
+
}, []);
|
|
211
|
+
const getRequestContextHeaders = (0, _react.useCallback)(() => {
|
|
212
|
+
const context = requestContextProvider?.();
|
|
213
|
+
if (!context) return {};
|
|
214
|
+
const headers = {};
|
|
215
|
+
if (context.threadId) {
|
|
216
|
+
headers["x-thread-id"] = String(context.threadId);
|
|
217
|
+
}
|
|
218
|
+
if (context.turnId) {
|
|
219
|
+
headers["x-turn-id"] = String(context.turnId);
|
|
220
|
+
}
|
|
221
|
+
if (context.sessionId !== undefined && context.sessionId !== null) {
|
|
222
|
+
headers["x-voice-session-id"] = String(context.sessionId);
|
|
223
|
+
}
|
|
224
|
+
if (context.sentryTrace) {
|
|
225
|
+
headers["sentry-trace"] = String(context.sentryTrace);
|
|
226
|
+
}
|
|
227
|
+
if (context.baggage) {
|
|
228
|
+
headers.baggage = String(context.baggage);
|
|
229
|
+
}
|
|
230
|
+
return headers;
|
|
231
|
+
}, [requestContextProvider]);
|
|
232
|
+
const translateToEnglish = (0, _react.useCallback)(async text => {
|
|
233
|
+
const input = text.trim();
|
|
234
|
+
if (!input || !openaiTranslationEndpoint) return "";
|
|
235
|
+
if (language.toLowerCase().startsWith("en")) return "";
|
|
236
|
+
const headers = _objectSpread({
|
|
237
|
+
"content-type": "application/json"
|
|
238
|
+
}, getRequestContextHeaders());
|
|
239
|
+
if (proxyAuthToken) {
|
|
240
|
+
headers.Authorization = `Bearer ${proxyAuthToken}`;
|
|
241
|
+
}
|
|
242
|
+
const response = await fetch(openaiTranslationEndpoint, {
|
|
243
|
+
method: "POST",
|
|
244
|
+
headers,
|
|
245
|
+
body: JSON.stringify({
|
|
246
|
+
text: input,
|
|
247
|
+
sourceLanguage: language,
|
|
248
|
+
model: openaiTranslationModel
|
|
249
|
+
})
|
|
250
|
+
});
|
|
251
|
+
if (!response.ok) {
|
|
252
|
+
const body = await response.text().catch(() => "");
|
|
253
|
+
throw new Error(`translation failed (${response.status}): ${body}`);
|
|
254
|
+
}
|
|
255
|
+
const payload = await response.json().catch(() => null);
|
|
256
|
+
const translated = typeof payload?.text === "string" ? payload.text.trim() : "";
|
|
257
|
+
if (translated) {
|
|
258
|
+
speechTranslationCallback?.(translated);
|
|
259
|
+
}
|
|
260
|
+
return translated;
|
|
261
|
+
}, [proxyAuthToken, language, getRequestContextHeaders, openaiTranslationEndpoint, openaiTranslationModel, speechTranslationCallback]);
|
|
262
|
+
const emitFinal = (0, _react.useCallback)(async () => {
|
|
263
|
+
if (finalizedRef.current) return;
|
|
264
|
+
finalizedRef.current = true;
|
|
265
|
+
const finalText = (finalTranscriptRef.current || interimTranscriptRef.current).trim();
|
|
266
|
+
let parseText = finalText;
|
|
267
|
+
try {
|
|
268
|
+
const translated = await translateToEnglish(finalText);
|
|
269
|
+
if (translated) {
|
|
270
|
+
parseText = translated;
|
|
271
|
+
}
|
|
272
|
+
} catch (error) {
|
|
273
|
+
_logger.default.warn("[OpenAI Native SR] translation failed:", error);
|
|
274
|
+
} finally {
|
|
275
|
+
speechStatusCallback(false, "");
|
|
276
|
+
if (parseText) {
|
|
277
|
+
speechResultCallback(parseText);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}, [speechResultCallback, speechStatusCallback, translateToEnglish]);
|
|
281
|
+
const finalizeAndReset = (0, _react.useCallback)(async () => {
|
|
282
|
+
clearCommitFinalWait();
|
|
283
|
+
await emitFinal();
|
|
284
|
+
resetTranscriptRefs();
|
|
285
|
+
}, [clearCommitFinalWait, emitFinal, resetTranscriptRefs]);
|
|
286
|
+
const handleMessage = (0, _react.useCallback)(payload => {
|
|
287
|
+
const type = String(payload?.type || "");
|
|
288
|
+
const acceptsTranscript = isRecordingRef.current || awaitingCommitFinalRef.current;
|
|
289
|
+
if (!acceptsTranscript) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
const shouldPublishInterim = isRecordingRef.current;
|
|
293
|
+
const delta = extractDeltaText(payload);
|
|
294
|
+
const completed = extractCompletedText(payload);
|
|
295
|
+
if (delta) {
|
|
296
|
+
interimTranscriptRef.current = (0, _groqTranscription.mergeTranscriptParts)(finalTranscriptRef.current, delta);
|
|
297
|
+
if (shouldPublishInterim) {
|
|
298
|
+
speechStatusCallback(true, interimTranscriptRef.current);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (completed) {
|
|
302
|
+
finalTranscriptRef.current = (0, _groqTranscription.mergeTranscriptParts)(finalTranscriptRef.current, completed);
|
|
303
|
+
interimTranscriptRef.current = finalTranscriptRef.current;
|
|
304
|
+
if (shouldPublishInterim) {
|
|
305
|
+
speechStatusCallback(true, finalTranscriptRef.current);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
const looksCompleted = !!completed || type.includes("completed");
|
|
309
|
+
if (awaitingCommitFinalRef.current && looksCompleted && getBufferedTranscript()) {
|
|
310
|
+
finalizeAndReset().catch(error => emitError(error));
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (openaiAutoStopOnVadSilence && type === "input_audio_buffer.speech_stopped") {
|
|
314
|
+
const pauseTranscript = getBufferedTranscript();
|
|
315
|
+
speechStatusCallback(false, pauseTranscript);
|
|
316
|
+
}
|
|
317
|
+
}, [emitError, finalizeAndReset, getBufferedTranscript, openaiAutoStopOnVadSilence, speechStatusCallback]);
|
|
318
|
+
const startNativeWebRtcSession = (0, _react.useCallback)(async token => {
|
|
319
|
+
const webrtc = nativeWebRTC;
|
|
320
|
+
if (!webrtc?.RTCPeerConnection || !webrtc?.mediaDevices?.getUserMedia) {
|
|
321
|
+
throw new Error("react-native-webrtc is not installed. Install it for OpenAI native realtime speech.");
|
|
322
|
+
}
|
|
323
|
+
const stream = await webrtc.mediaDevices.getUserMedia({
|
|
324
|
+
audio: true,
|
|
325
|
+
video: false
|
|
326
|
+
});
|
|
327
|
+
streamRef.current = stream;
|
|
328
|
+
setAudioCaptureEnabled(false);
|
|
329
|
+
const pc = new webrtc.RTCPeerConnection();
|
|
330
|
+
pcRef.current = pc;
|
|
331
|
+
const tracks = typeof stream.getTracks === "function" ? stream.getTracks() : [];
|
|
332
|
+
tracks.forEach(track => pc.addTrack(track, stream));
|
|
333
|
+
const dataChannel = pc.createDataChannel("oai-events");
|
|
334
|
+
dataChannelRef.current = dataChannel;
|
|
335
|
+
dataChannel.onopen = () => {
|
|
336
|
+
notifyReady(true);
|
|
337
|
+
};
|
|
338
|
+
dataChannel.onmessage = event => {
|
|
339
|
+
try {
|
|
340
|
+
const payload = JSON.parse(String(event.data || "{}"));
|
|
341
|
+
if (payload?.type === "error") {
|
|
342
|
+
const message = String(payload?.error?.message || "OpenAI realtime error");
|
|
343
|
+
if (isCommitBufferTooSmallError(message)) {
|
|
344
|
+
// Ignore commit buffer-too-small errors for low-latency fast-stop path.
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
if (isSessionDurationLimitError(message)) {
|
|
348
|
+
handleExpiredSession(dataChannel, pc);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
throw new Error(message);
|
|
352
|
+
}
|
|
353
|
+
handleMessage(payload);
|
|
354
|
+
} catch (error) {
|
|
355
|
+
emitError(error);
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
dataChannel.onerror = () => {
|
|
359
|
+
if (suppressedChannelErrorRef.current === dataChannel) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
notifyReady(false);
|
|
363
|
+
emitError(new Error("OpenAI native realtime data channel error"));
|
|
364
|
+
};
|
|
365
|
+
dataChannel.onclose = () => {
|
|
366
|
+
notifyReady(false);
|
|
367
|
+
};
|
|
368
|
+
const offer = await pc.createOffer();
|
|
369
|
+
await pc.setLocalDescription(offer);
|
|
370
|
+
const response = await fetch(openaiRealtimeWebRtcUrl, {
|
|
371
|
+
method: "POST",
|
|
372
|
+
headers: {
|
|
373
|
+
Authorization: `Bearer ${token}`,
|
|
374
|
+
"content-type": "application/sdp"
|
|
375
|
+
},
|
|
376
|
+
body: offer?.sdp || ""
|
|
377
|
+
});
|
|
378
|
+
if (!response.ok) {
|
|
379
|
+
const body = await response.text().catch(() => "");
|
|
380
|
+
throw new Error(`webrtc negotiation failed (${response.status}): ${body}`);
|
|
381
|
+
}
|
|
382
|
+
const answerSdp = await response.text();
|
|
383
|
+
await pc.setRemoteDescription({
|
|
384
|
+
type: "answer",
|
|
385
|
+
sdp: answerSdp
|
|
386
|
+
});
|
|
387
|
+
await waitForDataChannelOpen(dataChannel);
|
|
388
|
+
}, [emitError, handleMessage, notifyReady, openaiRealtimeWebRtcUrl, setAudioCaptureEnabled, waitForDataChannelOpen]);
|
|
389
|
+
const getEphemeralToken = (0, _react.useCallback)(async () => {
|
|
390
|
+
const headers = _objectSpread({
|
|
391
|
+
"content-type": "application/json"
|
|
392
|
+
}, getRequestContextHeaders());
|
|
393
|
+
if (proxyAuthToken) {
|
|
394
|
+
headers.Authorization = `Bearer ${proxyAuthToken}`;
|
|
395
|
+
}
|
|
396
|
+
const response = await fetch(openaiTranscriptionSessionEndpoint, {
|
|
397
|
+
method: "POST",
|
|
398
|
+
headers,
|
|
399
|
+
body: JSON.stringify({
|
|
400
|
+
input_audio_format: "pcm16",
|
|
401
|
+
input_audio_transcription: {
|
|
402
|
+
model: openaiRealtimeModel,
|
|
403
|
+
language
|
|
404
|
+
},
|
|
405
|
+
turn_detection: buildTurnDetection() || undefined
|
|
406
|
+
})
|
|
407
|
+
});
|
|
408
|
+
if (!response.ok) {
|
|
409
|
+
const body = await response.text().catch(() => "");
|
|
410
|
+
throw new Error(`transcription session request failed (${response.status}): ${body}`);
|
|
411
|
+
}
|
|
412
|
+
const payload = await response.json().catch(() => ({}));
|
|
413
|
+
const token = payload?.client_secret?.value || payload?.client_secret || payload?.value || "";
|
|
414
|
+
if (!token) {
|
|
415
|
+
throw new Error("No ephemeral token returned from transcription session endpoint");
|
|
416
|
+
}
|
|
417
|
+
return token;
|
|
418
|
+
}, [buildTurnDetection, getRequestContextHeaders, proxyAuthToken, language, openaiRealtimeModel, openaiTranscriptionSessionEndpoint]);
|
|
419
|
+
const hasReusableSession = (0, _react.useCallback)(() => {
|
|
420
|
+
return !!pcRef.current && !!streamRef.current && dataChannelRef.current?.readyState === "open";
|
|
421
|
+
}, []);
|
|
422
|
+
const ensureNativeWebRtcSession = (0, _react.useCallback)(async () => {
|
|
423
|
+
if (hasReusableSession()) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
if (sessionInitRef.current) {
|
|
427
|
+
await sessionInitRef.current;
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
sessionInitRef.current = (async () => {
|
|
431
|
+
const token = await getEphemeralToken();
|
|
432
|
+
await startNativeWebRtcSession(token);
|
|
433
|
+
})();
|
|
434
|
+
try {
|
|
435
|
+
await sessionInitRef.current;
|
|
436
|
+
} finally {
|
|
437
|
+
sessionInitRef.current = null;
|
|
438
|
+
}
|
|
439
|
+
}, [getEphemeralToken, hasReusableSession, startNativeWebRtcSession]);
|
|
440
|
+
const cleanup = (0, _react.useCallback)(() => {
|
|
441
|
+
sessionInitRef.current = null;
|
|
442
|
+
try {
|
|
443
|
+
if (dataChannelRef.current) {
|
|
444
|
+
dataChannelRef.current.close();
|
|
445
|
+
}
|
|
446
|
+
} catch (error) {
|
|
447
|
+
_logger.default.warn("[OpenAI Native SR] close data channel warning:", error);
|
|
448
|
+
} finally {
|
|
449
|
+
dataChannelRef.current = null;
|
|
450
|
+
}
|
|
451
|
+
try {
|
|
452
|
+
if (pcRef.current) {
|
|
453
|
+
pcRef.current.close();
|
|
454
|
+
}
|
|
455
|
+
} catch (error) {
|
|
456
|
+
_logger.default.warn("[OpenAI Native SR] close peer warning:", error);
|
|
457
|
+
} finally {
|
|
458
|
+
pcRef.current = null;
|
|
459
|
+
}
|
|
460
|
+
try {
|
|
461
|
+
if (streamRef.current?.getTracks) {
|
|
462
|
+
streamRef.current.getTracks().forEach(track => track.stop?.());
|
|
463
|
+
}
|
|
464
|
+
} catch (error) {
|
|
465
|
+
_logger.default.warn("[OpenAI Native SR] stop stream warning:", error);
|
|
466
|
+
} finally {
|
|
467
|
+
streamRef.current = null;
|
|
468
|
+
}
|
|
469
|
+
}, []);
|
|
470
|
+
(0, _react.useEffect)(() => {
|
|
471
|
+
if (sessionRecoveryToken === 0 || !sessionRecoveryModeRef.current) {
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
let cancelled = false;
|
|
475
|
+
const recoveryMode = sessionRecoveryModeRef.current;
|
|
476
|
+
(async () => {
|
|
477
|
+
try {
|
|
478
|
+
await ensureNativeWebRtcSession();
|
|
479
|
+
if (cancelled) {
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
if (recoveryMode === "listen" && shouldListenRef.current) {
|
|
483
|
+
setAudioCaptureEnabled(true);
|
|
484
|
+
setIsRecording(true);
|
|
485
|
+
}
|
|
486
|
+
notifyReady(dataChannelRef.current?.readyState === "open");
|
|
487
|
+
} catch (error) {
|
|
488
|
+
if (cancelled) {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
emitError(error);
|
|
492
|
+
setAudioCaptureEnabled(false);
|
|
493
|
+
cleanup();
|
|
494
|
+
setIsRecording(false);
|
|
495
|
+
notifyReady(false);
|
|
496
|
+
speechStatusCallback(false, "");
|
|
497
|
+
} finally {
|
|
498
|
+
if (cancelled) {
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
sessionRecoveryModeRef.current = null;
|
|
502
|
+
sessionRecoveryInFlightRef.current = false;
|
|
503
|
+
suppressedChannelErrorRef.current = null;
|
|
504
|
+
}
|
|
505
|
+
})();
|
|
506
|
+
return () => {
|
|
507
|
+
cancelled = true;
|
|
508
|
+
};
|
|
509
|
+
}, [cleanup, emitError, ensureNativeWebRtcSession, notifyReady, sessionRecoveryToken, setAudioCaptureEnabled, speechStatusCallback]);
|
|
510
|
+
const startRecording = (0, _react.useCallback)(async () => {
|
|
511
|
+
if (isRecording || stopInFlightRef.current || sessionRecoveryInFlightRef.current) {
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
resetTranscriptRefs();
|
|
515
|
+
try {
|
|
516
|
+
clearCommitFinalWait();
|
|
517
|
+
notifyReady(false);
|
|
518
|
+
const reusingWarmSession = hasReusableSession();
|
|
519
|
+
await ensureNativeWebRtcSession();
|
|
520
|
+
if (reusingWarmSession) {
|
|
521
|
+
clearRealtimeInputBuffer("start_recording");
|
|
522
|
+
}
|
|
523
|
+
if (!shouldListenRef.current) {
|
|
524
|
+
setAudioCaptureEnabled(false);
|
|
525
|
+
notifyReady(dataChannelRef.current?.readyState === "open");
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
setAudioCaptureEnabled(true);
|
|
529
|
+
setIsRecording(true);
|
|
530
|
+
notifyReady(dataChannelRef.current?.readyState === "open");
|
|
531
|
+
} catch (error) {
|
|
532
|
+
emitError(error);
|
|
533
|
+
setAudioCaptureEnabled(false);
|
|
534
|
+
cleanup();
|
|
535
|
+
setIsRecording(false);
|
|
536
|
+
notifyReady(false);
|
|
537
|
+
speechStatusCallback(false, "");
|
|
538
|
+
}
|
|
539
|
+
}, [cleanup, clearCommitFinalWait, clearRealtimeInputBuffer, ensureNativeWebRtcSession, emitError, hasReusableSession, isRecording, notifyReady, resetTranscriptRefs, setAudioCaptureEnabled, speechStatusCallback]);
|
|
540
|
+
const stopRecording = (0, _react.useCallback)(async () => {
|
|
541
|
+
if (!isRecording || stopInFlightRef.current) return;
|
|
542
|
+
stopInFlightRef.current = true;
|
|
543
|
+
setIsRecording(false);
|
|
544
|
+
setAudioCaptureEnabled(false);
|
|
545
|
+
notifyReady(false);
|
|
546
|
+
try {
|
|
547
|
+
if (dataChannelRef.current?.readyState === "open") {
|
|
548
|
+
dataChannelRef.current.send(JSON.stringify({
|
|
549
|
+
type: "input_audio_buffer.commit"
|
|
550
|
+
}));
|
|
551
|
+
}
|
|
552
|
+
const buffered = getBufferedTranscript();
|
|
553
|
+
if (buffered) {
|
|
554
|
+
await finalizeAndReset();
|
|
555
|
+
} else {
|
|
556
|
+
speechStatusCallback(false, "");
|
|
557
|
+
awaitingCommitFinalRef.current = true;
|
|
558
|
+
if (commitFinalTimeoutRef.current) {
|
|
559
|
+
clearTimeout(commitFinalTimeoutRef.current);
|
|
560
|
+
}
|
|
561
|
+
// Short fallback: if no post-commit transcript arrives, reset state and exit.
|
|
562
|
+
commitFinalTimeoutRef.current = setTimeout(() => {
|
|
563
|
+
if (!awaitingCommitFinalRef.current) return;
|
|
564
|
+
clearCommitFinalWait();
|
|
565
|
+
resetTranscriptRefs();
|
|
566
|
+
}, 1500);
|
|
567
|
+
}
|
|
568
|
+
} catch (error) {
|
|
569
|
+
emitError(error);
|
|
570
|
+
speechStatusCallback(false, "");
|
|
571
|
+
} finally {
|
|
572
|
+
stopInFlightRef.current = false;
|
|
573
|
+
notifyReady(false);
|
|
574
|
+
}
|
|
575
|
+
}, [emitError, finalizeAndReset, getBufferedTranscript, isRecording, notifyReady, clearCommitFinalWait, resetTranscriptRefs, setAudioCaptureEnabled, speechStatusCallback]);
|
|
576
|
+
(0, _react.useEffect)(() => {
|
|
577
|
+
if (!openaiPrewarmOnMount || didPrewarmRef.current) {
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
didPrewarmRef.current = true;
|
|
581
|
+
ensureNativeWebRtcSession().then(() => {
|
|
582
|
+
notifyReady(true);
|
|
583
|
+
}).catch(error => {
|
|
584
|
+
emitError(error);
|
|
585
|
+
});
|
|
586
|
+
}, [emitError, ensureNativeWebRtcSession, notifyReady, openaiPrewarmOnMount]);
|
|
587
|
+
(0, _react.useEffect)(() => {
|
|
588
|
+
if (shouldListen && !isRecording) {
|
|
589
|
+
startRecording();
|
|
590
|
+
} else if (!shouldListen && isRecording) {
|
|
591
|
+
stopRecording();
|
|
592
|
+
}
|
|
593
|
+
}, [isRecording, shouldListen, startRecording, stopRecording]);
|
|
594
|
+
(0, _react.useEffect)(() => {
|
|
595
|
+
return () => {
|
|
596
|
+
notifyReady(false);
|
|
597
|
+
clearCommitFinalWait();
|
|
598
|
+
setAudioCaptureEnabled(false);
|
|
599
|
+
cleanup();
|
|
600
|
+
};
|
|
601
|
+
}, [cleanup, notifyReady, clearCommitFinalWait, setAudioCaptureEnabled]);
|
|
602
|
+
return /*#__PURE__*/_react.default.createElement(_reactNative.View, null);
|
|
603
|
+
};
|
|
604
|
+
exports.OpenAINativeSpeechRecognizer = OpenAINativeSpeechRecognizer;
|
|
605
|
+
function extractDeltaText(payload) {
|
|
606
|
+
const type = String(payload?.type || "");
|
|
607
|
+
if (!type.includes("delta")) return "";
|
|
608
|
+
const candidates = [payload?.delta, payload?.text_delta, payload?.transcript_delta, payload?.item?.content?.[0]?.transcript];
|
|
609
|
+
for (const value of candidates) {
|
|
610
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
611
|
+
}
|
|
612
|
+
return "";
|
|
613
|
+
}
|
|
614
|
+
function extractCompletedText(payload) {
|
|
615
|
+
const type = String(payload?.type || "");
|
|
616
|
+
if (!type.includes("completed")) return "";
|
|
617
|
+
const candidates = [payload?.transcript, payload?.text, payload?.item?.content?.[0]?.transcript, payload?.item?.transcript];
|
|
618
|
+
for (const value of candidates) {
|
|
619
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
620
|
+
}
|
|
621
|
+
return "";
|
|
622
|
+
}
|
|
623
|
+
function extractItemId(payload) {
|
|
624
|
+
const candidates = [payload?.item_id, payload?.item?.id];
|
|
625
|
+
for (const value of candidates) {
|
|
626
|
+
if (typeof value === "string" && value.trim()) {
|
|
627
|
+
return value.trim();
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
return null;
|
|
631
|
+
}
|
|
632
|
+
function isCommitBufferTooSmallError(message) {
|
|
633
|
+
const normalized = message.toLowerCase();
|
|
634
|
+
return normalized.includes("input audio buffer") && normalized.includes("buffer too small");
|
|
635
|
+
}
|
|
636
|
+
function isSessionDurationLimitError(message) {
|
|
637
|
+
const normalized = message.toLowerCase();
|
|
638
|
+
return normalized.includes("session") && (normalized.includes("maximum duration") || normalized.includes("max duration"));
|
|
639
|
+
}
|
|
640
|
+
function isOpenAINativeSpeechAvailable() {
|
|
641
|
+
return (_reactNative.Platform.OS === "ios" || _reactNative.Platform.OS === "android") && !!nativeWebRTC?.RTCPeerConnection && !!nativeWebRTC?.mediaDevices?.getUserMedia;
|
|
642
|
+
}
|
|
643
|
+
function getOpenAINativeSpeechCapabilities() {
|
|
644
|
+
return {
|
|
645
|
+
available: isOpenAINativeSpeechAvailable(),
|
|
646
|
+
platform: _reactNative.Platform.OS,
|
|
647
|
+
supportsServerVAD: true,
|
|
648
|
+
transport: "webrtc",
|
|
649
|
+
requiresWebRTCDependency: true
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
var _default = exports.default = OpenAINativeSpeechRecognizer;
|
|
653
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVXaWxkY2FyZCIsInJlcXVpcmUiLCJfcmVhY3ROYXRpdmUiLCJfbG9nZ2VyIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsIl9ncm9xVHJhbnNjcmlwdGlvbiIsImUiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsInQiLCJXZWFrTWFwIiwiciIsIm4iLCJvIiwiaSIsImYiLCJfX3Byb3RvX18iLCJoYXMiLCJnZXQiLCJzZXQiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJPYmplY3QiLCJkZWZpbmVQcm9wZXJ0eSIsImdldE93blByb3BlcnR5RGVzY3JpcHRvciIsIm93bktleXMiLCJrZXlzIiwiZ2V0T3duUHJvcGVydHlTeW1ib2xzIiwiZmlsdGVyIiwiZW51bWVyYWJsZSIsInB1c2giLCJhcHBseSIsIl9vYmplY3RTcHJlYWQiLCJhcmd1bWVudHMiLCJsZW5ndGgiLCJmb3JFYWNoIiwiX2RlZmluZVByb3BlcnR5IiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9ycyIsImRlZmluZVByb3BlcnRpZXMiLCJfdG9Qcm9wZXJ0eUtleSIsInZhbHVlIiwiY29uZmlndXJhYmxlIiwid3JpdGFibGUiLCJfdG9QcmltaXRpdmUiLCJTeW1ib2wiLCJ0b1ByaW1pdGl2ZSIsIlR5cGVFcnJvciIsIlN0cmluZyIsIk51bWJlciIsImxvYWRSZWFjdE5hdGl2ZVdlYlJUQyIsIm1vZHVsZSIsInJlc29sdmVkIiwiUlRDUGVlckNvbm5lY3Rpb24iLCJtZWRpYURldmljZXMiLCJnZXRVc2VyTWVkaWEiLCJuYXRpdmVXZWJSVEMiLCJERUZBVUxUX1JFQUxUSU1FX01PREVMIiwiREVGQVVMVF9SRUFMVElNRV9XRUJSVENfVVJMIiwiREFUQV9DSEFOTkVMX09QRU5fVElNRU9VVF9NUyIsIk9wZW5BSU5hdGl2ZVNwZWVjaFJlY29nbml6ZXIiLCJzaG91bGRMaXN0ZW4iLCJzcGVlY2hTdGF0dXNDYWxsYmFjayIsInNwZWVjaFJlc3VsdENhbGxiYWNrIiwic3BlZWNoVHJhbnNsYXRpb25DYWxsYmFjayIsInNwZWVjaFJlYWR5Q2FsbGJhY2siLCJjbGllbnRTZWNyZXQiLCJvcGVuYWlUcmFuc2NyaXB0aW9uU2Vzc2lvbkVuZHBvaW50Iiwib3BlbmFpVHJhbnNsYXRpb25FbmRwb2ludCIsIm9wZW5haVJlYWx0aW1lV2ViUnRjVXJsIiwib3BlbmFpUmVhbHRpbWVNb2RlbCIsIm9wZW5haVRyYW5zbGF0aW9uTW9kZWwiLCJvcGVuYWlWYWRFbmFibGVkIiwib3BlbmFpQXV0b1N0b3BPblZhZFNpbGVuY2UiLCJvcGVuYWlWYWRUaHJlc2hvbGQiLCJvcGVuYWlWYWRQcmVmaXhQYWRkaW5nTXMiLCJvcGVuYWlWYWRTaWxlbmNlRHVyYXRpb25NcyIsIm9wZW5haVZhZElkbGVUaW1lb3V0TXMiLCJvcGVuYWlQcmV3YXJtT25Nb3VudCIsImxhbmd1YWdlIiwicmVxdWVzdENvbnRleHRQcm92aWRlciIsIm9uRXJyb3IiLCJwcm94eUF1dGhUb2tlbiIsImlzUmVjb3JkaW5nIiwic2V0SXNSZWNvcmRpbmciLCJ1c2VTdGF0ZSIsInNlc3Npb25SZWNvdmVyeVRva2VuIiwic2V0U2Vzc2lvblJlY292ZXJ5VG9rZW4iLCJwY1JlZiIsInVzZVJlZiIsImRhdGFDaGFubmVsUmVmIiwic3RyZWFtUmVmIiwic2Vzc2lvbkluaXRSZWYiLCJmaW5hbFRyYW5zY3JpcHRSZWYiLCJpbnRlcmltVHJhbnNjcmlwdFJlZiIsInN0b3BJbkZsaWdodFJlZiIsImZpbmFsaXplZFJlZiIsImF3YWl0aW5nQ29tbWl0RmluYWxSZWYiLCJjb21taXRGaW5hbFRpbWVvdXRSZWYiLCJkaWRQcmV3YXJtUmVmIiwiaXNSZWNvcmRpbmdSZWYiLCJzaG91bGRMaXN0ZW5SZWYiLCJvcGVuYWlQcmV3YXJtT25Nb3VudFJlZiIsInNlc3Npb25SZWNvdmVyeU1vZGVSZWYiLCJzZXNzaW9uUmVjb3ZlcnlJbkZsaWdodFJlZiIsInN1cHByZXNzZWRDaGFubmVsRXJyb3JSZWYiLCJlbWl0RXJyb3IiLCJ1c2VDYWxsYmFjayIsImVycm9yIiwiZXJyIiwiRXJyb3IiLCJsb2dnZXIiLCJidWlsZFR1cm5EZXRlY3Rpb24iLCJ0eXBlIiwidGhyZXNob2xkIiwicHJlZml4X3BhZGRpbmdfbXMiLCJzaWxlbmNlX2R1cmF0aW9uX21zIiwid2FpdEZvckRhdGFDaGFubmVsT3BlbiIsImNoYW5uZWwiLCJyZWFkeVN0YXRlIiwic3RhcnQiLCJEYXRlIiwibm93IiwiUHJvbWlzZSIsInJlc29sdmUiLCJzZXRUaW1lb3V0IiwicmVzZXRUcmFuc2NyaXB0UmVmcyIsImN1cnJlbnQiLCJnZXRCdWZmZXJlZFRyYW5zY3JpcHQiLCJ0cmltIiwiY2xlYXJDb21taXRGaW5hbFdhaXQiLCJjbGVhclRpbWVvdXQiLCJub3RpZnlSZWFkeSIsInJlYWR5IiwidXNlRWZmZWN0Iiwic2V0QXVkaW9DYXB0dXJlRW5hYmxlZCIsImVuYWJsZWQiLCJzdHJlYW0iLCJnZXRUcmFja3MiLCJ0cmFja3MiLCJ0cmFjayIsImtpbmQiLCJ3YXJuIiwiaGFuZGxlRXhwaXJlZFNlc3Npb24iLCJwYyIsImNsb3NlIiwic3RvcCIsImNsZWFyUmVhbHRpbWVJbnB1dEJ1ZmZlciIsInJlYXNvbiIsInNlbmQiLCJKU09OIiwic3RyaW5naWZ5IiwiZGVidWciLCJnZXRSZXF1ZXN0Q29udGV4dEhlYWRlcnMiLCJjb250ZXh0IiwiaGVhZGVycyIsInRocmVhZElkIiwidHVybklkIiwic2Vzc2lvbklkIiwidW5kZWZpbmVkIiwic2VudHJ5VHJhY2UiLCJiYWdnYWdlIiwidHJhbnNsYXRlVG9FbmdsaXNoIiwidGV4dCIsImlucHV0IiwidG9Mb3dlckNhc2UiLCJzdGFydHNXaXRoIiwiQXV0aG9yaXphdGlvbiIsInJlc3BvbnNlIiwiZmV0Y2giLCJtZXRob2QiLCJib2R5Iiwic291cmNlTGFuZ3VhZ2UiLCJtb2RlbCIsIm9rIiwiY2F0Y2giLCJzdGF0dXMiLCJwYXlsb2FkIiwianNvbiIsInRyYW5zbGF0ZWQiLCJlbWl0RmluYWwiLCJmaW5hbFRleHQiLCJwYXJzZVRleHQiLCJmaW5hbGl6ZUFuZFJlc2V0IiwiaGFuZGxlTWVzc2FnZSIsImFjY2VwdHNUcmFuc2NyaXB0Iiwic2hvdWxkUHVibGlzaEludGVyaW0iLCJkZWx0YSIsImV4dHJhY3REZWx0YVRleHQiLCJjb21wbGV0ZWQiLCJleHRyYWN0Q29tcGxldGVkVGV4dCIsIm1lcmdlVHJhbnNjcmlwdFBhcnRzIiwibG9va3NDb21wbGV0ZWQiLCJpbmNsdWRlcyIsInBhdXNlVHJhbnNjcmlwdCIsInN0YXJ0TmF0aXZlV2ViUnRjU2Vzc2lvbiIsInRva2VuIiwid2VicnRjIiwiYXVkaW8iLCJ2aWRlbyIsImFkZFRyYWNrIiwiZGF0YUNoYW5uZWwiLCJjcmVhdGVEYXRhQ2hhbm5lbCIsIm9ub3BlbiIsIm9ubWVzc2FnZSIsImV2ZW50IiwicGFyc2UiLCJkYXRhIiwibWVzc2FnZSIsImlzQ29tbWl0QnVmZmVyVG9vU21hbGxFcnJvciIsImlzU2Vzc2lvbkR1cmF0aW9uTGltaXRFcnJvciIsIm9uZXJyb3IiLCJvbmNsb3NlIiwib2ZmZXIiLCJjcmVhdGVPZmZlciIsInNldExvY2FsRGVzY3JpcHRpb24iLCJzZHAiLCJhbnN3ZXJTZHAiLCJzZXRSZW1vdGVEZXNjcmlwdGlvbiIsImdldEVwaGVtZXJhbFRva2VuIiwiaW5wdXRfYXVkaW9fZm9ybWF0IiwiaW5wdXRfYXVkaW9fdHJhbnNjcmlwdGlvbiIsInR1cm5fZGV0ZWN0aW9uIiwiY2xpZW50X3NlY3JldCIsImhhc1JldXNhYmxlU2Vzc2lvbiIsImVuc3VyZU5hdGl2ZVdlYlJ0Y1Nlc3Npb24iLCJjbGVhbnVwIiwiY2FuY2VsbGVkIiwicmVjb3ZlcnlNb2RlIiwic3RhcnRSZWNvcmRpbmciLCJyZXVzaW5nV2FybVNlc3Npb24iLCJzdG9wUmVjb3JkaW5nIiwiYnVmZmVyZWQiLCJ0aGVuIiwiY3JlYXRlRWxlbWVudCIsIlZpZXciLCJleHBvcnRzIiwiY2FuZGlkYXRlcyIsInRleHRfZGVsdGEiLCJ0cmFuc2NyaXB0X2RlbHRhIiwiaXRlbSIsImNvbnRlbnQiLCJ0cmFuc2NyaXB0IiwiZXh0cmFjdEl0ZW1JZCIsIml0ZW1faWQiLCJpZCIsIm5vcm1hbGl6ZWQiLCJpc09wZW5BSU5hdGl2ZVNwZWVjaEF2YWlsYWJsZSIsIlBsYXRmb3JtIiwiT1MiLCJnZXRPcGVuQUlOYXRpdmVTcGVlY2hDYXBhYmlsaXRpZXMiLCJhdmFpbGFibGUiLCJwbGF0Zm9ybSIsInN1cHBvcnRzU2VydmVyVkFEIiwidHJhbnNwb3J0IiwicmVxdWlyZXNXZWJSVENEZXBlbmRlbmN5IiwiX2RlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvc3BlZWNoLXJlY29nbml0aW9uL3NwZWVjaC1yZWNvZ25pdGlvbi1vcGVuYWktbmF0aXZlLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUmVhY3QsIHsgdXNlQ2FsbGJhY2ssIHVzZUVmZmVjdCwgdXNlUmVmLCB1c2VTdGF0ZSB9IGZyb20gXCJyZWFjdFwiO1xuaW1wb3J0IHsgUGxhdGZvcm0sIFZpZXcgfSBmcm9tIFwicmVhY3QtbmF0aXZlXCI7XG5pbXBvcnQgbG9nZ2VyIGZyb20gXCIuLi9sb2dnZXJcIjtcbmltcG9ydCB7IG1lcmdlVHJhbnNjcmlwdFBhcnRzIH0gZnJvbSBcIi4vdXRpbHMvZ3JvcS10cmFuc2NyaXB0aW9uXCI7XG5cbnR5cGUgUmVhY3ROYXRpdmVXZWJSVENNb2R1bGUgPSB7XG4gIFJUQ1BlZXJDb25uZWN0aW9uOiBuZXcgKC4uLmFyZ3M6IGFueVtdKSA9PiBhbnk7XG4gIG1lZGlhRGV2aWNlczoge1xuICAgIGdldFVzZXJNZWRpYTogKGNvbnN0cmFpbnRzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+KSA9PiBQcm9taXNlPGFueT47XG4gIH07XG59O1xuXG5mdW5jdGlvbiBsb2FkUmVhY3ROYXRpdmVXZWJSVEMoKTogUmVhY3ROYXRpdmVXZWJSVENNb2R1bGUgfCBudWxsIHtcbiAgdHJ5IHtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXZhci1yZXF1aXJlc1xuICAgIGNvbnN0IG1vZHVsZSA9IHJlcXVpcmUoXCJyZWFjdC1uYXRpdmUtd2VicnRjXCIpO1xuICAgIGNvbnN0IHJlc29sdmVkID0gbW9kdWxlPy5kZWZhdWx0IHx8IG1vZHVsZTtcbiAgICBpZiAoXG4gICAgICByZXNvbHZlZD8uUlRDUGVlckNvbm5lY3Rpb24gJiZcbiAgICAgIHJlc29sdmVkPy5tZWRpYURldmljZXM/LmdldFVzZXJNZWRpYVxuICAgICkge1xuICAgICAgcmV0dXJuIHJlc29sdmVkIGFzIFJlYWN0TmF0aXZlV2ViUlRDTW9kdWxlO1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbn1cblxuY29uc3QgbmF0aXZlV2ViUlRDID0gbG9hZFJlYWN0TmF0aXZlV2ViUlRDKCk7XG5jb25zdCBERUZBVUxUX1JFQUxUSU1FX01PREVMID0gXCJncHQtNG8tdHJhbnNjcmliZVwiO1xuY29uc3QgREVGQVVMVF9SRUFMVElNRV9XRUJSVENfVVJMID1cbiAgXCJodHRwczovL2FwaS5vcGVuYWkuY29tL3YxL3JlYWx0aW1lP2ludGVudD10cmFuc2NyaXB0aW9uXCI7XG5jb25zdCBEQVRBX0NIQU5ORUxfT1BFTl9USU1FT1VUX01TID0gNjAwMDtcblxuZXhwb3J0IGludGVyZmFjZSBPcGVuQUlOYXRpdmVTcGVlY2hSZWNvZ25pemVyUHJvcHMge1xuICBzaG91bGRMaXN0ZW46IGJvb2xlYW47XG4gIHNwZWVjaFN0YXR1c0NhbGxiYWNrOiAoc3RhdHVzOiBib29sZWFuLCB0cmFuc2NyaXB0OiBzdHJpbmcpID0+IHZvaWQ7XG4gIHNwZWVjaFJlc3VsdENhbGxiYWNrOiAocmVzdWx0OiBzdHJpbmcpID0+IHZvaWQ7XG4gIHNwZWVjaFRyYW5zbGF0aW9uQ2FsbGJhY2s/OiAodHJhbnNsYXRpb246IHN0cmluZykgPT4gdm9pZDtcbiAgc3BlZWNoUmVhZHlDYWxsYmFjaz86IChyZWFkeTogYm9vbGVhbikgPT4gdm9pZDtcbiAgY2xpZW50U2VjcmV0Pzogc3RyaW5nO1xuICBvcGVuYWlUcmFuc2NyaXB0aW9uU2Vzc2lvbkVuZHBvaW50OiBzdHJpbmc7XG4gIG9wZW5haVRyYW5zbGF0aW9uRW5kcG9pbnQ/OiBzdHJpbmc7XG4gIG9wZW5haVJlYWx0aW1lV2ViUnRjVXJsPzogc3RyaW5nO1xuICBvcGVuYWlSZWFsdGltZU1vZGVsPzogXCJncHQtNG8tdHJhbnNjcmliZVwiIHwgXCJncHQtNG8tbWluaS10cmFuc2NyaWJlXCI7XG4gIG9wZW5haVRyYW5zbGF0aW9uTW9kZWw/OiBzdHJpbmc7XG4gIG9wZW5haVZhZEVuYWJsZWQ/OiBib29sZWFuO1xuICBvcGVuYWlBdXRvU3RvcE9uVmFkU2lsZW5jZT86IGJvb2xlYW47XG4gIG9wZW5haVZhZFRocmVzaG9sZD86IG51bWJlcjtcbiAgb3BlbmFpVmFkUHJlZml4UGFkZGluZ01zPzogbnVtYmVyO1xuICBvcGVuYWlWYWRTaWxlbmNlRHVyYXRpb25Ncz86IG51bWJlcjtcbiAgb3BlbmFpVmFkSWRsZVRpbWVvdXRNcz86IG51bWJlcjtcbiAgb3BlbmFpUHJld2FybU9uTW91bnQ/OiBib29sZWFuO1xuICBsYW5ndWFnZT86IHN0cmluZztcbiAgcmVxdWVzdENvbnRleHRQcm92aWRlcj86ICgpID0+XG4gICAgfCB7XG4gICAgICAgIHRocmVhZElkPzogc3RyaW5nIHwgbnVsbDtcbiAgICAgICAgdHVybklkPzogc3RyaW5nIHwgbnVsbDtcbiAgICAgICAgc2Vzc2lvbklkPzogc3RyaW5nIHwgbnVtYmVyIHwgbnVsbDtcbiAgICAgICAgc2VudHJ5VHJhY2U/OiBzdHJpbmcgfCBudWxsO1xuICAgICAgICBiYWdnYWdlPzogc3RyaW5nIHwgbnVsbDtcbiAgICAgIH1cbiAgICB8IG51bGxcbiAgICB8IHVuZGVmaW5lZDtcbiAgb25FcnJvcj86IChlcnJvcjogRXJyb3IpID0+IHZvaWQ7XG59XG5cbmV4cG9ydCBjb25zdCBPcGVuQUlOYXRpdmVTcGVlY2hSZWNvZ25pemVyOiBSZWFjdC5GQzxcbiAgT3BlbkFJTmF0aXZlU3BlZWNoUmVjb2duaXplclByb3BzXG4+ID0gKHtcbiAgc2hvdWxkTGlzdGVuLFxuICBzcGVlY2hTdGF0dXNDYWxsYmFjayxcbiAgc3BlZWNoUmVzdWx0Q2FsbGJhY2ssXG4gIHNwZWVjaFRyYW5zbGF0aW9uQ2FsbGJhY2ssXG4gIHNwZWVjaFJlYWR5Q2FsbGJhY2ssXG4gIGNsaWVudFNlY3JldCxcbiAgb3BlbmFpVHJhbnNjcmlwdGlvblNlc3Npb25FbmRwb2ludCxcbiAgb3BlbmFpVHJhbnNsYXRpb25FbmRwb2ludCxcbiAgb3BlbmFpUmVhbHRpbWVXZWJSdGNVcmwgPSBERUZBVUxUX1JFQUxUSU1FX1dFQlJUQ19VUkwsXG4gIG9wZW5haVJlYWx0aW1lTW9kZWwgPSBERUZBVUxUX1JFQUxUSU1FX01PREVMLFxuICBvcGVuYWlUcmFuc2xhdGlvbk1vZGVsID0gXCJncHQtNC4xLW1pbmlcIixcbiAgb3BlbmFpVmFkRW5hYmxlZCA9IHRydWUsXG4gIG9wZW5haUF1dG9TdG9wT25WYWRTaWxlbmNlID0gZmFsc2UsXG4gIG9wZW5haVZhZFRocmVzaG9sZCA9IDAuNyxcbiAgb3BlbmFpVmFkUHJlZml4UGFkZGluZ01zID0gNDAwLFxuICBvcGVuYWlWYWRTaWxlbmNlRHVyYXRpb25NcyA9IDEwMDAsXG4gIG9wZW5haVZhZElkbGVUaW1lb3V0TXMgPSA2MDAwLFxuICBvcGVuYWlQcmV3YXJtT25Nb3VudCA9IGZhbHNlLFxuICBsYW5ndWFnZSA9IFwiZW5cIixcbiAgcmVxdWVzdENvbnRleHRQcm92aWRlcixcbiAgb25FcnJvcixcbn0pID0+IHtcbiAgY29uc3QgcHJveHlBdXRoVG9rZW4gPSBjbGllbnRTZWNyZXQ7XG4gIGNvbnN0IFtpc1JlY29yZGluZywgc2V0SXNSZWNvcmRpbmddID0gdXNlU3RhdGUoZmFsc2UpO1xuICBjb25zdCBbc2Vzc2lvblJlY292ZXJ5VG9rZW4sIHNldFNlc3Npb25SZWNvdmVyeVRva2VuXSA9IHVzZVN0YXRlKDApO1xuICBjb25zdCBwY1JlZiA9IHVzZVJlZjxhbnk+KG51bGwpO1xuICBjb25zdCBkYXRhQ2hhbm5lbFJlZiA9IHVzZVJlZjxhbnk+KG51bGwpO1xuICBjb25zdCBzdHJlYW1SZWYgPSB1c2VSZWY8YW55PihudWxsKTtcbiAgY29uc3Qgc2Vzc2lvbkluaXRSZWYgPSB1c2VSZWY8UHJvbWlzZTx2b2lkPiB8IG51bGw+KG51bGwpO1xuICBjb25zdCBmaW5hbFRyYW5zY3JpcHRSZWYgPSB1c2VSZWYoXCJcIik7XG4gIGNvbnN0IGludGVyaW1UcmFuc2NyaXB0UmVmID0gdXNlUmVmKFwiXCIpO1xuICBjb25zdCBzdG9wSW5GbGlnaHRSZWYgPSB1c2VSZWYoZmFsc2UpO1xuICBjb25zdCBmaW5hbGl6ZWRSZWYgPSB1c2VSZWYoZmFsc2UpO1xuICBjb25zdCBhd2FpdGluZ0NvbW1pdEZpbmFsUmVmID0gdXNlUmVmKGZhbHNlKTtcbiAgY29uc3QgY29tbWl0RmluYWxUaW1lb3V0UmVmID0gdXNlUmVmPFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgbnVsbD4obnVsbCk7XG4gIGNvbnN0IGRpZFByZXdhcm1SZWYgPSB1c2VSZWYoZmFsc2UpO1xuICBjb25zdCBpc1JlY29yZGluZ1JlZiA9IHVzZVJlZihmYWxzZSk7XG4gIGNvbnN0IHNob3VsZExpc3RlblJlZiA9IHVzZVJlZihzaG91bGRMaXN0ZW4pO1xuICBjb25zdCBvcGVuYWlQcmV3YXJtT25Nb3VudFJlZiA9IHVzZVJlZihvcGVuYWlQcmV3YXJtT25Nb3VudCk7XG4gIGNvbnN0IHNlc3Npb25SZWNvdmVyeU1vZGVSZWYgPSB1c2VSZWY8XCJsaXN0ZW5cIiB8IFwicHJld2FybVwiIHwgbnVsbD4obnVsbCk7XG4gIGNvbnN0IHNlc3Npb25SZWNvdmVyeUluRmxpZ2h0UmVmID0gdXNlUmVmKGZhbHNlKTtcbiAgY29uc3Qgc3VwcHJlc3NlZENoYW5uZWxFcnJvclJlZiA9IHVzZVJlZjxhbnk+KG51bGwpO1xuXG4gIGNvbnN0IGVtaXRFcnJvciA9IHVzZUNhbGxiYWNrKFxuICAgIChlcnJvcjogdW5rbm93bikgPT4ge1xuICAgICAgY29uc3QgZXJyID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yIDogbmV3IEVycm9yKFN0cmluZyhlcnJvcikpO1xuICAgICAgbG9nZ2VyLmVycm9yKFwiW09wZW5BSSBOYXRpdmUgU1JdIGVycm9yOlwiLCBlcnIpO1xuICAgICAgb25FcnJvcj8uKGVycik7XG4gICAgfSxcbiAgICBbb25FcnJvcl1cbiAgKTtcblxuICBjb25zdCBidWlsZFR1cm5EZXRlY3Rpb24gPSB1c2VDYWxsYmFjaygoKSA9PiB7XG4gICAgaWYgKCFvcGVuYWlWYWRFbmFibGVkKSByZXR1cm4gbnVsbDtcbiAgICByZXR1cm4ge1xuICAgICAgdHlwZTogXCJzZXJ2ZXJfdmFkXCIsXG4gICAgICB0aHJlc2hvbGQ6IG9wZW5haVZhZFRocmVzaG9sZCxcbiAgICAgIHByZWZpeF9wYWRkaW5nX21zOiBvcGVuYWlWYWRQcmVmaXhQYWRkaW5nTXMsXG4gICAgICBzaWxlbmNlX2R1cmF0aW9uX21zOiBvcGVuYWlWYWRTaWxlbmNlRHVyYXRpb25NcyxcbiAgICB9O1xuICB9LCBbXG4gICAgb3BlbmFpVmFkRW5hYmxlZCxcbiAgICBvcGVuYWlWYWRUaHJlc2hvbGQsXG4gICAgb3BlbmFpVmFkUHJlZml4UGFkZGluZ01zLFxuICAgIG9wZW5haVZhZFNpbGVuY2VEdXJhdGlvbk1zLFxuICBdKTtcblxuICBjb25zdCB3YWl0Rm9yRGF0YUNoYW5uZWxPcGVuID0gdXNlQ2FsbGJhY2soXG4gICAgYXN5bmMgKGNoYW5uZWw6IGFueSk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgaWYgKGNoYW5uZWw/LnJlYWR5U3RhdGUgPT09IFwib3BlblwiKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHN0YXJ0ID0gRGF0ZS5ub3coKTtcbiAgICAgIHdoaWxlIChEYXRlLm5vdygpIC0gc3RhcnQgPCBEQVRBX0NIQU5ORUxfT1BFTl9USU1FT1VUX01TKSB7XG4gICAgICAgIGlmIChjaGFubmVsPy5yZWFkeVN0YXRlID09PSBcIm9wZW5cIikge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCA1MCkpO1xuICAgICAgfVxuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgT3BlbkFJIG5hdGl2ZSByZWFsdGltZSBkYXRhIGNoYW5uZWwgZGlkIG5vdCBvcGVuIHdpdGhpbiAke0RBVEFfQ0hBTk5FTF9PUEVOX1RJTUVPVVRfTVN9bXMgKHN0YXRlPSR7U3RyaW5nKFxuICAgICAgICAgIGNoYW5uZWw/LnJlYWR5U3RhdGUgPz8gXCJ1bmtub3duXCJcbiAgICAgICAgKX0pYFxuICAgICAgKTtcbiAgICB9LFxuICAgIFtdXG4gICk7XG5cbiAgY29uc3QgcmVzZXRUcmFuc2NyaXB0UmVmcyA9IHVzZUNhbGxiYWNrKCgpID0+IHtcbiAgICBmaW5hbFRyYW5zY3JpcHRSZWYuY3VycmVudCA9IFwiXCI7XG4gICAgaW50ZXJpbVRyYW5zY3JpcHRSZWYuY3VycmVudCA9IFwiXCI7XG4gICAgZmluYWxpemVkUmVmLmN1cnJlbnQgPSBmYWxzZTtcbiAgfSwgW10pO1xuXG4gIGNvbnN0IGdldEJ1ZmZlcmVkVHJhbnNjcmlwdCA9IHVzZUNhbGxiYWNrKCgpID0+IHtcbiAgICByZXR1cm4gKFxuICAgICAgZmluYWxUcmFuc2NyaXB0UmVmLmN1cnJlbnQgfHxcbiAgICAgIGludGVyaW1UcmFuc2NyaXB0UmVmLmN1cnJlbnRcbiAgICApLnRyaW0oKTtcbiAgfSwgW10pO1xuXG4gIGNvbnN0IGNsZWFyQ29tbWl0RmluYWxXYWl0ID0gdXNlQ2FsbGJhY2soKCkgPT4ge1xuICAgIGF3YWl0aW5nQ29tbWl0RmluYWxSZWYuY3VycmVudCA9IGZhbHNlO1xuICAgIGlmIChjb21taXRGaW5hbFRpbWVvdXRSZWYuY3VycmVudCkge1xuICAgICAgY2xlYXJUaW1lb3V0KGNvbW1pdEZpbmFsVGltZW91dFJlZi5jdXJyZW50KTtcbiAgICAgIGNvbW1pdEZpbmFsVGltZW91dFJlZi5jdXJyZW50ID0gbnVsbDtcbiAgICB9XG4gIH0sIFtdKTtcblxuICBjb25zdCBub3RpZnlSZWFkeSA9IHVzZUNhbGxiYWNrKFxuICAgIChyZWFkeTogYm9vbGVhbikgPT4ge1xuICAgICAgc3BlZWNoUmVhZHlDYWxsYmFjaz8uKHJlYWR5KTtcbiAgICB9LFxuICAgIFtzcGVlY2hSZWFkeUNhbGxiYWNrXVxuICApO1xuXG4gIHVzZUVmZmVjdCgoKSA9PiB7XG4gICAgaXNSZWNvcmRpbmdSZWYuY3VycmVudCA9IGlzUmVjb3JkaW5nO1xuICB9LCBbaXNSZWNvcmRpbmddKTtcblxuICB1c2VFZmZlY3QoKCkgPT4ge1xuICAgIHNob3VsZExpc3RlblJlZi5jdXJyZW50ID0gc2hvdWxkTGlzdGVuO1xuICB9LCBbc2hvdWxkTGlzdGVuXSk7XG5cbiAgdXNlRWZmZWN0KCgpID0+IHtcbiAgICBvcGVuYWlQcmV3YXJtT25Nb3VudFJlZi5jdXJyZW50ID0gb3BlbmFpUHJld2FybU9uTW91bnQ7XG4gIH0sIFtvcGVuYWlQcmV3YXJtT25Nb3VudF0pO1xuXG4gIGNvbnN0IHNldEF1ZGlvQ2FwdHVyZUVuYWJsZWQgPSB1c2VDYWxsYmFjaygoZW5hYmxlZDogYm9vbGVhbikgPT4ge1xuICAgIGNvbnN0IHN0cmVhbSA9IHN0cmVhbVJlZi5jdXJyZW50O1xuICAgIGlmICghc3RyZWFtIHx8IHR5cGVvZiBzdHJlYW0uZ2V0VHJhY2tzICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgdHJhY2tzID0gc3RyZWFtXG4gICAgICAgIC5nZXRUcmFja3MoKVxuICAgICAgICAuZmlsdGVyKCh0cmFjazogYW55KSA9PiB0cmFjaz8ua2luZCA9PT0gXCJhdWRpb1wiKTtcbiAgICAgIHRyYWNrcy5mb3JFYWNoKCh0cmFjazogYW55KSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgdHJhY2suZW5hYmxlZCA9IGVuYWJsZWQ7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgbG9nZ2VyLndhcm4oXCJbT3BlbkFJIE5hdGl2ZSBTUl0gdG9nZ2xlIGF1ZGlvIHRyYWNrIHdhcm5pbmc6XCIsIGVycm9yKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci53YXJuKFwiW09wZW5BSSBOYXRpdmUgU1JdIGVudW1lcmF0ZSBhdWRpbyB0cmFja3Mgd2FybmluZzpcIiwgZXJyb3IpO1xuICAgIH1cbiAgfSwgW10pO1xuXG4gIGNvbnN0IGhhbmRsZUV4cGlyZWRTZXNzaW9uID0gdXNlQ2FsbGJhY2soXG4gICAgKGNoYW5uZWw6IGFueSwgcGM6IGFueSkgPT4ge1xuICAgICAgaWYgKHNlc3Npb25SZWNvdmVyeUluRmxpZ2h0UmVmLmN1cnJlbnQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgaWYgKGRhdGFDaGFubmVsUmVmLmN1cnJlbnQgIT09IGNoYW5uZWwpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBzZXNzaW9uUmVjb3ZlcnlJbkZsaWdodFJlZi5jdXJyZW50ID0gdHJ1ZTtcbiAgICAgIHN1cHByZXNzZWRDaGFubmVsRXJyb3JSZWYuY3VycmVudCA9IGNoYW5uZWw7XG4gICAgICBzZXNzaW9uUmVjb3ZlcnlNb2RlUmVmLmN1cnJlbnQgPSBzaG91bGRMaXN0ZW5SZWYuY3VycmVudFxuICAgICAgICA/IFwibGlzdGVuXCJcbiAgICAgICAgOiBvcGVuYWlQcmV3YXJtT25Nb3VudFJlZi5jdXJyZW50XG4gICAgICAgICAgPyBcInByZXdhcm1cIlxuICAgICAgICAgIDogbnVsbDtcblxuICAgICAgY2xlYXJDb21taXRGaW5hbFdhaXQoKTtcbiAgICAgIHJlc2V0VHJhbnNjcmlwdFJlZnMoKTtcbiAgICAgIHNldEF1ZGlvQ2FwdHVyZUVuYWJsZWQoZmFsc2UpO1xuICAgICAgc2Vzc2lvbkluaXRSZWYuY3VycmVudCA9IG51bGw7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGNoYW5uZWw/LmNsb3NlPy4oKTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGxvZ2dlci53YXJuKFwiW09wZW5BSSBOYXRpdmUgU1JdIGNsb3NlIGRhdGEgY2hhbm5lbCB3YXJuaW5nOlwiLCBlcnJvcik7XG4gICAgICB9XG4gICAgICB0cnkge1xuICAgICAgICBwYz8uY2xvc2U/LigpO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgbG9nZ2VyLndhcm4oXCJbT3BlbkFJIE5hdGl2ZSBTUl0gY2xvc2UgcGVlciB3YXJuaW5nOlwiLCBlcnJvcik7XG4gICAgICB9XG4gICAgICB0cnkge1xuICAgICAgICBzdHJlYW1SZWYuY3VycmVudD8uZ2V0VHJhY2tzPy4oKS5mb3JFYWNoKCh0cmFjazogYW55KSA9PiB0cmFjay5zdG9wPy4oKSk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2dnZXIud2FybihcIltPcGVuQUkgTmF0aXZlIFNSXSBzdG9wIHN0cmVhbSB3YXJuaW5nOlwiLCBlcnJvcik7XG4gICAgICB9XG5cbiAgICAgIGlmIChkYXRhQ2hhbm5lbFJlZi5jdXJyZW50ID09PSBjaGFubmVsKSB7XG4gICAgICAgIGRhdGFDaGFubmVsUmVmLmN1cnJlbnQgPSBudWxsO1xuICAgICAgfVxuICAgICAgaWYgKHBjUmVmLmN1cnJlbnQgPT09IHBjKSB7XG4gICAgICAgIHBjUmVmLmN1cnJlbnQgPSBudWxsO1xuICAgICAgfVxuICAgICAgc3RyZWFtUmVmLmN1cnJlbnQgPSBudWxsO1xuXG4gICAgICBzZXRJc1JlY29yZGluZyhmYWxzZSk7XG4gICAgICBub3RpZnlSZWFkeShmYWxzZSk7XG4gICAgICBzcGVlY2hTdGF0dXNDYWxsYmFjayhmYWxzZSwgXCJcIik7XG5cbiAgICAgIGlmIChzZXNzaW9uUmVjb3ZlcnlNb2RlUmVmLmN1cnJlbnQpIHtcbiAgICAgICAgc2V0U2Vzc2lvblJlY292ZXJ5VG9rZW4oKHZhbHVlKSA9PiB2YWx1ZSArIDEpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc2Vzc2lvblJlY292ZXJ5SW5GbGlnaHRSZWYuY3VycmVudCA9IGZhbHNlO1xuICAgICAgICBzdXBwcmVzc2VkQ2hhbm5lbEVycm9yUmVmLmN1cnJlbnQgPSBudWxsO1xuICAgICAgfVxuICAgIH0sXG4gICAgW1xuICAgICAgY2xlYXJDb21taXRGaW5hbFdhaXQsXG4gICAgICBub3RpZnlSZWFkeSxcbiAgICAgIHJlc2V0VHJhbnNjcmlwdFJlZnMsXG4gICAgICBzZXRBdWRpb0NhcHR1cmVFbmFibGVkLFxuICAgICAgc3BlZWNoU3RhdHVzQ2FsbGJhY2ssXG4gICAgXVxuICApO1xuXG4gIGNvbnN0IGNsZWFyUmVhbHRpbWVJbnB1dEJ1ZmZlciA9IHVzZUNhbGxiYWNrKChyZWFzb246IHN0cmluZykgPT4ge1xuICAgIGlmIChkYXRhQ2hhbm5lbFJlZi5jdXJyZW50Py5yZWFkeVN0YXRlICE9PSBcIm9wZW5cIikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgZGF0YUNoYW5uZWxSZWYuY3VycmVudC5zZW5kKFxuICAgICAgICBKU09OLnN0cmluZ2lmeSh7IHR5cGU6IFwiaW5wdXRfYXVkaW9fYnVmZmVyLmNsZWFyXCIgfSlcbiAgICAgICk7XG4gICAgICBsb2dnZXIuZGVidWcoYFtPcGVuQUkgTmF0aXZlIFNSXSBjbGVhcmVkIGlucHV0IGJ1ZmZlciAoJHtyZWFzb259KWApO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIud2FybihcIltPcGVuQUkgTmF0aXZlIFNSXSBjbGVhciBpbnB1dCBidWZmZXIgd2FybmluZzpcIiwgZXJyb3IpO1xuICAgIH1cbiAgfSwgW10pO1xuXG4gIGNvbnN0IGdldFJlcXVlc3RDb250ZXh0SGVhZGVycyA9IHVzZUNhbGxiYWNrKCgpOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0+IHtcbiAgICBjb25zdCBjb250ZXh0ID0gcmVxdWVzdENvbnRleHRQcm92aWRlcj8uKCk7XG4gICAgaWYgKCFjb250ZXh0KSByZXR1cm4ge307XG5cbiAgICBjb25zdCBoZWFkZXJzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG4gICAgaWYgKGNvbnRleHQudGhyZWFkSWQpIHtcbiAgICAgIGhlYWRlcnNbXCJ4LXRocmVhZC1pZFwiXSA9IFN0cmluZyhjb250ZXh0LnRocmVhZElkKTtcbiAgICB9XG4gICAgaWYgKGNvbnRleHQudHVybklkKSB7XG4gICAgICBoZWFkZXJzW1wieC10dXJuLWlkXCJdID0gU3RyaW5nKGNvbnRleHQudHVybklkKTtcbiAgICB9XG4gICAgaWYgKGNvbnRleHQuc2Vzc2lvbklkICE9PSB1bmRlZmluZWQgJiYgY29udGV4dC5zZXNzaW9uSWQgIT09IG51bGwpIHtcbiAgICAgIGhlYWRlcnNbXCJ4LXZvaWNlLXNlc3Npb24taWRcIl0gPSBTdHJpbmcoY29udGV4dC5zZXNzaW9uSWQpO1xuICAgIH1cbiAgICBpZiAoY29udGV4dC5zZW50cnlUcmFjZSkge1xuICAgICAgaGVhZGVyc1tcInNlbnRyeS10cmFjZVwiXSA9IFN0cmluZyhjb250ZXh0LnNlbnRyeVRyYWNlKTtcbiAgICB9XG4gICAgaWYgKGNvbnRleHQuYmFnZ2FnZSkge1xuICAgICAgaGVhZGVycy5iYWdnYWdlID0gU3RyaW5nKGNvbnRleHQuYmFnZ2FnZSk7XG4gICAgfVxuICAgIHJldHVybiBoZWFkZXJzO1xuICB9LCBbcmVxdWVzdENvbnRleHRQcm92aWRlcl0pO1xuXG4gIGNvbnN0IHRyYW5zbGF0ZVRvRW5nbGlzaCA9IHVzZUNhbGxiYWNrKFxuICAgIGFzeW5jICh0ZXh0OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4gPT4ge1xuICAgICAgY29uc3QgaW5wdXQgPSB0ZXh0LnRyaW0oKTtcbiAgICAgIGlmICghaW5wdXQgfHwgIW9wZW5haVRyYW5zbGF0aW9uRW5kcG9pbnQpIHJldHVybiBcIlwiO1xuICAgICAgaWYgKGxhbmd1YWdlLnRvTG93ZXJDYXNlKCkuc3RhcnRzV2l0aChcImVuXCIpKSByZXR1cm4gXCJcIjtcblxuICAgICAgY29uc3QgaGVhZGVyczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICAgICAgXCJjb250ZW50LXR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4gICAgICAgIC4uLmdldFJlcXVlc3RDb250ZXh0SGVhZGVycygpLFxuICAgICAgfTtcbiAgICAgIGlmIChwcm94eUF1dGhUb2tlbikge1xuICAgICAgICBoZWFkZXJzLkF1dGhvcml6YXRpb24gPSBgQmVhcmVyICR7cHJveHlBdXRoVG9rZW59YDtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChvcGVuYWlUcmFuc2xhdGlvbkVuZHBvaW50LCB7XG4gICAgICAgIG1ldGhvZDogXCJQT1NUXCIsXG4gICAgICAgIGhlYWRlcnMsXG4gICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICB0ZXh0OiBpbnB1dCxcbiAgICAgICAgICBzb3VyY2VMYW5ndWFnZTogbGFuZ3VhZ2UsXG4gICAgICAgICAgbW9kZWw6IG9wZW5haVRyYW5zbGF0aW9uTW9kZWwsXG4gICAgICAgIH0pLFxuICAgICAgfSk7XG4gICAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICAgIGNvbnN0IGJvZHkgPSBhd2FpdCByZXNwb25zZS50ZXh0KCkuY2F0Y2goKCkgPT4gXCJcIik7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgdHJhbnNsYXRpb24gZmFpbGVkICgke3Jlc3BvbnNlLnN0YXR1c30pOiAke2JvZHl9YCk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHBheWxvYWQgPSBhd2FpdCByZXNwb25zZS5qc29uKCkuY2F0Y2goKCkgPT4gbnVsbCk7XG4gICAgICBjb25zdCB0cmFuc2xhdGVkID1cbiAgICAgICAgdHlwZW9mIHBheWxvYWQ/LnRleHQgPT09IFwic3RyaW5nXCIgPyBwYXlsb2FkLnRleHQudHJpbSgpIDogXCJcIjtcbiAgICAgIGlmICh0cmFuc2xhdGVkKSB7XG4gICAgICAgIHNwZWVjaFRyYW5zbGF0aW9uQ2FsbGJhY2s/Lih0cmFuc2xhdGVkKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0cmFuc2xhdGVkO1xuICAgIH0sXG4gICAgW1xuICAgICAgcHJveHlBdXRoVG9rZW4sXG4gICAgICBsYW5ndWFnZSxcbiAgICAgIGdldFJlcXVlc3RDb250ZXh0SGVhZGVycyxcbiAgICAgIG9wZW5haVRyYW5zbGF0aW9uRW5kcG9pbnQsXG4gICAgICBvcGVuYWlUcmFuc2xhdGlvbk1vZGVsLFxuICAgICAgc3BlZWNoVHJhbnNsYXRpb25DYWxsYmFjayxcbiAgICBdXG4gICk7XG5cbiAgY29uc3QgZW1pdEZpbmFsID0gdXNlQ2FsbGJhY2soYXN5bmMgKCkgPT4ge1xuICAgIGlmIChmaW5hbGl6ZWRSZWYuY3VycmVudCkgcmV0dXJuO1xuICAgIGZpbmFsaXplZFJlZi5jdXJyZW50ID0gdHJ1ZTtcblxuICAgIGNvbnN0IGZpbmFsVGV4dCA9IChcbiAgICAgIGZpbmFsVHJhbnNjcmlwdFJlZi5jdXJyZW50IHx8XG4gICAgICBpbnRlcmltVHJhbnNjcmlwdFJlZi5jdXJyZW50XG4gICAgKS50cmltKCk7XG5cbiAgICBsZXQgcGFyc2VUZXh0ID0gZmluYWxUZXh0O1xuICAgIHRyeSB7XG4gICAgICBjb25zdCB0cmFuc2xhdGVkID0gYXdhaXQgdHJhbnNsYXRlVG9FbmdsaXNoKGZpbmFsVGV4dCk7XG4gICAgICBpZiAodHJhbnNsYXRlZCkge1xuICAgICAgICBwYXJzZVRleHQgPSB0cmFuc2xhdGVkO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIud2FybihcIltPcGVuQUkgTmF0aXZlIFNSXSB0cmFuc2xhdGlvbiBmYWlsZWQ6XCIsIGVycm9yKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgc3BlZWNoU3RhdHVzQ2FsbGJhY2soZmFsc2UsIFwiXCIpO1xuICAgICAgaWYgKHBhcnNlVGV4dCkge1xuICAgICAgICBzcGVlY2hSZXN1bHRDYWxsYmFjayhwYXJzZVRleHQpO1xuICAgICAgfVxuICAgIH1cbiAgfSwgW3NwZWVjaFJlc3VsdENhbGxiYWNrLCBzcGVlY2hTdGF0dXNDYWxsYmFjaywgdHJhbnNsYXRlVG9FbmdsaXNoXSk7XG5cbiAgY29uc3QgZmluYWxpemVBbmRSZXNldCA9IHVzZUNhbGxiYWNrKGFzeW5jICgpID0+IHtcbiAgICBjbGVhckNvbW1pdEZpbmFsV2FpdCgpO1xuICAgIGF3YWl0IGVtaXRGaW5hbCgpO1xuICAgIHJlc2V0VHJhbnNjcmlwdFJlZnMoKTtcbiAgfSwgW2NsZWFyQ29tbWl0RmluYWxXYWl0LCBlbWl0RmluYWwsIHJlc2V0VHJhbnNjcmlwdFJlZnNdKTtcblxuICBjb25zdCBoYW5kbGVNZXNzYWdlID0gdXNlQ2FsbGJhY2soXG4gICAgKHBheWxvYWQ6IGFueSkgPT4ge1xuICAgICAgY29uc3QgdHlwZSA9IFN0cmluZyhwYXlsb2FkPy50eXBlIHx8IFwiXCIpO1xuICAgICAgY29uc3QgYWNjZXB0c1RyYW5zY3JpcHQgPVxuICAgICAgICBpc1JlY29yZGluZ1JlZi5jdXJyZW50IHx8IGF3YWl0aW5nQ29tbWl0RmluYWxSZWYuY3VycmVudDtcbiAgICAgIGlmICghYWNjZXB0c1RyYW5zY3JpcHQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzaG91bGRQdWJsaXNoSW50ZXJpbSA9IGlzUmVjb3JkaW5nUmVmLmN1cnJlbnQ7XG4gICAgICBjb25zdCBkZWx0YSA9IGV4dHJhY3REZWx0YVRleHQocGF5bG9hZCk7XG4gICAgICBjb25zdCBjb21wbGV0ZWQgPSBleHRyYWN0Q29tcGxldGVkVGV4dChwYXlsb2FkKTtcblxuICAgICAgaWYgKGRlbHRhKSB7XG4gICAgICAgIGludGVyaW1UcmFuc2NyaXB0UmVmLmN1cnJlbnQgPSBtZXJnZVRyYW5zY3JpcHRQYXJ0cyhcbiAgICAgICAgICBmaW5hbFRyYW5zY3JpcHRSZWYuY3VycmVudCxcbiAgICAgICAgICBkZWx0YVxuICAgICAgICApO1xuICAgICAgICBpZiAoc2hvdWxkUHVibGlzaEludGVyaW0pIHtcbiAgICAgICAgICBzcGVlY2hTdGF0dXNDYWxsYmFjayh0cnVlLCBpbnRlcmltVHJhbnNjcmlwdFJlZi5jdXJyZW50KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoY29tcGxldGVkKSB7XG4gICAgICAgIGZpbmFsVHJhbnNjcmlwdFJlZi5jdXJyZW50ID0gbWVyZ2VUcmFuc2NyaXB0UGFydHMoXG4gICAgICAgICAgZmluYWxUcmFuc2NyaXB0UmVmLmN1cnJlbnQsXG4gICAgICAgICAgY29tcGxldGVkXG4gICAgICAgICk7XG4gICAgICAgIGludGVyaW1UcmFuc2NyaXB0UmVmLmN1cnJlbnQgPSBmaW5hbFRyYW5zY3JpcHRSZWYuY3VycmVudDtcbiAgICAgICAgaWYgKHNob3VsZFB1Ymxpc2hJbnRlcmltKSB7XG4gICAgICAgICAgc3BlZWNoU3RhdHVzQ2FsbGJhY2sodHJ1ZSwgZmluYWxUcmFuc2NyaXB0UmVmLmN1cnJlbnQpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGxvb2tzQ29tcGxldGVkID0gISFjb21wbGV0ZWQgfHwgdHlwZS5pbmNsdWRlcyhcImNvbXBsZXRlZFwiKTtcbiAgICAgIGlmIChcbiAgICAgICAgYXdhaXRpbmdDb21taXRGaW5hbFJlZi5jdXJyZW50ICYmXG4gICAgICAgIGxvb2tzQ29tcGxldGVkICYmXG4gICAgICAgIGdldEJ1ZmZlcmVkVHJhbnNjcmlwdCgpXG4gICAgICApIHtcbiAgICAgICAgZmluYWxpemVBbmRSZXNldCgpLmNhdGNoKChlcnJvcikgPT4gZW1pdEVycm9yKGVycm9yKSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgaWYgKG9wZW5haUF1dG9TdG9wT25WYWRTaWxlbmNlICYmIHR5cGUgPT09IFwiaW5wdXRfYXVkaW9fYnVmZmVyLnNwZWVjaF9zdG9wcGVkXCIpIHtcbiAgICAgICAgY29uc3QgcGF1c2VUcmFuc2NyaXB0ID0gZ2V0QnVmZmVyZWRUcmFuc2NyaXB0KCk7XG4gICAgICAgIHNwZWVjaFN0YXR1c0NhbGxiYWNrKGZhbHNlLCBwYXVzZVRyYW5zY3JpcHQpO1xuICAgICAgfVxuICAgIH0sXG4gICAgW1xuICAgICAgZW1pdEVycm9yLFxuICAgICAgZmluYWxpemVBbmRSZXNldCxcbiAgICAgIGdldEJ1ZmZlcmVkVHJhbnNjcmlwdCxcbiAgICAgIG9wZW5haUF1dG9TdG9wT25WYWRTaWxlbmNlLFxuICAgICAgc3BlZWNoU3RhdHVzQ2FsbGJhY2ssXG4gICAgXVxuICApO1xuXG4gIGNvbnN0IHN0YXJ0TmF0aXZlV2ViUnRjU2Vzc2lvbiA9IHVzZUNhbGxiYWNrKFxuICAgIGFzeW5jICh0b2tlbjogc3RyaW5nKSA9PiB7XG4gICAgICBjb25zdCB3ZWJydGMgPSBuYXRpdmVXZWJSVEM7XG4gICAgICBpZiAoIXdlYnJ0Yz8uUlRDUGVlckNvbm5lY3Rpb24gfHwgIXdlYnJ0Yz8ubWVkaWFEZXZpY2VzPy5nZXRVc2VyTWVkaWEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIFwicmVhY3QtbmF0aXZlLXdlYnJ0YyBpcyBub3QgaW5zdGFsbGVkLiBJbnN0YWxsIGl0IGZvciBPcGVuQUkgbmF0aXZlIHJlYWx0aW1lIHNwZWVjaC5cIlxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzdHJlYW0gPSBhd2FpdCB3ZWJydGMubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYSh7XG4gICAgICAgIGF1ZGlvOiB0cnVlLFxuICAgICAgICB2aWRlbzogZmFsc2UsXG4gICAgICB9KTtcbiAgICAgIHN0cmVhbVJlZi5jdXJyZW50ID0gc3RyZWFtO1xuICAgICAgc2V0QXVkaW9DYXB0dXJlRW5hYmxlZChmYWxzZSk7XG5cbiAgICAgIGNvbnN0IHBjID0gbmV3IHdlYnJ0Yy5SVENQZWVyQ29ubmVjdGlvbigpO1xuICAgICAgcGNSZWYuY3VycmVudCA9IHBjO1xuICAgICAgY29uc3QgdHJhY2tzID0gdHlwZW9mIHN0cmVhbS5nZXRUcmFja3MgPT09IFwiZnVuY3Rpb25cIiA/IHN0cmVhbS5nZXRUcmFja3MoKSA6IFtdO1xuICAgICAgdHJhY2tzLmZvckVhY2goKHRyYWNrOiBhbnkpID0+IHBjLmFkZFRyYWNrKHRyYWNrLCBzdHJlYW0pKTtcblxuICAgICAgY29uc3QgZGF0YUNoYW5uZWwgPSBwYy5jcmVhdGVEYXRhQ2hhbm5lbChcIm9haS1ldmVudHNcIik7XG4gICAgICBkYXRhQ2hhbm5lbFJlZi5jdXJyZW50ID0gZGF0YUNoYW5uZWw7XG5cbiAgICAgIGRhdGFDaGFubmVsLm9ub3BlbiA9ICgpID0+IHtcbiAgICAgICAgbm90aWZ5UmVhZHkodHJ1ZSk7XG4gICAgICB9O1xuICAgICAgZGF0YUNoYW5uZWwub25tZXNzYWdlID0gKGV2ZW50OiB7IGRhdGE6IHN0cmluZyB9KSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgcGF5bG9hZCA9IEpTT04ucGFyc2UoU3RyaW5nKGV2ZW50LmRhdGEgfHwgXCJ7fVwiKSk7XG4gICAgICAgICAgaWYgKHBheWxvYWQ/LnR5cGUgPT09IFwiZXJyb3JcIikge1xuICAgICAgICAgICAgY29uc3QgbWVzc2FnZSA9IFN0cmluZyhcbiAgICAgICAgICAgICAgcGF5bG9hZD8uZXJyb3I/Lm1lc3NhZ2UgfHwgXCJPcGVuQUkgcmVhbHRpbWUgZXJyb3JcIlxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGlmIChpc0NvbW1pdEJ1ZmZlclRvb1NtYWxsRXJyb3IobWVzc2FnZSkpIHtcbiAgICAgICAgICAgICAgLy8gSWdub3JlIGNvbW1pdCBidWZmZXItdG9vLXNtYWxsIGVycm9ycyBmb3IgbG93LWxhdGVuY3kgZmFzdC1zdG9wIHBhdGguXG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChpc1Nlc3Npb25EdXJhdGlvbkxpbWl0RXJyb3IobWVzc2FnZSkpIHtcbiAgICAgICAgICAgICAgaGFuZGxlRXhwaXJlZFNlc3Npb24oZGF0YUNoYW5uZWwsIHBjKTtcbiAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKG1lc3NhZ2UpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBoYW5kbGVNZXNzYWdlKHBheWxvYWQpO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGVtaXRFcnJvcihlcnJvcik7XG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgICBkYXRhQ2hhbm5lbC5vbmVycm9yID0gKCkgPT4ge1xuICAgICAgICBpZiAoc3VwcHJlc3NlZENoYW5uZWxFcnJvclJlZi5jdXJyZW50ID09PSBkYXRhQ2hhbm5lbCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBub3RpZnlSZWFkeShmYWxzZSk7XG4gICAgICAgIGVtaXRFcnJvcihuZXcgRXJyb3IoXCJPcGVuQUkgbmF0aXZlIHJlYWx0aW1lIGRhdGEgY2hhbm5lbCBlcnJvclwiKSk7XG4gICAgICB9O1xuICAgICAgZGF0YUNoYW5uZWwub25jbG9zZSA9ICgpID0+IHtcbiAgICAgICAgbm90aWZ5UmVhZHkoZmFsc2UpO1xuICAgICAgfTtcblxuICAgICAgY29uc3Qgb2ZmZXIgPSBhd2FpdCBwYy5jcmVhdGVPZmZlcigpO1xuICAgICAgYXdhaXQgcGMuc2V0TG9jYWxEZXNjcmlwdGlvbihvZmZlcik7XG5cbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2gob3BlbmFpUmVhbHRpbWVXZWJSdGNVcmwsIHtcbiAgICAgICAgbWV0aG9kOiBcIlBPU1RcIixcbiAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgIEF1dGhvcml6YXRpb246IGBCZWFyZXIgJHt0b2tlbn1gLFxuICAgICAgICAgIFwiY29udGVudC10eXBlXCI6IFwiYXBwbGljYXRpb24vc2RwXCIsXG4gICAgICAgIH0sXG4gICAgICAgIGJvZHk6IG9mZmVyPy5zZHAgfHwgXCJcIixcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICAgIGNvbnN0IGJvZHkgPSBhd2FpdCByZXNwb25zZS50ZXh0KCkuY2F0Y2goKCkgPT4gXCJcIik7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgd2VicnRjIG5lZ290aWF0aW9uIGZhaWxlZCAoJHtyZXNwb25zZS5zdGF0dXN9KTogJHtib2R5fWApO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBhbnN3ZXJTZHAgPSBhd2FpdCByZXNwb25zZS50ZXh0KCk7XG4gICAgICBhd2FpdCBwYy5zZXRSZW1vdGVEZXNjcmlwdGlvbih7XG4gICAgICAgIHR5cGU6IFwiYW5zd2VyXCIsXG4gICAgICAgIHNkcDogYW5zd2VyU2RwLFxuICAgICAgfSk7XG4gICAgICBhd2FpdCB3YWl0Rm9yRGF0YUNoYW5uZWxPcGVuKGRhdGFDaGFubmVsKTtcbiAgICB9LFxuICAgIFtcbiAgICAgIGVtaXRFcnJvcixcbiAgICAgIGhhbmRsZU1lc3NhZ2UsXG4gICAgICBub3RpZnlSZWFkeSxcbiAgICAgIG9wZW5haVJlYWx0aW1lV2ViUnRjVXJsLFxuICAgICAgc2V0QXVkaW9DYXB0dXJlRW5hYmxlZCxcbiAgICAgIHdhaXRGb3JEYXRhQ2hhbm5lbE9wZW4sXG4gICAgXVxuICApO1xuXG4gIGNvbnN0IGdldEVwaGVtZXJhbFRva2VuID0gdXNlQ2FsbGJhY2soYXN5bmMgKCk6IFByb21pc2U8c3RyaW5nPiA9PiB7XG4gICAgY29uc3QgaGVhZGVyczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICAgIFwiY29udGVudC10eXBlXCI6IFwiYXBwbGljYXRpb24vanNvblwiLFxuICAgICAgLi4uZ2V0UmVxdWVzdENvbnRleHRIZWFkZXJzKCksXG4gICAgfTtcbiAgICBpZiAocHJveHlBdXRoVG9rZW4pIHtcbiAgICAgIGhlYWRlcnMuQXV0aG9yaXphdGlvbiA9IGBCZWFyZXIgJHtwcm94eUF1dGhUb2tlbn1gO1xuICAgIH1cblxuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2gob3BlbmFpVHJhbnNjcmlwdGlvblNlc3Npb25FbmRwb2ludCwge1xuICAgICAgbWV0aG9kOiBcIlBPU1RcIixcbiAgICAgIGhlYWRlcnMsXG4gICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgIGlucHV0X2F1ZGlvX2Zvcm1hdDogXCJwY20xNlwiLFxuICAgICAgICBpbnB1dF9hdWRpb190cmFuc2NyaXB0aW9uOiB7XG4gICAgICAgICAgbW9kZWw6IG9wZW5haVJlYWx0aW1lTW9kZWwsXG4gICAgICAgICAgbGFuZ3VhZ2UsXG4gICAgICAgIH0sXG4gICAgICAgIHR1cm5fZGV0ZWN0aW9uOiBidWlsZFR1cm5EZXRlY3Rpb24oKSB8fCB1bmRlZmluZWQsXG4gICAgICB9KSxcbiAgICB9KTtcblxuICAgIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICAgIGNvbnN0IGJvZHkgPSBhd2FpdCByZXNwb25zZS50ZXh0KCkuY2F0Y2goKCkgPT4gXCJcIik7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGB0cmFuc2NyaXB0aW9uIHNlc3Npb24gcmVxdWVzdCBmYWlsZWQgKCR7cmVzcG9uc2Uuc3RhdHVzfSk6ICR7Ym9keX1gXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IHBheWxvYWQgPSBhd2FpdCByZXNwb25zZS5qc29uKCkuY2F0Y2goKCkgPT4gKHt9KSk7XG4gICAgY29uc3QgdG9rZW4gPVxuICAgICAgcGF5bG9hZD8uY2xpZW50X3NlY3JldD8udmFsdWUgfHxcbiAgICAgIHBheWxvYWQ/LmNsaWVudF9zZWNyZXQgfHxcbiAgICAgIHBheWxvYWQ/LnZhbHVlIHx8XG4gICAgICBcIlwiO1xuICAgIGlmICghdG9rZW4pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgXCJObyBlcGhlbWVyYWwgdG9rZW4gcmV0dXJuZWQgZnJvbSB0cmFuc2NyaXB0aW9uIHNlc3Npb24gZW5kcG9pbnRcIlxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdG9rZW47XG4gIH0sIFtcbiAgICBidWlsZFR1cm5EZXRlY3Rpb24sXG4gICAgZ2V0UmVxdWVzdENvbnRleHRIZWFkZXJzLFxuICAgIHByb3h5QXV0aFRva2VuLFxuICAgIGxhbmd1YWdlLFxuICAgIG9wZW5haVJlYWx0aW1lTW9kZWwsXG4gICAgb3BlbmFpVHJhbnNjcmlwdGlvblNlc3Npb25FbmRwb2ludCxcbiAgXSk7XG5cbiAgY29uc3QgaGFzUmV1c2FibGVTZXNzaW9uID0gdXNlQ2FsbGJhY2soKCk6IGJvb2xlYW4gPT4ge1xuICAgIHJldHVybiAoXG4gICAgICAhIXBjUmVmLmN1cnJlbnQgJiZcbiAgICAgICEhc3RyZWFtUmVmLmN1cnJlbnQgJiZcbiAgICAgIGRhdGFDaGFubmVsUmVmLmN1cnJlbnQ/LnJlYWR5U3RhdGUgPT09IFwib3BlblwiXG4gICAgKTtcbiAgfSwgW10pO1xuXG4gIGNvbnN0IGVuc3VyZU5hdGl2ZVdlYlJ0Y1Nlc3Npb24gPSB1c2VDYWxsYmFjayhhc3luYyAoKSA9PiB7XG4gICAgaWYgKGhhc1JldXNhYmxlU2Vzc2lvbigpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmIChzZXNzaW9uSW5pdFJlZi5jdXJyZW50KSB7XG4gICAgICBhd2FpdCBzZXNzaW9uSW5pdFJlZi5jdXJyZW50O1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHNlc3Npb25Jbml0UmVmLmN1cnJlbnQgPSAoYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgdG9rZW4gPSBhd2FpdCBnZXRFcGhlbWVyYWxUb2tlbigpO1xuICAgICAgYXdhaXQgc3RhcnROYXRpdmVXZWJSdGNTZXNzaW9uKHRva2VuKTtcbiAgICB9KSgpO1xuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHNlc3Npb25Jbml0UmVmLmN1cnJlbnQ7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHNlc3Npb25Jbml0UmVmLmN1cnJlbnQgPSBudWxsO1xuICAgIH1cbiAgfSwgW2dldEVwaGVtZXJhbFRva2VuLCBoYXNSZXVzYWJsZVNlc3Npb24sIHN0YXJ0TmF0aXZlV2ViUnRjU2Vzc2lvbl0pO1xuXG4gIGNvbnN0IGNsZWFudXAgPSB1c2VDYWxsYmFjaygoKSA9PiB7XG4gICAgc2Vzc2lvbkluaXRSZWYuY3VycmVudCA9IG51bGw7XG5cbiAgICB0cnkge1xuICAgICAgaWYgKGRhdGFDaGFubmVsUmVmLmN1cnJlbnQpIHtcbiAgICAgICAgZGF0YUNoYW5uZWxSZWYuY3VycmVudC5jbG9zZSgpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIud2FybihcIltPcGVuQUkgTmF0aXZlIFNSXSBjbG9zZSBkYXRhIGNoYW5uZWwgd2FybmluZzpcIiwgZXJyb3IpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBkYXRhQ2hhbm5lbFJlZi5jdXJyZW50ID0gbnVsbDtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgaWYgKHBjUmVmLmN1cnJlbnQpIHtcbiAgICAgICAgcGNSZWYuY3VycmVudC5jbG9zZSgpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIud2FybihcIltPcGVuQUkgTmF0aXZlIFNSXSBjbG9zZSBwZWVyIHdhcm5pbmc6XCIsIGVycm9yKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgcGNSZWYuY3VycmVudCA9IG51bGw7XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIGlmIChzdHJlYW1SZWYuY3VycmVudD8uZ2V0VHJhY2tzKSB7XG4gICAgICAgIHN0cmVhbVJlZi5jdXJyZW50LmdldFRyYWNrcygpLmZvckVhY2goKHRyYWNrOiBhbnkpID0+IHRyYWNrLnN0b3A/LigpKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLndhcm4oXCJbT3BlbkFJIE5hdGl2ZSBTUl0gc3RvcCBzdHJlYW0gd2FybmluZzpcIiwgZXJyb3IpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBzdHJlYW1SZWYuY3VycmVudCA9IG51bGw7XG4gICAgfVxuICB9LCBbXSk7XG5cbiAgdXNlRWZmZWN0KCgpID0+IHtcbiAgICBpZiAoc2Vzc2lvblJlY292ZXJ5VG9rZW4gPT09IDAgfHwgIXNlc3Npb25SZWNvdmVyeU1vZGVSZWYuY3VycmVudCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGxldCBjYW5jZWxsZWQgPSBmYWxzZTtcbiAgICBjb25zdCByZWNvdmVyeU1vZGUgPSBzZXNzaW9uUmVjb3ZlcnlNb2RlUmVmLmN1cnJlbnQ7XG5cbiAgICAoYXN5bmMgKCkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgZW5zdXJlTmF0aXZlV2ViUnRjU2Vzc2lvbigpO1xuICAgICAgICBpZiAoY2FuY2VsbGVkKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHJlY292ZXJ5TW9kZSA9PT0gXCJsaXN0ZW5cIiAmJiBzaG91bGRMaXN0ZW5SZWYuY3VycmVudCkge1xuICAgICAgICAgIHNldEF1ZGlvQ2FwdHVyZUVuYWJsZWQodHJ1ZSk7XG4gICAgICAgICAgc2V0SXNSZWNvcmRpbmcodHJ1ZSk7XG4gICAgICAgIH1cbiAgICAgICAgbm90aWZ5UmVhZHkoZGF0YUNoYW5uZWxSZWYuY3VycmVudD8ucmVhZHlTdGF0ZSA9PT0gXCJvcGVuXCIpO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgaWYgKGNhbmNlbGxlZCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBlbWl0RXJyb3IoZXJyb3IpO1xuICAgICAgICBzZXRBdWRpb0NhcHR1cmVFbmFibGVkKGZhbHNlKTtcbiAgICAgICAgY2xlYW51cCgpO1xuICAgICAgICBzZXRJc1JlY29yZGluZyhmYWxzZSk7XG4gICAgICAgIG5vdGlmeVJlYWR5KGZhbHNlKTtcbiAgICAgICAgc3BlZWNoU3RhdHVzQ2FsbGJhY2soZmFsc2UsIFwiXCIpO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgaWYgKGNhbmNlbGxlZCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBzZXNzaW9uUmVjb3ZlcnlNb2RlUmVmLmN1cnJlbnQgPSBudWxsO1xuICAgICAgICBzZXNzaW9uUmVjb3ZlcnlJbkZsaWdodFJlZi5jdXJyZW50ID0gZmFsc2U7XG4gICAgICAgIHN1cHByZXNzZWRDaGFubmVsRXJyb3JSZWYuY3VycmVudCA9IG51bGw7XG4gICAgICB9XG4gICAgfSkoKTtcblxuICAgIHJldHVybiAoKSA9PiB7XG4gICAgICBjYW5jZWxsZWQgPSB0cnVlO1xuICAgIH07XG4gIH0sIFtcbiAgICBjbGVhbnVwLFxuICAgIGVtaXRFcnJvcixcbiAgICBlbnN1cmVOYXRpdmVXZWJSdGNTZXNzaW9uLFxuICAgIG5vdGlmeVJlYWR5LFxuICAgIHNlc3Npb25SZWNvdmVyeVRva2VuLFxuICAgIHNldEF1ZGlvQ2FwdHVyZUVuYWJsZWQsXG4gICAgc3BlZWNoU3RhdHVzQ2FsbGJhY2ssXG4gIF0pO1xuXG4gIGNvbnN0IHN0YXJ0UmVjb3JkaW5nID0gdXNlQ2FsbGJhY2soYXN5bmMgKCkgPT4ge1xuICAgIGlmIChpc1JlY29yZGluZyB8fCBzdG9wSW5GbGlnaHRSZWYuY3VycmVudCB8fCBzZXNzaW9uUmVjb3ZlcnlJbkZsaWdodFJlZi5jdXJyZW50KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHJlc2V0VHJhbnNjcmlwdFJlZnMoKTtcbiAgICB0cnkge1xuICAgICAgY2xlYXJDb21taXRGaW5hbFdhaXQoKTtcbiAgICAgIG5vdGlmeVJlYWR5KGZhbHNlKTtcbiAgICAgIGNvbnN0IHJldXNpbmdXYXJtU2Vzc2lvbiA9IGhhc1JldXNhYmxlU2Vzc2lvbigpO1xuICAgICAgYXdhaXQgZW5zdXJlTmF0aXZlV2ViUnRjU2Vzc2lvbigpO1xuICAgICAgaWYgKHJldXNpbmdXYXJtU2Vzc2lvbikge1xuICAgICAgICBjbGVhclJlYWx0aW1lSW5wdXRCdWZmZXIoXCJzdGFydF9yZWNvcmRpbmdcIik7XG4gICAgICB9XG4gICAgICBpZiAoIXNob3VsZExpc3RlblJlZi5jdXJyZW50KSB7XG4gICAgICAgIHNldEF1ZGlvQ2FwdHVyZUVuYWJsZWQoZmFsc2UpO1xuICAgICAgICBub3RpZnlSZWFkeShkYXRhQ2hhbm5lbFJlZi5jdXJyZW50Py5yZWFkeVN0YXRlID09PSBcIm9wZW5cIik7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHNldEF1ZGlvQ2FwdHVyZUVuYWJsZWQodHJ1ZSk7XG4gICAgICBzZXRJc1JlY29yZGluZyh0cnVlKTtcbiAgICAgIG5vdGlmeVJlYWR5KGRhdGFDaGFubmVsUmVmLmN1cnJlbnQ/LnJlYWR5U3RhdGUgPT09IFwib3BlblwiKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgZW1pdEVycm9yKGVycm9yKTtcbiAgICAgIHNldEF1ZGlvQ2FwdHVyZUVuYWJsZWQoZmFsc2UpO1xuICAgICAgY2xlYW51cCgpO1xuICAgICAgc2V0SXNSZWNvcmRpbmcoZmFsc2UpO1xuICAgICAgbm90aWZ5UmVhZHkoZmFsc2UpO1xuICAgICAgc3BlZWNoU3RhdHVzQ2FsbGJhY2soZmFsc2UsIFwiXCIpO1xuICAgIH1cbiAgfSwgW1xuICAgIGNsZWFudXAsXG4gICAgY2xlYXJDb21taXRGaW5hbFdhaXQsXG4gICAgY2xlYXJSZWFsdGltZUlucHV0QnVmZmVyLFxuICAgIGVuc3VyZU5hdGl2ZVdlYlJ0Y1Nlc3Npb24sXG4gICAgZW1pdEVycm9yLFxuICAgIGhhc1JldXNhYmxlU2Vzc2lvbixcbiAgICBpc1JlY29yZGluZyxcbiAgICBub3RpZnlSZWFkeSxcbiAgICByZXNldFRyYW5zY3JpcHRSZWZzLFxuICAgIHNldEF1ZGlvQ2FwdHVyZUVuYWJsZWQsXG4gICAgc3BlZWNoU3RhdHVzQ2FsbGJhY2ssXG4gIF0pO1xuXG4gIGNvbnN0IHN0b3BSZWNvcmRpbmcgPSB1c2VDYWxsYmFjayhhc3luYyAoKSA9PiB7XG4gICAgaWYgKCFpc1JlY29yZGluZyB8fCBzdG9wSW5GbGlnaHRSZWYuY3VycmVudCkgcmV0dXJuO1xuICAgIHN0b3BJbkZsaWdodFJlZi5jdXJyZW50ID0gdHJ1ZTtcbiAgICBzZXRJc1JlY29yZGluZyhmYWxzZSk7XG4gICAgc2V0QXVkaW9DYXB0dXJlRW5hYmxlZChmYWxzZSk7XG4gICAgbm90aWZ5UmVhZHkoZmFsc2UpO1xuICAgIHRyeSB7XG4gICAgICBpZiAoZGF0YUNoYW5uZWxSZWYuY3VycmVudD8ucmVhZHlTdGF0ZSA9PT0gXCJvcGVuXCIpIHtcbiAgICAgICAgZGF0YUNoYW5uZWxSZWYuY3VycmVudC5zZW5kKFxuICAgICAgICAgIEpTT04uc3RyaW5naWZ5KHsgdHlwZTogXCJpbnB1dF9hdWRpb19idWZmZXIuY29tbWl0XCIgfSlcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGJ1ZmZlcmVkID0gZ2V0QnVmZmVyZWRUcmFuc2NyaXB0KCk7XG4gICAgICBpZiAoYnVmZmVyZWQpIHtcbiAgICAgICAgYXdhaXQgZmluYWxpemVBbmRSZXNldCgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc3BlZWNoU3RhdHVzQ2FsbGJhY2soZmFsc2UsIFwiXCIpO1xuICAgICAgICBhd2FpdGluZ0NvbW1pdEZpbmFsUmVmLmN1cnJlbnQgPSB0cnVlO1xuICAgICAgICBpZiAoY29tbWl0RmluYWxUaW1lb3V0UmVmLmN1cnJlbnQpIHtcbiAgICAgICAgICBjbGVhclRpbWVvdXQoY29tbWl0RmluYWxUaW1lb3V0UmVmLmN1cnJlbnQpO1xuICAgICAgICB9XG4gICAgICAgIC8vIFNob3J0IGZhbGxiYWNrOiBpZiBubyBwb3N0LWNvbW1pdCB0cmFuc2NyaXB0IGFycml2ZXMsIHJlc2V0IHN0YXRlIGFuZCBleGl0LlxuICAgICAgICBjb21taXRGaW5hbFRpbWVvdXRSZWYuY3VycmVudCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgIGlmICghYXdhaXRpbmdDb21taXRGaW5hbFJlZi5jdXJyZW50KSByZXR1cm47XG4gICAgICAgICAgY2xlYXJDb21taXRGaW5hbFdhaXQoKTtcbiAgICAgICAgICByZXNldFRyYW5zY3JpcHRSZWZzKCk7XG4gICAgICAgIH0sIDE1MDApO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBlbWl0RXJyb3IoZXJyb3IpO1xuICAgICAgc3BlZWNoU3RhdHVzQ2FsbGJhY2soZmFsc2UsIFwiXCIpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBzdG9wSW5GbGlnaHRSZWYuY3VycmVudCA9IGZhbHNlO1xuICAgICAgbm90aWZ5UmVhZHkoZmFsc2UpO1xuICAgIH1cbiAgfSwgW1xuICAgIGVtaXRFcnJvcixcbiAgICBmaW5hbGl6ZUFuZFJlc2V0LFxuICAgIGdldEJ1ZmZlcmVkVHJhbnNjcmlwdCxcbiAgICBpc1JlY29yZGluZyxcbiAgICBub3RpZnlSZWFkeSxcbiAgICBjbGVhckNvbW1pdEZpbmFsV2FpdCxcbiAgICByZXNldFRyYW5zY3JpcHRSZWZzLFxuICAgIHNldEF1ZGlvQ2FwdHVyZUVuYWJsZWQsXG4gICAgc3BlZWNoU3RhdHVzQ2FsbGJhY2ssXG4gIF0pO1xuXG4gIHVzZUVmZmVjdCgoKSA9PiB7XG4gICAgaWYgKCFvcGVuYWlQcmV3YXJtT25Nb3VudCB8fCBkaWRQcmV3YXJtUmVmLmN1cnJlbnQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgZGlkUHJld2FybVJlZi5jdXJyZW50ID0gdHJ1ZTtcbiAgICBlbnN1cmVOYXRpdmVXZWJSdGNTZXNzaW9uKClcbiAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgbm90aWZ5UmVhZHkodHJ1ZSk7XG4gICAgICB9KVxuICAgICAgLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICBlbWl0RXJyb3IoZXJyb3IpO1xuICAgICAgfSk7XG4gIH0sIFtlbWl0RXJyb3IsIGVuc3VyZU5hdGl2ZVdlYlJ0Y1Nlc3Npb24sIG5vdGlmeVJlYWR5LCBvcGVuYWlQcmV3YXJtT25Nb3VudF0pO1xuXG4gIHVzZUVmZmVjdCgoKSA9PiB7XG4gICAgaWYgKHNob3VsZExpc3RlbiAmJiAhaXNSZWNvcmRpbmcpIHtcbiAgICAgIHN0YXJ0UmVjb3JkaW5nKCk7XG4gICAgfSBlbHNlIGlmICghc2hvdWxkTGlzdGVuICYmIGlzUmVjb3JkaW5nKSB7XG4gICAgICBzdG9wUmVjb3JkaW5nKCk7XG4gICAgfVxuICB9LCBbaXNSZWNvcmRpbmcsIHNob3VsZExpc3Rlbiwgc3RhcnRSZWNvcmRpbmcsIHN0b3BSZWNvcmRpbmddKTtcblxuICB1c2VFZmZlY3QoKCkgPT4ge1xuICAgIHJldHVybiAoKSA9PiB7XG4gICAgICBub3RpZnlSZWFkeShmYWxzZSk7XG4gICAgICBjbGVhckNvbW1pdEZpbmFsV2FpdCgpO1xuICAgICAgc2V0QXVkaW9DYXB0dXJlRW5hYmxlZChmYWxzZSk7XG4gICAgICBjbGVhbnVwKCk7XG4gICAgfTtcbiAgfSwgW2NsZWFudXAsIG5vdGlmeVJlYWR5LCBjbGVhckNvbW1pdEZpbmFsV2FpdCwgc2V0QXVkaW9DYXB0dXJlRW5hYmxlZF0pO1xuXG4gIHJldHVybiA8VmlldyAvPjtcbn07XG5cbmZ1bmN0aW9uIGV4dHJhY3REZWx0YVRleHQocGF5bG9hZDogYW55KTogc3RyaW5nIHtcbiAgY29uc3QgdHlwZSA9IFN0cmluZyhwYXlsb2FkPy50eXBlIHx8IFwiXCIpO1xuICBpZiAoIXR5cGUuaW5jbHVkZXMoXCJkZWx0YVwiKSkgcmV0dXJuIFwiXCI7XG4gIGNvbnN0IGNhbmRpZGF0ZXMgPSBbXG4gICAgcGF5bG9hZD8uZGVsdGEsXG4gICAgcGF5bG9hZD8udGV4dF9kZWx0YSxcbiAgICBwYXlsb2FkPy50cmFuc2NyaXB0X2RlbHRhLFxuICAgIHBheWxvYWQ/Lml0ZW0/LmNvbnRlbnQ/LlswXT8udHJhbnNjcmlwdCxcbiAgXTtcbiAgZm9yIChjb25zdCB2YWx1ZSBvZiBjYW5kaWRhdGVzKSB7XG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIiAmJiB2YWx1ZS50cmltKCkpIHJldHVybiB2YWx1ZS50cmltKCk7XG4gIH1cbiAgcmV0dXJuIFwiXCI7XG59XG5cbmZ1bmN0aW9uIGV4dHJhY3RDb21wbGV0ZWRUZXh0KHBheWxvYWQ6IGFueSk6IHN0cmluZyB7XG4gIGNvbnN0IHR5cGUgPSBTdHJpbmcocGF5bG9hZD8udHlwZSB8fCBcIlwiKTtcbiAgaWYgKCF0eXBlLmluY2x1ZGVzKFwiY29tcGxldGVkXCIpKSByZXR1cm4gXCJcIjtcbiAgY29uc3QgY2FuZGlkYXRlcyA9IFtcbiAgICBwYXlsb2FkPy50cmFuc2NyaXB0LFxuICAgIHBheWxvYWQ/LnRleHQsXG4gICAgcGF5bG9hZD8uaXRlbT8uY29udGVudD8uWzBdPy50cmFuc2NyaXB0LFxuICAgIHBheWxvYWQ/Lml0ZW0/LnRyYW5zY3JpcHQsXG4gIF07XG4gIGZvciAoY29uc3QgdmFsdWUgb2YgY2FuZGlkYXRlcykge1xuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09IFwic3RyaW5nXCIgJiYgdmFsdWUudHJpbSgpKSByZXR1cm4gdmFsdWUudHJpbSgpO1xuICB9XG4gIHJldHVybiBcIlwiO1xufVxuXG5mdW5jdGlvbiBleHRyYWN0SXRlbUlkKHBheWxvYWQ6IGFueSk6IHN0cmluZyB8IG51bGwge1xuICBjb25zdCBjYW5kaWRhdGVzID0gW3BheWxvYWQ/Lml0ZW1faWQsIHBheWxvYWQ/Lml0ZW0/LmlkXTtcbiAgZm9yIChjb25zdCB2YWx1ZSBvZiBjYW5kaWRhdGVzKSB7XG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIiAmJiB2YWx1ZS50cmltKCkpIHtcbiAgICAgIHJldHVybiB2YWx1ZS50cmltKCk7XG4gICAgfVxuICB9XG4gIHJldHVybiBudWxsO1xufVxuXG5mdW5jdGlvbiBpc0NvbW1pdEJ1ZmZlclRvb1NtYWxsRXJyb3IobWVzc2FnZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gIGNvbnN0IG5vcm1hbGl6ZWQgPSBtZXNzYWdlLnRvTG93ZXJDYXNlKCk7XG4gIHJldHVybiAoXG4gICAgbm9ybWFsaXplZC5pbmNsdWRlcyhcImlucHV0IGF1ZGlvIGJ1ZmZlclwiKSAmJlxuICAgIG5vcm1hbGl6ZWQuaW5jbHVkZXMoXCJidWZmZXIgdG9vIHNtYWxsXCIpXG4gICk7XG59XG5cbmZ1bmN0aW9uIGlzU2Vzc2lvbkR1cmF0aW9uTGltaXRFcnJvcihtZXNzYWdlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgY29uc3Qgbm9ybWFsaXplZCA9IG1lc3NhZ2UudG9Mb3dlckNhc2UoKTtcbiAgcmV0dXJuIChcbiAgICBub3JtYWxpemVkLmluY2x1ZGVzKFwic2Vzc2lvblwiKSAmJlxuICAgIChub3JtYWxpemVkLmluY2x1ZGVzKFwibWF4aW11bSBkdXJhdGlvblwiKSB8fFxuICAgICAgbm9ybWFsaXplZC5pbmNsdWRlcyhcIm1heCBkdXJhdGlvblwiKSlcbiAgKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzT3BlbkFJTmF0aXZlU3BlZWNoQXZhaWxhYmxlKCk6IGJvb2xlYW4ge1xuICByZXR1cm4gKFxuICAgIChQbGF0Zm9ybS5PUyA9PT0gXCJpb3NcIiB8fCBQbGF0Zm9ybS5PUyA9PT0gXCJhbmRyb2lkXCIpICYmXG4gICAgISFuYXRpdmVXZWJSVEM/LlJUQ1BlZXJDb25uZWN0aW9uICYmXG4gICAgISFuYXRpdmVXZWJSVEM/Lm1lZGlhRGV2aWNlcz8uZ2V0VXNlck1lZGlhXG4gICk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRPcGVuQUlOYXRpdmVTcGVlY2hDYXBhYmlsaXRpZXMoKSB7XG4gIHJldHVybiB7XG4gICAgYXZhaWxhYmxlOiBpc09wZW5BSU5hdGl2ZVNwZWVjaEF2YWlsYWJsZSgpLFxuICAgIHBsYXRmb3JtOiBQbGF0Zm9ybS5PUyxcbiAgICBzdXBwb3J0c1NlcnZlclZBRDogdHJ1ZSxcbiAgICB0cmFuc3BvcnQ6IFwid2VicnRjXCIsXG4gICAgcmVxdWlyZXNXZWJSVENEZXBlbmRlbmN5OiB0cnVlLFxuICB9O1xufVxuXG5leHBvcnQgZGVmYXVsdCBPcGVuQUlOYXRpdmVTcGVlY2hSZWNvZ25pemVyO1xuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7OztBQUFB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LEVBQUVuRSxPQUFPLEVBQUUrRCxJQUFJLEVBQUVLLEVBQUUsQ0FBQztFQUN4RCxLQUFLLE1BQU01TSxLQUFLLElBQUlvTSxVQUFVLEVBQUU7SUFDOUIsSUFBSSxPQUFPcE0sS0FBSyxLQUFLLFFBQVEsSUFBSUEsS0FBSyxDQUFDd0YsSUFBSSxDQUFDLENBQUMsRUFBRTtNQUM3QyxPQUFPeEYsS0FBSyxDQUFDd0YsSUFBSSxDQUFDLENBQUM7SUFDckI7RUFDRjtFQUNBLE9BQU8sSUFBSTtBQUNiO0FBRUEsU0FBU2dGLDJCQUEyQkEsQ0FBQ0QsT0FBZSxFQUFXO0VBQzdELE1BQU1zQyxVQUFVLEdBQUd0QyxPQUFPLENBQUMzQyxXQUFXLENBQUMsQ0FBQztFQUN4QyxPQUNFaUYsVUFBVSxDQUFDckQsUUFBUSxDQUFDLG9CQUFvQixDQUFDLElBQ3pDcUQsVUFBVSxDQUFDckQsUUFBUSxDQUFDLGtCQUFrQixDQUFDO0FBRTNDO0FBRUEsU0FBU2lCLDJCQUEyQkEsQ0FBQ0YsT0FBZSxFQUFXO0VBQzdELE1BQU1zQyxVQUFVLEdBQUd0QyxPQUFPLENBQUMzQyxXQUFXLENBQUMsQ0FBQztFQUN4QyxPQUNFaUYsVUFBVSxDQUFDckQsUUFBUSxDQUFDLFNBQVMsQ0FBQyxLQUM3QnFELFVBQVUsQ0FBQ3JELFFBQVEsQ0FBQyxrQkFBa0IsQ0FBQyxJQUN0Q3FELFVBQVUsQ0FBQ3JELFFBQVEsQ0FBQyxjQUFjLENBQUMsQ0FBQztBQUUxQztBQUVPLFNBQVNzRCw2QkFBNkJBLENBQUEsRUFBWTtFQUN2RCxPQUNFLENBQUNDLHFCQUFRLENBQUNDLEVBQUUsS0FBSyxLQUFLLElBQUlELHFCQUFRLENBQUNDLEVBQUUsS0FBSyxTQUFTLEtBQ25ELENBQUMsQ0FBQ2pNLFlBQVksRUFBRUgsaUJBQWlCLElBQ2pDLENBQUMsQ0FBQ0csWUFBWSxFQUFFRixZQUFZLEVBQUVDLFlBQVk7QUFFOUM7QUFFTyxTQUFTbU0saUNBQWlDQSxDQUFBLEVBQUc7RUFDbEQsT0FBTztJQUNMQyxTQUFTLEVBQUVKLDZCQUE2QixDQUFDLENBQUM7SUFDMUNLLFFBQVEsRUFBRUoscUJBQVEsQ0FBQ0MsRUFBRTtJQUNyQkksaUJBQWlCLEVBQUUsSUFBSTtJQUN2QkMsU0FBUyxFQUFFLFFBQVE7SUFDbkJDLHdCQUF3QixFQUFFO0VBQzVCLENBQUM7QUFDSDtBQUFDLElBQUFDLFFBQUEsR0FBQXBCLE9BQUEsQ0FBQW5PLE9BQUEsR0FFY21ELDRCQUE0QiIsImlnbm9yZUxpc3QiOltdfQ==
|