@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,589 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = exports.UnifiedSpeechRecognizer = void 0;
|
|
7
|
+
Object.defineProperty(exports, "getGroqSpeechCapabilities", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: function () {
|
|
10
|
+
return _speechRecognitionGroq.getGroqSpeechCapabilities;
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
Object.defineProperty(exports, "getOpenAISpeechCapabilities", {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
get: function () {
|
|
16
|
+
return _speechRecognitionOpenai.getOpenAISpeechCapabilities;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
exports.getSpeechRecognitionConfig = getSpeechRecognitionConfig;
|
|
20
|
+
exports.getSpeechRecognitionStatus = getSpeechRecognitionStatus;
|
|
21
|
+
Object.defineProperty(exports, "isGroqSpeechAvailable", {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function () {
|
|
24
|
+
return _speechRecognitionGroq.isGroqSpeechAvailable;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(exports, "isOpenAISpeechAvailable", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
get: function () {
|
|
30
|
+
return _speechRecognitionOpenai.isOpenAISpeechAvailable;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
exports.isWebSpeechAvailable = void 0;
|
|
34
|
+
exports.selectSpeechRecognitionMethod = selectSpeechRecognitionMethod;
|
|
35
|
+
var _react = _interopRequireDefault(require("react"));
|
|
36
|
+
var _reactNative = require("react-native");
|
|
37
|
+
var _speechRecognition = require("../speech-recognition");
|
|
38
|
+
var _speechRecognitionGroq = require("./speech-recognition-groq");
|
|
39
|
+
var _speechRecognitionMlx = require("./speech-recognition-mlx");
|
|
40
|
+
var _speechRecognitionOpenai = require("./speech-recognition-openai");
|
|
41
|
+
var _logger = _interopRequireDefault(require("../logger"));
|
|
42
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
43
|
+
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; }
|
|
44
|
+
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; }
|
|
45
|
+
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; }
|
|
46
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
47
|
+
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); } /**
|
|
48
|
+
* Unified Speech Recognition Component
|
|
49
|
+
* Automatically selects best speech recognition method based on:
|
|
50
|
+
* 1. Platform (Web vs Native)
|
|
51
|
+
* 2. Environment configuration
|
|
52
|
+
* 3. Feature availability
|
|
53
|
+
*/
|
|
54
|
+
/**
|
|
55
|
+
* Configuration for speech recognition.
|
|
56
|
+
* Resolved from in-code defaults + explicit runtime overrides passed via props.
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
function normalizeProvider(value) {
|
|
60
|
+
if (!value) return undefined;
|
|
61
|
+
const normalized = value.trim().toLowerCase();
|
|
62
|
+
if (normalized === "groq") return "groq";
|
|
63
|
+
if (normalized === "openai") return "openai";
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
const DEFAULT_REALTIME_MODEL = "gpt-4o-transcribe";
|
|
67
|
+
const DEFAULT_TRANSLATION_MODEL = "gpt-4.1-mini";
|
|
68
|
+
const DEFAULT_OPENAI_AUTO_STOP_ON_VAD_SILENCE = false;
|
|
69
|
+
const DEFAULT_OPENAI_VAD_SILENCE_DURATION_MS = 2000;
|
|
70
|
+
const DEFAULT_OPENAI_PREWARM_ON_MOUNT = true;
|
|
71
|
+
function getRuntimeEnvValue(key) {
|
|
72
|
+
try {
|
|
73
|
+
const env = typeof process !== "undefined" ? process.env : undefined;
|
|
74
|
+
const value = env?.[key];
|
|
75
|
+
if (typeof value !== "string") return undefined;
|
|
76
|
+
const trimmed = value.trim();
|
|
77
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
78
|
+
} catch {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function parseBooleanEnv(key, fallback) {
|
|
83
|
+
const raw = getRuntimeEnvValue(key);
|
|
84
|
+
if (!raw) return fallback;
|
|
85
|
+
const normalized = raw.toLowerCase();
|
|
86
|
+
if (normalized === "true" || normalized === "1" || normalized === "yes" || normalized === "on") {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
if (normalized === "false" || normalized === "0" || normalized === "no" || normalized === "off") {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
return fallback;
|
|
93
|
+
}
|
|
94
|
+
function parseNumberEnv(key, fallback) {
|
|
95
|
+
const raw = getRuntimeEnvValue(key);
|
|
96
|
+
if (!raw) return fallback;
|
|
97
|
+
const parsed = Number(raw);
|
|
98
|
+
if (!Number.isFinite(parsed)) return fallback;
|
|
99
|
+
return parsed;
|
|
100
|
+
}
|
|
101
|
+
const toOpenAIEndpointsFromBaseUrl = baseUrl => {
|
|
102
|
+
const trimmed = (baseUrl || "").trim().replace(/\/+$/, "");
|
|
103
|
+
if (!trimmed) {
|
|
104
|
+
return {
|
|
105
|
+
transcriptionSessionEndpoint: undefined,
|
|
106
|
+
translationEndpoint: undefined
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
transcriptionSessionEndpoint: `${trimmed}/openai/v1/realtime/transcription_sessions`,
|
|
111
|
+
translationEndpoint: `${trimmed}/openai/v1/speech/translate-to-english`
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
function resolveOpenAIConfig(config) {
|
|
115
|
+
const defaults = {
|
|
116
|
+
realtimeModel: DEFAULT_REALTIME_MODEL,
|
|
117
|
+
translationModel: DEFAULT_TRANSLATION_MODEL,
|
|
118
|
+
vadEnabled: true,
|
|
119
|
+
autoStopOnVadSilence: parseBooleanEnv("OPENAI_AUTO_STOP_ON_VAD_SILENCE", DEFAULT_OPENAI_AUTO_STOP_ON_VAD_SILENCE),
|
|
120
|
+
vadThreshold: 0.7,
|
|
121
|
+
vadPrefixPaddingMs: 400,
|
|
122
|
+
vadSilenceDurationMs: parseNumberEnv("OPENAI_VAD_SILENCE_DURATION_MS", DEFAULT_OPENAI_VAD_SILENCE_DURATION_MS),
|
|
123
|
+
vadIdleTimeoutMs: 6000,
|
|
124
|
+
prewarmOnMount: parseBooleanEnv("OPENAI_PREWARM_ON_MOUNT", DEFAULT_OPENAI_PREWARM_ON_MOUNT)
|
|
125
|
+
};
|
|
126
|
+
const nested = config?.openai || {};
|
|
127
|
+
const endpointBase = nested.proxyBaseUrl;
|
|
128
|
+
const derivedEndpoints = toOpenAIEndpointsFromBaseUrl(endpointBase);
|
|
129
|
+
return _objectSpread(_objectSpread(_objectSpread({}, defaults), nested), {}, {
|
|
130
|
+
transcriptionSessionEndpoint: nested.transcriptionSessionEndpoint || derivedEndpoints.transcriptionSessionEndpoint,
|
|
131
|
+
translationEndpoint: nested.translationEndpoint || derivedEndpoints.translationEndpoint,
|
|
132
|
+
realtimeWebRtcUrl: nested.realtimeWebRtcUrl,
|
|
133
|
+
realtimeModel: nested.realtimeModel || defaults.realtimeModel,
|
|
134
|
+
translationModel: nested.translationModel || defaults.translationModel,
|
|
135
|
+
vadEnabled: nested.vadEnabled ?? defaults.vadEnabled,
|
|
136
|
+
autoStopOnVadSilence: nested.autoStopOnVadSilence ?? defaults.autoStopOnVadSilence,
|
|
137
|
+
vadThreshold: nested.vadThreshold ?? defaults.vadThreshold,
|
|
138
|
+
vadPrefixPaddingMs: nested.vadPrefixPaddingMs ?? defaults.vadPrefixPaddingMs,
|
|
139
|
+
vadSilenceDurationMs: nested.vadSilenceDurationMs ?? defaults.vadSilenceDurationMs,
|
|
140
|
+
vadIdleTimeoutMs: nested.vadIdleTimeoutMs ?? defaults.vadIdleTimeoutMs,
|
|
141
|
+
prewarmOnMount: nested.prewarmOnMount ?? defaults.prewarmOnMount
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
function resolveGroqConfig(config) {
|
|
145
|
+
const defaults = {
|
|
146
|
+
enabled: true,
|
|
147
|
+
stream: true
|
|
148
|
+
};
|
|
149
|
+
return _objectSpread(_objectSpread({}, defaults), config?.groq || {});
|
|
150
|
+
}
|
|
151
|
+
function resolveLocalModelConfig(config) {
|
|
152
|
+
const defaults = {
|
|
153
|
+
enabledOnWeb: false,
|
|
154
|
+
baseUrl: "http://127.0.0.1:8000",
|
|
155
|
+
mode: "oneshot",
|
|
156
|
+
model: "large-v3-turbo"
|
|
157
|
+
};
|
|
158
|
+
return _objectSpread(_objectSpread({}, defaults), config?.localModel || {});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Load speech recognition config from defaults + explicit overrides.
|
|
163
|
+
*/
|
|
164
|
+
function getSpeechRecognitionConfig(overrides) {
|
|
165
|
+
const defaults = {
|
|
166
|
+
provider: "groq",
|
|
167
|
+
fallbackToWebSpeech: true,
|
|
168
|
+
groq: resolveGroqConfig(),
|
|
169
|
+
openai: resolveOpenAIConfig(),
|
|
170
|
+
localModel: resolveLocalModelConfig()
|
|
171
|
+
};
|
|
172
|
+
const merged = _objectSpread(_objectSpread(_objectSpread({}, defaults), overrides || {}), {}, {
|
|
173
|
+
provider: normalizeProvider(overrides?.provider) || normalizeProvider(defaults.provider) || "groq"
|
|
174
|
+
});
|
|
175
|
+
return _objectSpread(_objectSpread({}, merged), {}, {
|
|
176
|
+
groq: resolveGroqConfig(merged),
|
|
177
|
+
openai: resolveOpenAIConfig(merged),
|
|
178
|
+
localModel: resolveLocalModelConfig(merged)
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Check if Web Speech API is available
|
|
184
|
+
*/
|
|
185
|
+
function checkWebSpeechAvailability() {
|
|
186
|
+
if (typeof window === "undefined") {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
return "webkitSpeechRecognition" in window || "SpeechRecognition" in window;
|
|
190
|
+
}
|
|
191
|
+
const isWebSpeechAvailable = exports.isWebSpeechAvailable = checkWebSpeechAvailability;
|
|
192
|
+
const normalizeLanguageTag = lang => {
|
|
193
|
+
const normalized = (lang || "en").trim().toLowerCase();
|
|
194
|
+
return normalized.length > 0 ? normalized : "en";
|
|
195
|
+
};
|
|
196
|
+
const toShortLanguageCode = lang => lang.split("-")[0];
|
|
197
|
+
const toWebSpeechLocale = lang => {
|
|
198
|
+
if (lang.startsWith("en")) return "en-US";
|
|
199
|
+
if (lang.startsWith("de")) return "de-DE";
|
|
200
|
+
return lang;
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Types of speech recognition methods
|
|
205
|
+
*/
|
|
206
|
+
|
|
207
|
+
let nativeSpeechModuleCache;
|
|
208
|
+
let openAiNativeSpeechModuleCache;
|
|
209
|
+
function getNativeSpeechModule() {
|
|
210
|
+
if (nativeSpeechModuleCache !== undefined) {
|
|
211
|
+
return nativeSpeechModuleCache;
|
|
212
|
+
}
|
|
213
|
+
try {
|
|
214
|
+
// Keep native module lazy to avoid loading native-only dependencies on web.
|
|
215
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
216
|
+
nativeSpeechModuleCache = require("./speech-recognition-native");
|
|
217
|
+
} catch (error) {
|
|
218
|
+
nativeSpeechModuleCache = null;
|
|
219
|
+
_logger.default.debug("Native speech module unavailable:", error);
|
|
220
|
+
}
|
|
221
|
+
return nativeSpeechModuleCache;
|
|
222
|
+
}
|
|
223
|
+
function isNativeRecognizerAvailable() {
|
|
224
|
+
const nativeModule = getNativeSpeechModule();
|
|
225
|
+
return !!nativeModule?.isNativeSpeechAvailable?.();
|
|
226
|
+
}
|
|
227
|
+
function getOpenAINativeSpeechModule() {
|
|
228
|
+
if (openAiNativeSpeechModuleCache !== undefined) {
|
|
229
|
+
return openAiNativeSpeechModuleCache;
|
|
230
|
+
}
|
|
231
|
+
try {
|
|
232
|
+
// Keep native module lazy to avoid loading native-only dependencies on web.
|
|
233
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
234
|
+
openAiNativeSpeechModuleCache = require("./speech-recognition-openai-native");
|
|
235
|
+
} catch (error) {
|
|
236
|
+
openAiNativeSpeechModuleCache = null;
|
|
237
|
+
_logger.default.debug("OpenAI native speech module unavailable:", error);
|
|
238
|
+
}
|
|
239
|
+
return openAiNativeSpeechModuleCache;
|
|
240
|
+
}
|
|
241
|
+
function isOpenAINativeRecognizerAvailable() {
|
|
242
|
+
const nativeModule = getOpenAINativeSpeechModule();
|
|
243
|
+
return !!nativeModule?.isOpenAINativeSpeechAvailable?.();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Determine which speech recognition method to use
|
|
248
|
+
*/
|
|
249
|
+
function selectSpeechRecognitionMethod(config, clientSecret) {
|
|
250
|
+
const isWeb = _reactNative.Platform.OS === "web";
|
|
251
|
+
const isNative = _reactNative.Platform.OS === "ios" || _reactNative.Platform.OS === "android";
|
|
252
|
+
const isWebClientRuntime = isWeb && typeof window !== "undefined";
|
|
253
|
+
const shouldWarnUnavailable = isWebClientRuntime;
|
|
254
|
+
const provider = normalizeProvider(config.provider) || "groq";
|
|
255
|
+
const groq = resolveGroqConfig(config);
|
|
256
|
+
const openai = resolveOpenAIConfig(config);
|
|
257
|
+
const localModel = resolveLocalModelConfig(config);
|
|
258
|
+
const hasGroqKey = !!(clientSecret || groq.apiKey);
|
|
259
|
+
if (provider === "openai") {
|
|
260
|
+
if (isNative) {
|
|
261
|
+
if (openai.transcriptionSessionEndpoint && isOpenAINativeRecognizerAvailable()) {
|
|
262
|
+
_logger.default.info("✅ Using OpenAI Native Realtime (WebRTC)");
|
|
263
|
+
return "openai-native";
|
|
264
|
+
}
|
|
265
|
+
if (shouldWarnUnavailable) {
|
|
266
|
+
_logger.default.warn("⚠️ OpenAI native speech unavailable. Configure OPENAI_TRANSCRIPTION_SESSION_ENDPOINT and install react-native-webrtc.");
|
|
267
|
+
}
|
|
268
|
+
return "none";
|
|
269
|
+
}
|
|
270
|
+
if (isWeb) {
|
|
271
|
+
if (openai.transcriptionSessionEndpoint && (0, _speechRecognitionOpenai.isOpenAISpeechAvailable)()) {
|
|
272
|
+
_logger.default.info("✅ Using OpenAI Web Realtime (WebRTC)");
|
|
273
|
+
return "openai-web";
|
|
274
|
+
}
|
|
275
|
+
if (shouldWarnUnavailable) {
|
|
276
|
+
_logger.default.warn("⚠️ OpenAI web speech unavailable");
|
|
277
|
+
}
|
|
278
|
+
return "none";
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Native platforms: Use native Groq implementation
|
|
283
|
+
if (isNative) {
|
|
284
|
+
if (groq.enabled && hasGroqKey && isNativeRecognizerAvailable()) {
|
|
285
|
+
_logger.default.info("✅ Using Groq Native (expo-audio)");
|
|
286
|
+
return "groq-native";
|
|
287
|
+
}
|
|
288
|
+
if (shouldWarnUnavailable) {
|
|
289
|
+
_logger.default.warn("⚠️ No speech recognition available on native (install expo-audio + expo-file-system and run a dev client build)");
|
|
290
|
+
}
|
|
291
|
+
return "none";
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Web platform: Can use both, prefer based on config
|
|
295
|
+
if (isWeb) {
|
|
296
|
+
if (localModel.enabledOnWeb && localModel.baseUrl) {
|
|
297
|
+
_logger.default.info("✅ Using Local MLX Whisper server");
|
|
298
|
+
return "mlx-local";
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Use Groq if enabled and available
|
|
302
|
+
if (groq.enabled && hasGroqKey && (0, _speechRecognitionGroq.isGroqSpeechAvailable)()) {
|
|
303
|
+
_logger.default.info("✅ Using Groq Web (Enabled and available)");
|
|
304
|
+
return "groq-web";
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Fallback to Web Speech API
|
|
308
|
+
if (config.fallbackToWebSpeech && isWebSpeechAvailable()) {
|
|
309
|
+
_logger.default.info("✅ Using Web Speech API (Fallback)");
|
|
310
|
+
return "webspeech";
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
if (shouldWarnUnavailable) {
|
|
314
|
+
_logger.default.warn("⚠️ No speech recognition method available");
|
|
315
|
+
}
|
|
316
|
+
return "none";
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Unified Speech Recognizer Component
|
|
321
|
+
* Automatically selects and uses the best speech recognition method
|
|
322
|
+
*/
|
|
323
|
+
const UnifiedSpeechRecognizer = ({
|
|
324
|
+
shouldListen,
|
|
325
|
+
speechStatusCallback,
|
|
326
|
+
speechResultCallback,
|
|
327
|
+
speechTranslationCallback,
|
|
328
|
+
speechReadyCallback,
|
|
329
|
+
waveformPreviewCallback,
|
|
330
|
+
clientSecret,
|
|
331
|
+
language = "en",
|
|
332
|
+
onError,
|
|
333
|
+
requestContextProvider,
|
|
334
|
+
config
|
|
335
|
+
}) => {
|
|
336
|
+
// Get configuration
|
|
337
|
+
const resolvedConfig = getSpeechRecognitionConfig(config);
|
|
338
|
+
const isWebClientRuntime = _reactNative.Platform.OS === "web" && typeof window !== "undefined";
|
|
339
|
+
const normalizedLanguage = normalizeLanguageTag(language);
|
|
340
|
+
const apiLanguage = toShortLanguageCode(normalizedLanguage);
|
|
341
|
+
const webSpeechLanguage = toWebSpeechLocale(normalizedLanguage);
|
|
342
|
+
|
|
343
|
+
// Determine which method to use
|
|
344
|
+
const method = selectSpeechRecognitionMethod(resolvedConfig, clientSecret);
|
|
345
|
+
if (isWebClientRuntime) {
|
|
346
|
+
_logger.default.debug("Selected speech recognition method:", method);
|
|
347
|
+
}
|
|
348
|
+
const groqConfig = resolveGroqConfig(resolvedConfig);
|
|
349
|
+
const openaiConfig = resolveOpenAIConfig(resolvedConfig);
|
|
350
|
+
const localModelConfig = resolveLocalModelConfig(resolvedConfig);
|
|
351
|
+
const finalGroqApiKey = clientSecret || groqConfig.apiKey || "";
|
|
352
|
+
const groqApiBaseUrl = groqConfig.apiBaseUrl;
|
|
353
|
+
const groqTranscriptionEndpoint = groqConfig.transcriptionEndpoint;
|
|
354
|
+
const streamGroq = groqConfig.stream;
|
|
355
|
+
if (groqConfig.enabled && !finalGroqApiKey) {
|
|
356
|
+
_logger.default.warn("Groq speech is enabled but no API key was provided. Pass a non-secret client key or disable Groq speech.");
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Error handler with fallback
|
|
360
|
+
const handleError = error => {
|
|
361
|
+
_logger.default.error("Speech recognition error:", error);
|
|
362
|
+
if (onError) {
|
|
363
|
+
onError(error);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// If Groq fails and fallback is enabled, we could switch to Web Speech
|
|
367
|
+
// (This would require more complex state management)
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
// Render appropriate component based on method
|
|
371
|
+
switch (method) {
|
|
372
|
+
case "openai-native":
|
|
373
|
+
{
|
|
374
|
+
if (!openaiConfig.transcriptionSessionEndpoint) {
|
|
375
|
+
_logger.default.error("OpenAI transcription session endpoint is required but not provided");
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
const openaiNativeModule = getOpenAINativeSpeechModule();
|
|
379
|
+
if (!openaiNativeModule?.OpenAINativeSpeechRecognizer) {
|
|
380
|
+
_logger.default.error("OpenAI native speech module unavailable. Install react-native-webrtc and use a native/dev build.");
|
|
381
|
+
return null;
|
|
382
|
+
}
|
|
383
|
+
const OpenAINativeSpeechRecognizer = openaiNativeModule.OpenAINativeSpeechRecognizer;
|
|
384
|
+
return /*#__PURE__*/_react.default.createElement(OpenAINativeSpeechRecognizer, {
|
|
385
|
+
shouldListen: shouldListen,
|
|
386
|
+
speechStatusCallback: speechStatusCallback,
|
|
387
|
+
speechResultCallback: speechResultCallback,
|
|
388
|
+
speechTranslationCallback: speechTranslationCallback,
|
|
389
|
+
speechReadyCallback: speechReadyCallback,
|
|
390
|
+
clientSecret: finalGroqApiKey,
|
|
391
|
+
openaiTranscriptionSessionEndpoint: openaiConfig.transcriptionSessionEndpoint,
|
|
392
|
+
openaiTranslationEndpoint: openaiConfig.translationEndpoint,
|
|
393
|
+
openaiRealtimeWebRtcUrl: openaiConfig.realtimeWebRtcUrl,
|
|
394
|
+
openaiRealtimeModel: openaiConfig.realtimeModel,
|
|
395
|
+
openaiTranslationModel: openaiConfig.translationModel,
|
|
396
|
+
openaiVadEnabled: openaiConfig.vadEnabled,
|
|
397
|
+
openaiAutoStopOnVadSilence: openaiConfig.autoStopOnVadSilence,
|
|
398
|
+
openaiVadThreshold: openaiConfig.vadThreshold,
|
|
399
|
+
openaiVadPrefixPaddingMs: openaiConfig.vadPrefixPaddingMs,
|
|
400
|
+
openaiVadSilenceDurationMs: openaiConfig.vadSilenceDurationMs,
|
|
401
|
+
openaiVadIdleTimeoutMs: openaiConfig.vadIdleTimeoutMs,
|
|
402
|
+
openaiPrewarmOnMount: openaiConfig.prewarmOnMount,
|
|
403
|
+
language: apiLanguage,
|
|
404
|
+
requestContextProvider: requestContextProvider,
|
|
405
|
+
onError: handleError
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
case "openai-web":
|
|
409
|
+
if (!openaiConfig.transcriptionSessionEndpoint) {
|
|
410
|
+
_logger.default.error("OpenAI transcription session endpoint is required but not provided");
|
|
411
|
+
return null;
|
|
412
|
+
}
|
|
413
|
+
return /*#__PURE__*/_react.default.createElement(_speechRecognitionOpenai.OpenAISpeechRecognizer, {
|
|
414
|
+
shouldListen: shouldListen,
|
|
415
|
+
speechStatusCallback: speechStatusCallback,
|
|
416
|
+
speechResultCallback: speechResultCallback,
|
|
417
|
+
speechTranslationCallback: speechTranslationCallback,
|
|
418
|
+
speechReadyCallback: speechReadyCallback,
|
|
419
|
+
clientSecret: finalGroqApiKey,
|
|
420
|
+
openaiTranscriptionSessionEndpoint: openaiConfig.transcriptionSessionEndpoint,
|
|
421
|
+
openaiTranslationEndpoint: openaiConfig.translationEndpoint,
|
|
422
|
+
openaiRealtimeWebRtcUrl: openaiConfig.realtimeWebRtcUrl,
|
|
423
|
+
openaiRealtimeModel: openaiConfig.realtimeModel,
|
|
424
|
+
openaiTranslationModel: openaiConfig.translationModel,
|
|
425
|
+
openaiVadEnabled: openaiConfig.vadEnabled,
|
|
426
|
+
openaiAutoStopOnVadSilence: openaiConfig.autoStopOnVadSilence,
|
|
427
|
+
openaiVadThreshold: openaiConfig.vadThreshold,
|
|
428
|
+
openaiVadPrefixPaddingMs: openaiConfig.vadPrefixPaddingMs,
|
|
429
|
+
openaiVadSilenceDurationMs: openaiConfig.vadSilenceDurationMs,
|
|
430
|
+
openaiVadIdleTimeoutMs: openaiConfig.vadIdleTimeoutMs,
|
|
431
|
+
openaiPrewarmOnMount: openaiConfig.prewarmOnMount,
|
|
432
|
+
language: apiLanguage,
|
|
433
|
+
requestContextProvider: requestContextProvider,
|
|
434
|
+
onError: handleError
|
|
435
|
+
});
|
|
436
|
+
case "groq-native":
|
|
437
|
+
{
|
|
438
|
+
if (!finalGroqApiKey) {
|
|
439
|
+
_logger.default.error("Groq API key is required but not provided");
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
const nativeModule = getNativeSpeechModule();
|
|
443
|
+
if (!nativeModule?.NativeSpeechRecognizer) {
|
|
444
|
+
_logger.default.error("Native speech module is unavailable. Install expo-audio + expo-file-system and use a dev client build.");
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
const NativeSpeechRecognizer = nativeModule.NativeSpeechRecognizer;
|
|
448
|
+
return /*#__PURE__*/_react.default.createElement(NativeSpeechRecognizer, {
|
|
449
|
+
shouldListen: shouldListen,
|
|
450
|
+
speechStatusCallback: speechStatusCallback,
|
|
451
|
+
speechResultCallback: speechResultCallback,
|
|
452
|
+
speechTranslationCallback: speechTranslationCallback,
|
|
453
|
+
clientSecret: finalGroqApiKey,
|
|
454
|
+
groqApiBaseUrl: groqApiBaseUrl,
|
|
455
|
+
groqTranscriptionEndpoint: groqTranscriptionEndpoint,
|
|
456
|
+
stream: streamGroq,
|
|
457
|
+
language: apiLanguage,
|
|
458
|
+
onError: handleError
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
case "groq-web":
|
|
462
|
+
if (!finalGroqApiKey) {
|
|
463
|
+
_logger.default.error("Groq API key is required but not provided");
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
return /*#__PURE__*/_react.default.createElement(_speechRecognitionGroq.GroqSpeechRecognizer, {
|
|
467
|
+
shouldListen: shouldListen,
|
|
468
|
+
speechStatusCallback: speechStatusCallback,
|
|
469
|
+
speechResultCallback: speechResultCallback,
|
|
470
|
+
speechTranslationCallback: speechTranslationCallback,
|
|
471
|
+
clientSecret: finalGroqApiKey,
|
|
472
|
+
groqApiBaseUrl: groqApiBaseUrl,
|
|
473
|
+
groqTranscriptionEndpoint: groqTranscriptionEndpoint,
|
|
474
|
+
stream: streamGroq,
|
|
475
|
+
language: apiLanguage,
|
|
476
|
+
onError: handleError
|
|
477
|
+
});
|
|
478
|
+
case "mlx-local":
|
|
479
|
+
{
|
|
480
|
+
const effectiveUrl = localModelConfig.baseUrl;
|
|
481
|
+
if (!effectiveUrl) {
|
|
482
|
+
_logger.default.error("Local whisper URL is required but not provided");
|
|
483
|
+
return null;
|
|
484
|
+
}
|
|
485
|
+
return /*#__PURE__*/_react.default.createElement(_speechRecognitionMlx.MLXSpeechRecognizer, {
|
|
486
|
+
shouldListen: shouldListen,
|
|
487
|
+
speechStatusCallback: speechStatusCallback,
|
|
488
|
+
speechResultCallback: speechResultCallback,
|
|
489
|
+
language: apiLanguage,
|
|
490
|
+
onError: handleError,
|
|
491
|
+
baseUrl: effectiveUrl,
|
|
492
|
+
mode: localModelConfig.mode,
|
|
493
|
+
modelName: localModelConfig.model
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
case "webspeech":
|
|
497
|
+
return /*#__PURE__*/_react.default.createElement(_speechRecognition.SpeechRecognizer, {
|
|
498
|
+
shouldListen: shouldListen,
|
|
499
|
+
speechStatusCallback: speechStatusCallback,
|
|
500
|
+
speechResultCallback: speechResultCallback,
|
|
501
|
+
language: webSpeechLanguage
|
|
502
|
+
});
|
|
503
|
+
case "none":
|
|
504
|
+
default:
|
|
505
|
+
if (isWebClientRuntime) {
|
|
506
|
+
_logger.default.warn("No speech recognition available");
|
|
507
|
+
}
|
|
508
|
+
return null;
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Get speech recognition status and capabilities
|
|
514
|
+
*/
|
|
515
|
+
exports.UnifiedSpeechRecognizer = UnifiedSpeechRecognizer;
|
|
516
|
+
function getSpeechRecognitionStatus(overrides) {
|
|
517
|
+
const config = getSpeechRecognitionConfig(overrides);
|
|
518
|
+
const method = selectSpeechRecognitionMethod(config);
|
|
519
|
+
const localModel = resolveLocalModelConfig(config);
|
|
520
|
+
return {
|
|
521
|
+
method,
|
|
522
|
+
config,
|
|
523
|
+
capabilities: {
|
|
524
|
+
groq: (0, _speechRecognitionGroq.getGroqSpeechCapabilities)(),
|
|
525
|
+
openai: (0, _speechRecognitionOpenai.getOpenAISpeechCapabilities)(),
|
|
526
|
+
webSpeech: {
|
|
527
|
+
available: isWebSpeechAvailable(),
|
|
528
|
+
platform: _reactNative.Platform.OS
|
|
529
|
+
},
|
|
530
|
+
localModel: {
|
|
531
|
+
enabled: !!localModel.enabledOnWeb,
|
|
532
|
+
url: localModel.baseUrl,
|
|
533
|
+
mode: localModel.mode || "oneshot"
|
|
534
|
+
}
|
|
535
|
+
},
|
|
536
|
+
recommendations: getRecommendations(method, config)
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Get recommendations for improving speech recognition
|
|
542
|
+
*/
|
|
543
|
+
function getRecommendations(method, config) {
|
|
544
|
+
const recommendations = [];
|
|
545
|
+
if (method === "none") {
|
|
546
|
+
recommendations.push("No speech recognition available");
|
|
547
|
+
if (!config.groq?.apiKey && config.provider !== "openai") {
|
|
548
|
+
recommendations.push("Provide a Groq client secret via config or disable Groq speech");
|
|
549
|
+
}
|
|
550
|
+
if (_reactNative.Platform.OS === "web") {
|
|
551
|
+
if (!(0, _speechRecognitionGroq.isGroqSpeechAvailable)()) {
|
|
552
|
+
recommendations.push("Browser does not support MediaRecorder API");
|
|
553
|
+
}
|
|
554
|
+
if (!isWebSpeechAvailable()) {
|
|
555
|
+
recommendations.push("Browser does not support Web Speech API");
|
|
556
|
+
}
|
|
557
|
+
} else {
|
|
558
|
+
recommendations.push("Install expo-audio + expo-file-system and use a dev client build");
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
if (method === "webspeech") {
|
|
562
|
+
recommendations.push("Using Web Speech API (free but less accurate)");
|
|
563
|
+
recommendations.push("Enable Groq speech for better accuracy");
|
|
564
|
+
}
|
|
565
|
+
if (method === "groq-web") {
|
|
566
|
+
recommendations.push("Using Groq Web (high accuracy, best for web)");
|
|
567
|
+
}
|
|
568
|
+
if (method === "groq-native") {
|
|
569
|
+
recommendations.push("Using Groq Native capture (expo-audio)");
|
|
570
|
+
}
|
|
571
|
+
if (method === "openai-web") {
|
|
572
|
+
recommendations.push("Using OpenAI Web Realtime with server VAD");
|
|
573
|
+
}
|
|
574
|
+
if (method === "openai-native") {
|
|
575
|
+
recommendations.push("Using OpenAI Native Realtime with PCM stream");
|
|
576
|
+
}
|
|
577
|
+
if (method === "mlx-local") {
|
|
578
|
+
recommendations.push("Using Local MLX Whisper server (fast, offline)");
|
|
579
|
+
if (!config.localModel?.baseUrl) {
|
|
580
|
+
recommendations.push("Set LOCAL_WHISPER_URL to point at your server");
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
return recommendations;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// Export for convenience
|
|
587
|
+
// Default export
|
|
588
|
+
var _default = exports.default = UnifiedSpeechRecognizer;
|
|
589
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9yZWFjdE5hdGl2ZSIsIl9zcGVlY2hSZWNvZ25pdGlvbiIsIl9zcGVlY2hSZWNvZ25pdGlvbkdyb3EiLCJfc3BlZWNoUmVjb2duaXRpb25NbHgiLCJfc3BlZWNoUmVjb2duaXRpb25PcGVuYWkiLCJfbG9nZ2VyIiwiZSIsIl9fZXNNb2R1bGUiLCJkZWZhdWx0Iiwib3duS2V5cyIsInIiLCJ0IiwiT2JqZWN0Iiwia2V5cyIsImdldE93blByb3BlcnR5U3ltYm9scyIsIm8iLCJmaWx0ZXIiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJlbnVtZXJhYmxlIiwicHVzaCIsImFwcGx5IiwiX29iamVjdFNwcmVhZCIsImFyZ3VtZW50cyIsImxlbmd0aCIsImZvckVhY2giLCJfZGVmaW5lUHJvcGVydHkiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzIiwiZGVmaW5lUHJvcGVydGllcyIsImRlZmluZVByb3BlcnR5IiwiX3RvUHJvcGVydHlLZXkiLCJ2YWx1ZSIsImNvbmZpZ3VyYWJsZSIsIndyaXRhYmxlIiwiaSIsIl90b1ByaW1pdGl2ZSIsIlN5bWJvbCIsInRvUHJpbWl0aXZlIiwiY2FsbCIsIlR5cGVFcnJvciIsIlN0cmluZyIsIk51bWJlciIsIm5vcm1hbGl6ZVByb3ZpZGVyIiwidW5kZWZpbmVkIiwibm9ybWFsaXplZCIsInRyaW0iLCJ0b0xvd2VyQ2FzZSIsIkRFRkFVTFRfUkVBTFRJTUVfTU9ERUwiLCJERUZBVUxUX1RSQU5TTEFUSU9OX01PREVMIiwiREVGQVVMVF9PUEVOQUlfQVVUT19TVE9QX09OX1ZBRF9TSUxFTkNFIiwiREVGQVVMVF9PUEVOQUlfVkFEX1NJTEVOQ0VfRFVSQVRJT05fTVMiLCJERUZBVUxUX09QRU5BSV9QUkVXQVJNX09OX01PVU5UIiwiZ2V0UnVudGltZUVudlZhbHVlIiwia2V5IiwiZW52IiwicHJvY2VzcyIsInRyaW1tZWQiLCJwYXJzZUJvb2xlYW5FbnYiLCJmYWxsYmFjayIsInJhdyIsInBhcnNlTnVtYmVyRW52IiwicGFyc2VkIiwiaXNGaW5pdGUiLCJ0b09wZW5BSUVuZHBvaW50c0Zyb21CYXNlVXJsIiwiYmFzZVVybCIsInJlcGxhY2UiLCJ0cmFuc2NyaXB0aW9uU2Vzc2lvbkVuZHBvaW50IiwidHJhbnNsYXRpb25FbmRwb2ludCIsInJlc29sdmVPcGVuQUlDb25maWciLCJjb25maWciLCJkZWZhdWx0cyIsInJlYWx0aW1lTW9kZWwiLCJ0cmFuc2xhdGlvbk1vZGVsIiwidmFkRW5hYmxlZCIsImF1dG9TdG9wT25WYWRTaWxlbmNlIiwidmFkVGhyZXNob2xkIiwidmFkUHJlZml4UGFkZGluZ01zIiwidmFkU2lsZW5jZUR1cmF0aW9uTXMiLCJ2YWRJZGxlVGltZW91dE1zIiwicHJld2FybU9uTW91bnQiLCJuZXN0ZWQiLCJvcGVuYWkiLCJlbmRwb2ludEJhc2UiLCJwcm94eUJhc2VVcmwiLCJkZXJpdmVkRW5kcG9pbnRzIiwicmVhbHRpbWVXZWJSdGNVcmwiLCJyZXNvbHZlR3JvcUNvbmZpZyIsImVuYWJsZWQiLCJzdHJlYW0iLCJncm9xIiwicmVzb2x2ZUxvY2FsTW9kZWxDb25maWciLCJlbmFibGVkT25XZWIiLCJtb2RlIiwibW9kZWwiLCJsb2NhbE1vZGVsIiwiZ2V0U3BlZWNoUmVjb2duaXRpb25Db25maWciLCJvdmVycmlkZXMiLCJwcm92aWRlciIsImZhbGxiYWNrVG9XZWJTcGVlY2giLCJtZXJnZWQiLCJjaGVja1dlYlNwZWVjaEF2YWlsYWJpbGl0eSIsIndpbmRvdyIsImlzV2ViU3BlZWNoQXZhaWxhYmxlIiwiZXhwb3J0cyIsIm5vcm1hbGl6ZUxhbmd1YWdlVGFnIiwibGFuZyIsInRvU2hvcnRMYW5ndWFnZUNvZGUiLCJzcGxpdCIsInRvV2ViU3BlZWNoTG9jYWxlIiwic3RhcnRzV2l0aCIsIm5hdGl2ZVNwZWVjaE1vZHVsZUNhY2hlIiwib3BlbkFpTmF0aXZlU3BlZWNoTW9kdWxlQ2FjaGUiLCJnZXROYXRpdmVTcGVlY2hNb2R1bGUiLCJlcnJvciIsImxvZ2dlciIsImRlYnVnIiwiaXNOYXRpdmVSZWNvZ25pemVyQXZhaWxhYmxlIiwibmF0aXZlTW9kdWxlIiwiaXNOYXRpdmVTcGVlY2hBdmFpbGFibGUiLCJnZXRPcGVuQUlOYXRpdmVTcGVlY2hNb2R1bGUiLCJpc09wZW5BSU5hdGl2ZVJlY29nbml6ZXJBdmFpbGFibGUiLCJpc09wZW5BSU5hdGl2ZVNwZWVjaEF2YWlsYWJsZSIsInNlbGVjdFNwZWVjaFJlY29nbml0aW9uTWV0aG9kIiwiY2xpZW50U2VjcmV0IiwiaXNXZWIiLCJQbGF0Zm9ybSIsIk9TIiwiaXNOYXRpdmUiLCJpc1dlYkNsaWVudFJ1bnRpbWUiLCJzaG91bGRXYXJuVW5hdmFpbGFibGUiLCJoYXNHcm9xS2V5IiwiYXBpS2V5IiwiaW5mbyIsIndhcm4iLCJpc09wZW5BSVNwZWVjaEF2YWlsYWJsZSIsImlzR3JvcVNwZWVjaEF2YWlsYWJsZSIsIlVuaWZpZWRTcGVlY2hSZWNvZ25pemVyIiwic2hvdWxkTGlzdGVuIiwic3BlZWNoU3RhdHVzQ2FsbGJhY2siLCJzcGVlY2hSZXN1bHRDYWxsYmFjayIsInNwZWVjaFRyYW5zbGF0aW9uQ2FsbGJhY2siLCJzcGVlY2hSZWFkeUNhbGxiYWNrIiwid2F2ZWZvcm1QcmV2aWV3Q2FsbGJhY2siLCJsYW5ndWFnZSIsIm9uRXJyb3IiLCJyZXF1ZXN0Q29udGV4dFByb3ZpZGVyIiwicmVzb2x2ZWRDb25maWciLCJub3JtYWxpemVkTGFuZ3VhZ2UiLCJhcGlMYW5ndWFnZSIsIndlYlNwZWVjaExhbmd1YWdlIiwibWV0aG9kIiwiZ3JvcUNvbmZpZyIsIm9wZW5haUNvbmZpZyIsImxvY2FsTW9kZWxDb25maWciLCJmaW5hbEdyb3FBcGlLZXkiLCJncm9xQXBpQmFzZVVybCIsImFwaUJhc2VVcmwiLCJncm9xVHJhbnNjcmlwdGlvbkVuZHBvaW50IiwidHJhbnNjcmlwdGlvbkVuZHBvaW50Iiwic3RyZWFtR3JvcSIsImhhbmRsZUVycm9yIiwib3BlbmFpTmF0aXZlTW9kdWxlIiwiT3BlbkFJTmF0aXZlU3BlZWNoUmVjb2duaXplciIsImNyZWF0ZUVsZW1lbnQiLCJvcGVuYWlUcmFuc2NyaXB0aW9uU2Vzc2lvbkVuZHBvaW50Iiwib3BlbmFpVHJhbnNsYXRpb25FbmRwb2ludCIsIm9wZW5haVJlYWx0aW1lV2ViUnRjVXJsIiwib3BlbmFpUmVhbHRpbWVNb2RlbCIsIm9wZW5haVRyYW5zbGF0aW9uTW9kZWwiLCJvcGVuYWlWYWRFbmFibGVkIiwib3BlbmFpQXV0b1N0b3BPblZhZFNpbGVuY2UiLCJvcGVuYWlWYWRUaHJlc2hvbGQiLCJvcGVuYWlWYWRQcmVmaXhQYWRkaW5nTXMiLCJvcGVuYWlWYWRTaWxlbmNlRHVyYXRpb25NcyIsIm9wZW5haVZhZElkbGVUaW1lb3V0TXMiLCJvcGVuYWlQcmV3YXJtT25Nb3VudCIsIk9wZW5BSVNwZWVjaFJlY29nbml6ZXIiLCJOYXRpdmVTcGVlY2hSZWNvZ25pemVyIiwiR3JvcVNwZWVjaFJlY29nbml6ZXIiLCJlZmZlY3RpdmVVcmwiLCJNTFhTcGVlY2hSZWNvZ25pemVyIiwibW9kZWxOYW1lIiwiU3BlZWNoUmVjb2duaXplciIsImdldFNwZWVjaFJlY29nbml0aW9uU3RhdHVzIiwiY2FwYWJpbGl0aWVzIiwiZ2V0R3JvcVNwZWVjaENhcGFiaWxpdGllcyIsImdldE9wZW5BSVNwZWVjaENhcGFiaWxpdGllcyIsIndlYlNwZWVjaCIsImF2YWlsYWJsZSIsInBsYXRmb3JtIiwidXJsIiwicmVjb21tZW5kYXRpb25zIiwiZ2V0UmVjb21tZW5kYXRpb25zIiwiX2RlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvc3BlZWNoLXJlY29nbml0aW9uL3NwZWVjaC1yZWNvZ25pdGlvbi11bmlmaWVkLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFVuaWZpZWQgU3BlZWNoIFJlY29nbml0aW9uIENvbXBvbmVudFxuICogQXV0b21hdGljYWxseSBzZWxlY3RzIGJlc3Qgc3BlZWNoIHJlY29nbml0aW9uIG1ldGhvZCBiYXNlZCBvbjpcbiAqIDEuIFBsYXRmb3JtIChXZWIgdnMgTmF0aXZlKVxuICogMi4gRW52aXJvbm1lbnQgY29uZmlndXJhdGlvblxuICogMy4gRmVhdHVyZSBhdmFpbGFiaWxpdHlcbiAqL1xuXG5pbXBvcnQgUmVhY3QgZnJvbSBcInJlYWN0XCI7XG5pbXBvcnQgeyBQbGF0Zm9ybSB9IGZyb20gXCJyZWFjdC1uYXRpdmVcIjtcbmltcG9ydCB7IFNwZWVjaFJlY29nbml6ZXIgYXMgV2ViU3BlZWNoUmVjb2duaXplciB9IGZyb20gXCIuLi9zcGVlY2gtcmVjb2duaXRpb25cIjtcbmltcG9ydCB7XG4gIEdyb3FTcGVlY2hSZWNvZ25pemVyLFxuICBpc0dyb3FTcGVlY2hBdmFpbGFibGUsXG4gIGdldEdyb3FTcGVlY2hDYXBhYmlsaXRpZXMsXG59IGZyb20gXCIuL3NwZWVjaC1yZWNvZ25pdGlvbi1ncm9xXCI7XG5pbXBvcnQge1xuICBNTFhTcGVlY2hSZWNvZ25pemVyLFxuICB0eXBlIExvY2FsV2hpc3Blck1vZGUsXG59IGZyb20gXCIuL3NwZWVjaC1yZWNvZ25pdGlvbi1tbHhcIjtcbmltcG9ydCB7XG4gIE9wZW5BSVNwZWVjaFJlY29nbml6ZXIsXG4gIGlzT3BlbkFJU3BlZWNoQXZhaWxhYmxlLFxuICBnZXRPcGVuQUlTcGVlY2hDYXBhYmlsaXRpZXMsXG59IGZyb20gXCIuL3NwZWVjaC1yZWNvZ25pdGlvbi1vcGVuYWlcIjtcbmltcG9ydCBsb2dnZXIgZnJvbSBcIi4uL2xvZ2dlclwiO1xuXG5leHBvcnQgaW50ZXJmYWNlIFVuaWZpZWRTcGVlY2hSZWNvZ25pemVyUHJvcHMge1xuICBzaG91bGRMaXN0ZW46IGJvb2xlYW47XG4gIHNwZWVjaFN0YXR1c0NhbGxiYWNrOiAoc3RhdHVzOiBib29sZWFuLCB0cmFuc2NyaXB0OiBzdHJpbmcpID0+IHZvaWQ7XG4gIHNwZWVjaFJlc3VsdENhbGxiYWNrOiAocmVzdWx0OiBzdHJpbmcpID0+IHZvaWQ7XG4gIHNwZWVjaFRyYW5zbGF0aW9uQ2FsbGJhY2s/OiAodHJhbnNsYXRpb246IHN0cmluZykgPT4gdm9pZDtcbiAgc3BlZWNoUmVhZHlDYWxsYmFjaz86IChyZWFkeTogYm9vbGVhbikgPT4gdm9pZDtcbiAgd2F2ZWZvcm1QcmV2aWV3Q2FsbGJhY2s/OiAod2F2ZWZvcm06IG51bWJlcltdKSA9PiB2b2lkO1xuICBjbGllbnRTZWNyZXQ/OiBzdHJpbmc7XG4gIGxhbmd1YWdlPzogc3RyaW5nO1xuICBvbkVycm9yPzogKGVycm9yOiBFcnJvcikgPT4gdm9pZDtcbiAgcmVxdWVzdENvbnRleHRQcm92aWRlcj86ICgpID0+XG4gICAgfCB7XG4gICAgICAgIHRocmVhZElkPzogc3RyaW5nIHwgbnVsbDtcbiAgICAgICAgdHVybklkPzogc3RyaW5nIHwgbnVsbDtcbiAgICAgICAgc2Vzc2lvbklkPzogc3RyaW5nIHwgbnVtYmVyIHwgbnVsbDtcbiAgICAgICAgc2VudHJ5VHJhY2U/OiBzdHJpbmcgfCBudWxsO1xuICAgICAgICBiYWdnYWdlPzogc3RyaW5nIHwgbnVsbDtcbiAgICAgIH1cbiAgICB8IG51bGxcbiAgICB8IHVuZGVmaW5lZDtcbiAgLy8gT3B0aW9uYWwgcnVudGltZSBjb25maWcgb3ZlcnJpZGVzXG4gIGNvbmZpZz86IFNwZWVjaFJlY29nbml0aW9uQ29uZmlnO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEdyb3FDb25maWdQcm9wcyB7XG4gIGVuYWJsZWQ/OiBib29sZWFuO1xuICBhcGlLZXk/OiBzdHJpbmc7XG4gIGFwaUJhc2VVcmw/OiBzdHJpbmc7XG4gIHRyYW5zY3JpcHRpb25FbmRwb2ludD86IHN0cmluZztcbiAgc3RyZWFtPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBPcGVuQUlDb25maWdQcm9wcyB7XG4gIHByb3h5QmFzZVVybD86IHN0cmluZztcbiAgdHJhbnNjcmlwdGlvblNlc3Npb25FbmRwb2ludD86IHN0cmluZztcbiAgdHJhbnNsYXRpb25FbmRwb2ludD86IHN0cmluZztcbiAgcmVhbHRpbWVXZWJSdGNVcmw/OiBzdHJpbmc7XG4gIHJlYWx0aW1lTW9kZWw/OiBcImdwdC00by10cmFuc2NyaWJlXCIgfCBcImdwdC00by1taW5pLXRyYW5zY3JpYmVcIjtcbiAgdHJhbnNsYXRpb25Nb2RlbD86IHN0cmluZztcbiAgdmFkRW5hYmxlZD86IGJvb2xlYW47XG4gIGF1dG9TdG9wT25WYWRTaWxlbmNlPzogYm9vbGVhbjtcbiAgdmFkVGhyZXNob2xkPzogbnVtYmVyO1xuICB2YWRQcmVmaXhQYWRkaW5nTXM/OiBudW1iZXI7XG4gIHZhZFNpbGVuY2VEdXJhdGlvbk1zPzogbnVtYmVyO1xuICB2YWRJZGxlVGltZW91dE1zPzogbnVtYmVyO1xuICBwcmV3YXJtT25Nb3VudD86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTG9jYWxNb2RlbENvbmZpZ1Byb3BzIHtcbiAgZW5hYmxlZE9uV2ViPzogYm9vbGVhbjtcbiAgYmFzZVVybD86IHN0cmluZztcbiAgbW9kZT86IExvY2FsV2hpc3Blck1vZGU7XG4gIG1vZGVsPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIENvbmZpZ3VyYXRpb24gZm9yIHNwZWVjaCByZWNvZ25pdGlvbi5cbiAqIFJlc29sdmVkIGZyb20gaW4tY29kZSBkZWZhdWx0cyArIGV4cGxpY2l0IHJ1bnRpbWUgb3ZlcnJpZGVzIHBhc3NlZCB2aWEgcHJvcHMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3BlZWNoUmVjb2duaXRpb25Db25maWcge1xuICAvLyBTcGVlY2ggcHJvdmlkZXJcbiAgcHJvdmlkZXI/OiBcImdyb3FcIiB8IFwib3BlbmFpXCI7XG4gIC8vIEZhbGxiYWNrIHRvIHdlYiBzcGVlY2ggaWYgR3JvcSBmYWlsc1xuICBmYWxsYmFja1RvV2ViU3BlZWNoPzogYm9vbGVhbjtcbiAgLy8gUHJvdmlkZXItc3BlY2lmaWMgbmVzdGVkIGNvbmZpZ3NcbiAgZ3JvcT86IEdyb3FDb25maWdQcm9wcztcbiAgb3BlbmFpPzogT3BlbkFJQ29uZmlnUHJvcHM7XG4gIGxvY2FsTW9kZWw/OiBMb2NhbE1vZGVsQ29uZmlnUHJvcHM7XG59XG5cbmZ1bmN0aW9uIG5vcm1hbGl6ZVByb3ZpZGVyKFxuICB2YWx1ZT86IHN0cmluZyxcbik6IFwiZ3JvcVwiIHwgXCJvcGVuYWlcIiB8IHVuZGVmaW5lZCB7XG4gIGlmICghdmFsdWUpIHJldHVybiB1bmRlZmluZWQ7XG4gIGNvbnN0IG5vcm1hbGl6ZWQgPSB2YWx1ZS50cmltKCkudG9Mb3dlckNhc2UoKTtcbiAgaWYgKG5vcm1hbGl6ZWQgPT09IFwiZ3JvcVwiKSByZXR1cm4gXCJncm9xXCI7XG4gIGlmIChub3JtYWxpemVkID09PSBcIm9wZW5haVwiKSByZXR1cm4gXCJvcGVuYWlcIjtcbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuY29uc3QgREVGQVVMVF9SRUFMVElNRV9NT0RFTDogT3BlbkFJQ29uZmlnUHJvcHNbXCJyZWFsdGltZU1vZGVsXCJdID1cbiAgXCJncHQtNG8tdHJhbnNjcmliZVwiO1xuY29uc3QgREVGQVVMVF9UUkFOU0xBVElPTl9NT0RFTCA9IFwiZ3B0LTQuMS1taW5pXCI7XG5jb25zdCBERUZBVUxUX09QRU5BSV9BVVRPX1NUT1BfT05fVkFEX1NJTEVOQ0UgPSBmYWxzZTtcbmNvbnN0IERFRkFVTFRfT1BFTkFJX1ZBRF9TSUxFTkNFX0RVUkFUSU9OX01TID0gMjAwMDtcbmNvbnN0IERFRkFVTFRfT1BFTkFJX1BSRVdBUk1fT05fTU9VTlQgPSB0cnVlO1xuXG5mdW5jdGlvbiBnZXRSdW50aW1lRW52VmFsdWUoa2V5OiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICB0cnkge1xuICAgIGNvbnN0IGVudiA9IHR5cGVvZiBwcm9jZXNzICE9PSBcInVuZGVmaW5lZFwiID8gcHJvY2Vzcy5lbnYgOiB1bmRlZmluZWQ7XG4gICAgY29uc3QgdmFsdWUgPSBlbnY/LltrZXldO1xuICAgIGlmICh0eXBlb2YgdmFsdWUgIT09IFwic3RyaW5nXCIpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgY29uc3QgdHJpbW1lZCA9IHZhbHVlLnRyaW0oKTtcbiAgICByZXR1cm4gdHJpbW1lZC5sZW5ndGggPiAwID8gdHJpbW1lZCA6IHVuZGVmaW5lZDtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG5mdW5jdGlvbiBwYXJzZUJvb2xlYW5FbnYoXG4gIGtleTogc3RyaW5nLFxuICBmYWxsYmFjazogYm9vbGVhblxuKTogYm9vbGVhbiB7XG4gIGNvbnN0IHJhdyA9IGdldFJ1bnRpbWVFbnZWYWx1ZShrZXkpO1xuICBpZiAoIXJhdykgcmV0dXJuIGZhbGxiYWNrO1xuICBjb25zdCBub3JtYWxpemVkID0gcmF3LnRvTG93ZXJDYXNlKCk7XG4gIGlmIChub3JtYWxpemVkID09PSBcInRydWVcIiB8fCBub3JtYWxpemVkID09PSBcIjFcIiB8fCBub3JtYWxpemVkID09PSBcInllc1wiIHx8IG5vcm1hbGl6ZWQgPT09IFwib25cIikge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG4gIGlmIChub3JtYWxpemVkID09PSBcImZhbHNlXCIgfHwgbm9ybWFsaXplZCA9PT0gXCIwXCIgfHwgbm9ybWFsaXplZCA9PT0gXCJub1wiIHx8IG5vcm1hbGl6ZWQgPT09IFwib2ZmXCIpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgcmV0dXJuIGZhbGxiYWNrO1xufVxuXG5mdW5jdGlvbiBwYXJzZU51bWJlckVudihcbiAga2V5OiBzdHJpbmcsXG4gIGZhbGxiYWNrOiBudW1iZXJcbik6IG51bWJlciB7XG4gIGNvbnN0IHJhdyA9IGdldFJ1bnRpbWVFbnZWYWx1ZShrZXkpO1xuICBpZiAoIXJhdykgcmV0dXJuIGZhbGxiYWNrO1xuICBjb25zdCBwYXJzZWQgPSBOdW1iZXIocmF3KTtcbiAgaWYgKCFOdW1iZXIuaXNGaW5pdGUocGFyc2VkKSkgcmV0dXJuIGZhbGxiYWNrO1xuICByZXR1cm4gcGFyc2VkO1xufVxuXG5jb25zdCB0b09wZW5BSUVuZHBvaW50c0Zyb21CYXNlVXJsID0gKGJhc2VVcmw/OiBzdHJpbmcpID0+IHtcbiAgY29uc3QgdHJpbW1lZCA9IChiYXNlVXJsIHx8IFwiXCIpLnRyaW0oKS5yZXBsYWNlKC9cXC8rJC8sIFwiXCIpO1xuICBpZiAoIXRyaW1tZWQpIHtcbiAgICByZXR1cm4ge1xuICAgICAgdHJhbnNjcmlwdGlvblNlc3Npb25FbmRwb2ludDogdW5kZWZpbmVkLFxuICAgICAgdHJhbnNsYXRpb25FbmRwb2ludDogdW5kZWZpbmVkLFxuICAgIH07XG4gIH1cbiAgcmV0dXJuIHtcbiAgICB0cmFuc2NyaXB0aW9uU2Vzc2lvbkVuZHBvaW50OiBgJHt0cmltbWVkfS9vcGVuYWkvdjEvcmVhbHRpbWUvdHJhbnNjcmlwdGlvbl9zZXNzaW9uc2AsXG4gICAgdHJhbnNsYXRpb25FbmRwb2ludDogYCR7dHJpbW1lZH0vb3BlbmFpL3YxL3NwZWVjaC90cmFuc2xhdGUtdG8tZW5nbGlzaGAsXG4gIH07XG59O1xuXG5mdW5jdGlvbiByZXNvbHZlT3BlbkFJQ29uZmlnKFxuICBjb25maWc/OiBQYXJ0aWFsPFNwZWVjaFJlY29nbml0aW9uQ29uZmlnPixcbik6IE9wZW5BSUNvbmZpZ1Byb3BzIHtcbiAgY29uc3QgZGVmYXVsdHM6IE9wZW5BSUNvbmZpZ1Byb3BzID0ge1xuICAgIHJlYWx0aW1lTW9kZWw6IERFRkFVTFRfUkVBTFRJTUVfTU9ERUwsXG4gICAgdHJhbnNsYXRpb25Nb2RlbDogREVGQVVMVF9UUkFOU0xBVElPTl9NT0RFTCxcbiAgICB2YWRFbmFibGVkOiB0cnVlLFxuICAgIGF1dG9TdG9wT25WYWRTaWxlbmNlOiBwYXJzZUJvb2xlYW5FbnYoXG4gICAgICBcIk9QRU5BSV9BVVRPX1NUT1BfT05fVkFEX1NJTEVOQ0VcIixcbiAgICAgIERFRkFVTFRfT1BFTkFJX0FVVE9fU1RPUF9PTl9WQURfU0lMRU5DRVxuICAgICksXG4gICAgdmFkVGhyZXNob2xkOiAwLjcsXG4gICAgdmFkUHJlZml4UGFkZGluZ01zOiA0MDAsXG4gICAgdmFkU2lsZW5jZUR1cmF0aW9uTXM6IHBhcnNlTnVtYmVyRW52KFxuICAgICAgXCJPUEVOQUlfVkFEX1NJTEVOQ0VfRFVSQVRJT05fTVNcIixcbiAgICAgIERFRkFVTFRfT1BFTkFJX1ZBRF9TSUxFTkNFX0RVUkFUSU9OX01TXG4gICAgKSxcbiAgICB2YWRJZGxlVGltZW91dE1zOiA2MDAwLFxuICAgIHByZXdhcm1Pbk1vdW50OiBwYXJzZUJvb2xlYW5FbnYoXG4gICAgICBcIk9QRU5BSV9QUkVXQVJNX09OX01PVU5UXCIsXG4gICAgICBERUZBVUxUX09QRU5BSV9QUkVXQVJNX09OX01PVU5UXG4gICAgKSxcbiAgfTtcblxuICBjb25zdCBuZXN0ZWQgPSBjb25maWc/Lm9wZW5haSB8fCB7fTtcbiAgY29uc3QgZW5kcG9pbnRCYXNlID0gbmVzdGVkLnByb3h5QmFzZVVybDtcbiAgY29uc3QgZGVyaXZlZEVuZHBvaW50cyA9IHRvT3BlbkFJRW5kcG9pbnRzRnJvbUJhc2VVcmwoZW5kcG9pbnRCYXNlKTtcblxuICByZXR1cm4ge1xuICAgIC4uLmRlZmF1bHRzLFxuICAgIC4uLm5lc3RlZCxcbiAgICB0cmFuc2NyaXB0aW9uU2Vzc2lvbkVuZHBvaW50OlxuICAgICAgbmVzdGVkLnRyYW5zY3JpcHRpb25TZXNzaW9uRW5kcG9pbnQgfHxcbiAgICAgIGRlcml2ZWRFbmRwb2ludHMudHJhbnNjcmlwdGlvblNlc3Npb25FbmRwb2ludCxcbiAgICB0cmFuc2xhdGlvbkVuZHBvaW50OlxuICAgICAgbmVzdGVkLnRyYW5zbGF0aW9uRW5kcG9pbnQgfHwgZGVyaXZlZEVuZHBvaW50cy50cmFuc2xhdGlvbkVuZHBvaW50LFxuICAgIHJlYWx0aW1lV2ViUnRjVXJsOiBuZXN0ZWQucmVhbHRpbWVXZWJSdGNVcmwsXG4gICAgcmVhbHRpbWVNb2RlbDogbmVzdGVkLnJlYWx0aW1lTW9kZWwgfHwgZGVmYXVsdHMucmVhbHRpbWVNb2RlbCxcbiAgICB0cmFuc2xhdGlvbk1vZGVsOiBuZXN0ZWQudHJhbnNsYXRpb25Nb2RlbCB8fCBkZWZhdWx0cy50cmFuc2xhdGlvbk1vZGVsLFxuICAgIHZhZEVuYWJsZWQ6IG5lc3RlZC52YWRFbmFibGVkID8/IGRlZmF1bHRzLnZhZEVuYWJsZWQsXG4gICAgYXV0b1N0b3BPblZhZFNpbGVuY2U6XG4gICAgICBuZXN0ZWQuYXV0b1N0b3BPblZhZFNpbGVuY2UgPz8gZGVmYXVsdHMuYXV0b1N0b3BPblZhZFNpbGVuY2UsXG4gICAgdmFkVGhyZXNob2xkOiBuZXN0ZWQudmFkVGhyZXNob2xkID8/IGRlZmF1bHRzLnZhZFRocmVzaG9sZCxcbiAgICB2YWRQcmVmaXhQYWRkaW5nTXM6XG4gICAgICBuZXN0ZWQudmFkUHJlZml4UGFkZGluZ01zID8/IGRlZmF1bHRzLnZhZFByZWZpeFBhZGRpbmdNcyxcbiAgICB2YWRTaWxlbmNlRHVyYXRpb25NczpcbiAgICAgIG5lc3RlZC52YWRTaWxlbmNlRHVyYXRpb25NcyA/PyBkZWZhdWx0cy52YWRTaWxlbmNlRHVyYXRpb25NcyxcbiAgICB2YWRJZGxlVGltZW91dE1zOlxuICAgICAgbmVzdGVkLnZhZElkbGVUaW1lb3V0TXMgPz8gZGVmYXVsdHMudmFkSWRsZVRpbWVvdXRNcyxcbiAgICBwcmV3YXJtT25Nb3VudDpcbiAgICAgIG5lc3RlZC5wcmV3YXJtT25Nb3VudCA/PyBkZWZhdWx0cy5wcmV3YXJtT25Nb3VudCxcbiAgfTtcbn1cblxuZnVuY3Rpb24gcmVzb2x2ZUdyb3FDb25maWcoXG4gIGNvbmZpZz86IFBhcnRpYWw8U3BlZWNoUmVjb2duaXRpb25Db25maWc+LFxuKTogR3JvcUNvbmZpZ1Byb3BzIHtcbiAgY29uc3QgZGVmYXVsdHM6IEdyb3FDb25maWdQcm9wcyA9IHtcbiAgICBlbmFibGVkOiB0cnVlLFxuICAgIHN0cmVhbTogdHJ1ZSxcbiAgfTtcblxuICByZXR1cm4ge1xuICAgIC4uLmRlZmF1bHRzLFxuICAgIC4uLihjb25maWc/Lmdyb3EgfHwge30pLFxuICB9O1xufVxuXG5mdW5jdGlvbiByZXNvbHZlTG9jYWxNb2RlbENvbmZpZyhcbiAgY29uZmlnPzogUGFydGlhbDxTcGVlY2hSZWNvZ25pdGlvbkNvbmZpZz4sXG4pOiBMb2NhbE1vZGVsQ29uZmlnUHJvcHMge1xuICBjb25zdCBkZWZhdWx0czogTG9jYWxNb2RlbENvbmZpZ1Byb3BzID0ge1xuICAgIGVuYWJsZWRPbldlYjogZmFsc2UsXG4gICAgYmFzZVVybDogXCJodHRwOi8vMTI3LjAuMC4xOjgwMDBcIixcbiAgICBtb2RlOiBcIm9uZXNob3RcIixcbiAgICBtb2RlbDogXCJsYXJnZS12My10dXJib1wiLFxuICB9O1xuXG4gIHJldHVybiB7XG4gICAgLi4uZGVmYXVsdHMsXG4gICAgLi4uKGNvbmZpZz8ubG9jYWxNb2RlbCB8fCB7fSksXG4gIH07XG59XG5cbi8qKlxuICogTG9hZCBzcGVlY2ggcmVjb2duaXRpb24gY29uZmlnIGZyb20gZGVmYXVsdHMgKyBleHBsaWNpdCBvdmVycmlkZXMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRTcGVlY2hSZWNvZ25pdGlvbkNvbmZpZyhcbiAgb3ZlcnJpZGVzPzogUGFydGlhbDxTcGVlY2hSZWNvZ25pdGlvbkNvbmZpZz4sXG4pOiBTcGVlY2hSZWNvZ25pdGlvbkNvbmZpZyB7XG4gIGNvbnN0IGRlZmF1bHRzOiBTcGVlY2hSZWNvZ25pdGlvbkNvbmZpZyA9IHtcbiAgICBwcm92aWRlcjogXCJncm9xXCIsXG4gICAgZmFsbGJhY2tUb1dlYlNwZWVjaDogdHJ1ZSxcbiAgICBncm9xOiByZXNvbHZlR3JvcUNvbmZpZygpLFxuICAgIG9wZW5haTogcmVzb2x2ZU9wZW5BSUNvbmZpZygpLFxuICAgIGxvY2FsTW9kZWw6IHJlc29sdmVMb2NhbE1vZGVsQ29uZmlnKCksXG4gIH07XG5cbiAgY29uc3QgbWVyZ2VkOiBTcGVlY2hSZWNvZ25pdGlvbkNvbmZpZyA9IHtcbiAgICAuLi5kZWZhdWx0cyxcbiAgICAuLi4ob3ZlcnJpZGVzIHx8IHt9KSxcbiAgICBwcm92aWRlcjpcbiAgICAgIG5vcm1hbGl6ZVByb3ZpZGVyKG92ZXJyaWRlcz8ucHJvdmlkZXIpIHx8XG4gICAgICBub3JtYWxpemVQcm92aWRlcihkZWZhdWx0cy5wcm92aWRlcikgfHxcbiAgICAgIFwiZ3JvcVwiLFxuICB9O1xuXG4gIHJldHVybiB7XG4gICAgLi4ubWVyZ2VkLFxuICAgIGdyb3E6IHJlc29sdmVHcm9xQ29uZmlnKG1lcmdlZCksXG4gICAgb3BlbmFpOiByZXNvbHZlT3BlbkFJQ29uZmlnKG1lcmdlZCksXG4gICAgbG9jYWxNb2RlbDogcmVzb2x2ZUxvY2FsTW9kZWxDb25maWcobWVyZ2VkKSxcbiAgfTtcbn1cblxuLyoqXG4gKiBDaGVjayBpZiBXZWIgU3BlZWNoIEFQSSBpcyBhdmFpbGFibGVcbiAqL1xuZnVuY3Rpb24gY2hlY2tXZWJTcGVlY2hBdmFpbGFiaWxpdHkoKTogYm9vbGVhbiB7XG4gIGlmICh0eXBlb2Ygd2luZG93ID09PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgcmV0dXJuIFwid2Via2l0U3BlZWNoUmVjb2duaXRpb25cIiBpbiB3aW5kb3cgfHwgXCJTcGVlY2hSZWNvZ25pdGlvblwiIGluIHdpbmRvdztcbn1cblxuZXhwb3J0IGNvbnN0IGlzV2ViU3BlZWNoQXZhaWxhYmxlID0gY2hlY2tXZWJTcGVlY2hBdmFpbGFiaWxpdHk7XG5cbmNvbnN0IG5vcm1hbGl6ZUxhbmd1YWdlVGFnID0gKGxhbmc/OiBzdHJpbmcpID0+IHtcbiAgY29uc3Qgbm9ybWFsaXplZCA9IChsYW5nIHx8IFwiZW5cIikudHJpbSgpLnRvTG93ZXJDYXNlKCk7XG4gIHJldHVybiBub3JtYWxpemVkLmxlbmd0aCA+IDAgPyBub3JtYWxpemVkIDogXCJlblwiO1xufTtcblxuY29uc3QgdG9TaG9ydExhbmd1YWdlQ29kZSA9IChsYW5nOiBzdHJpbmcpID0+IGxhbmcuc3BsaXQoXCItXCIpWzBdO1xuXG5jb25zdCB0b1dlYlNwZWVjaExvY2FsZSA9IChsYW5nOiBzdHJpbmcpID0+IHtcbiAgaWYgKGxhbmcuc3RhcnRzV2l0aChcImVuXCIpKSByZXR1cm4gXCJlbi1VU1wiO1xuICBpZiAobGFuZy5zdGFydHNXaXRoKFwiZGVcIikpIHJldHVybiBcImRlLURFXCI7XG4gIHJldHVybiBsYW5nO1xufTtcblxuLyoqXG4gKiBUeXBlcyBvZiBzcGVlY2ggcmVjb2duaXRpb24gbWV0aG9kc1xuICovXG50eXBlIFNwZWVjaFJlY29nbml0aW9uTW9kZSA9XG4gIHwgXCJvcGVuYWktd2ViXCJcbiAgfCBcIm9wZW5haS1uYXRpdmVcIlxuICB8IFwiZ3JvcS13ZWJcIlxuICB8IFwiZ3JvcS1uYXRpdmVcIlxuICB8IFwid2Vic3BlZWNoXCJcbiAgfCBcIm1seC1sb2NhbFwiXG4gIHwgXCJub25lXCI7XG5cbnR5cGUgTmF0aXZlU3BlZWNoTW9kdWxlID0gdHlwZW9mIGltcG9ydChcIi4vc3BlZWNoLXJlY29nbml0aW9uLW5hdGl2ZVwiKTtcbmxldCBuYXRpdmVTcGVlY2hNb2R1bGVDYWNoZTogTmF0aXZlU3BlZWNoTW9kdWxlIHwgbnVsbCB8IHVuZGVmaW5lZDtcbnR5cGUgT3BlbkFJTmF0aXZlU3BlZWNoTW9kdWxlID0gdHlwZW9mIGltcG9ydChcIi4vc3BlZWNoLXJlY29nbml0aW9uLW9wZW5haS1uYXRpdmVcIik7XG5sZXQgb3BlbkFpTmF0aXZlU3BlZWNoTW9kdWxlQ2FjaGU6IE9wZW5BSU5hdGl2ZVNwZWVjaE1vZHVsZSB8IG51bGwgfCB1bmRlZmluZWQ7XG5cbmZ1bmN0aW9uIGdldE5hdGl2ZVNwZWVjaE1vZHVsZSgpOiBOYXRpdmVTcGVlY2hNb2R1bGUgfCBudWxsIHtcbiAgaWYgKG5hdGl2ZVNwZWVjaE1vZHVsZUNhY2hlICE9PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4gbmF0aXZlU3BlZWNoTW9kdWxlQ2FjaGU7XG4gIH1cblxuICB0cnkge1xuICAgIC8vIEtlZXAgbmF0aXZlIG1vZHVsZSBsYXp5IHRvIGF2b2lkIGxvYWRpbmcgbmF0aXZlLW9ubHkgZGVwZW5kZW5jaWVzIG9uIHdlYi5cbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXZhci1yZXF1aXJlc1xuICAgIG5hdGl2ZVNwZWVjaE1vZHVsZUNhY2hlID0gcmVxdWlyZShcIi4vc3BlZWNoLXJlY29nbml0aW9uLW5hdGl2ZVwiKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBuYXRpdmVTcGVlY2hNb2R1bGVDYWNoZSA9IG51bGw7XG4gICAgbG9nZ2VyLmRlYnVnKFwiTmF0aXZlIHNwZWVjaCBtb2R1bGUgdW5hdmFpbGFibGU6XCIsIGVycm9yKTtcbiAgfVxuXG4gIHJldHVybiBuYXRpdmVTcGVlY2hNb2R1bGVDYWNoZTtcbn1cblxuZnVuY3Rpb24gaXNOYXRpdmVSZWNvZ25pemVyQXZhaWxhYmxlKCk6IGJvb2xlYW4ge1xuICBjb25zdCBuYXRpdmVNb2R1bGUgPSBnZXROYXRpdmVTcGVlY2hNb2R1bGUoKTtcbiAgcmV0dXJuICEhbmF0aXZlTW9kdWxlPy5pc05hdGl2ZVNwZWVjaEF2YWlsYWJsZT8uKCk7XG59XG5cbmZ1bmN0aW9uIGdldE9wZW5BSU5hdGl2ZVNwZWVjaE1vZHVsZSgpOiBPcGVuQUlOYXRpdmVTcGVlY2hNb2R1bGUgfCBudWxsIHtcbiAgaWYgKG9wZW5BaU5hdGl2ZVNwZWVjaE1vZHVsZUNhY2hlICE9PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4gb3BlbkFpTmF0aXZlU3BlZWNoTW9kdWxlQ2FjaGU7XG4gIH1cblxuICB0cnkge1xuICAgIC8vIEtlZXAgbmF0aXZlIG1vZHVsZSBsYXp5IHRvIGF2b2lkIGxvYWRpbmcgbmF0aXZlLW9ubHkgZGVwZW5kZW5jaWVzIG9uIHdlYi5cbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXZhci1yZXF1aXJlc1xuICAgIG9wZW5BaU5hdGl2ZVNwZWVjaE1vZHVsZUNhY2hlID0gcmVxdWlyZShcIi4vc3BlZWNoLXJlY29nbml0aW9uLW9wZW5haS1uYXRpdmVcIik7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgb3BlbkFpTmF0aXZlU3BlZWNoTW9kdWxlQ2FjaGUgPSBudWxsO1xuICAgIGxvZ2dlci5kZWJ1ZyhcIk9wZW5BSSBuYXRpdmUgc3BlZWNoIG1vZHVsZSB1bmF2YWlsYWJsZTpcIiwgZXJyb3IpO1xuICB9XG5cbiAgcmV0dXJuIG9wZW5BaU5hdGl2ZVNwZWVjaE1vZHVsZUNhY2hlO1xufVxuXG5mdW5jdGlvbiBpc09wZW5BSU5hdGl2ZVJlY29nbml6ZXJBdmFpbGFibGUoKTogYm9vbGVhbiB7XG4gIGNvbnN0IG5hdGl2ZU1vZHVsZSA9IGdldE9wZW5BSU5hdGl2ZVNwZWVjaE1vZHVsZSgpO1xuICByZXR1cm4gISFuYXRpdmVNb2R1bGU/LmlzT3BlbkFJTmF0aXZlU3BlZWNoQXZhaWxhYmxlPy4oKTtcbn1cblxuLyoqXG4gKiBEZXRlcm1pbmUgd2hpY2ggc3BlZWNoIHJlY29nbml0aW9uIG1ldGhvZCB0byB1c2VcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNlbGVjdFNwZWVjaFJlY29nbml0aW9uTWV0aG9kKFxuICBjb25maWc6IFNwZWVjaFJlY29nbml0aW9uQ29uZmlnLFxuICBjbGllbnRTZWNyZXQ/OiBzdHJpbmcsXG4pOiBTcGVlY2hSZWNvZ25pdGlvbk1vZGUge1xuICBjb25zdCBpc1dlYiA9IFBsYXRmb3JtLk9TID09PSBcIndlYlwiO1xuICBjb25zdCBpc05hdGl2ZSA9IFBsYXRmb3JtLk9TID09PSBcImlvc1wiIHx8IFBsYXRmb3JtLk9TID09PSBcImFuZHJvaWRcIjtcbiAgY29uc3QgaXNXZWJDbGllbnRSdW50aW1lID0gaXNXZWIgJiYgdHlwZW9mIHdpbmRvdyAhPT0gXCJ1bmRlZmluZWRcIjtcbiAgY29uc3Qgc2hvdWxkV2FyblVuYXZhaWxhYmxlID0gaXNXZWJDbGllbnRSdW50aW1lO1xuICBjb25zdCBwcm92aWRlciA9IG5vcm1hbGl6ZVByb3ZpZGVyKGNvbmZpZy5wcm92aWRlcikgfHwgXCJncm9xXCI7XG4gIGNvbnN0IGdyb3EgPSByZXNvbHZlR3JvcUNvbmZpZyhjb25maWcpO1xuICBjb25zdCBvcGVuYWkgPSByZXNvbHZlT3BlbkFJQ29uZmlnKGNvbmZpZyk7XG4gIGNvbnN0IGxvY2FsTW9kZWwgPSByZXNvbHZlTG9jYWxNb2RlbENvbmZpZyhjb25maWcpO1xuXG4gIGNvbnN0IGhhc0dyb3FLZXkgPSAhIShjbGllbnRTZWNyZXQgfHwgZ3JvcS5hcGlLZXkpO1xuXG4gIGlmIChwcm92aWRlciA9PT0gXCJvcGVuYWlcIikge1xuICAgIGlmIChpc05hdGl2ZSkge1xuICAgICAgaWYgKFxuICAgICAgICBvcGVuYWkudHJhbnNjcmlwdGlvblNlc3Npb25FbmRwb2ludCAmJlxuICAgICAgICBpc09wZW5BSU5hdGl2ZVJlY29nbml6ZXJBdmFpbGFibGUoKVxuICAgICAgKSB7XG4gICAgICAgIGxvZ2dlci5pbmZvKFwi4pyFIFVzaW5nIE9wZW5BSSBOYXRpdmUgUmVhbHRpbWUgKFdlYlJUQylcIik7XG4gICAgICAgIHJldHVybiBcIm9wZW5haS1uYXRpdmVcIjtcbiAgICAgIH1cbiAgICAgIGlmIChzaG91bGRXYXJuVW5hdmFpbGFibGUpIHtcbiAgICAgICAgbG9nZ2VyLndhcm4oXG4gICAgICAgICAgXCLimqDvuI8gT3BlbkFJIG5hdGl2ZSBzcGVlY2ggdW5hdmFpbGFibGUuIENvbmZpZ3VyZSBPUEVOQUlfVFJBTlNDUklQVElPTl9TRVNTSU9OX0VORFBPSU5UIGFuZCBpbnN0YWxsIHJlYWN0LW5hdGl2ZS13ZWJydGMuXCIsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICByZXR1cm4gXCJub25lXCI7XG4gICAgfVxuXG4gICAgaWYgKGlzV2ViKSB7XG4gICAgICBpZiAob3BlbmFpLnRyYW5zY3JpcHRpb25TZXNzaW9uRW5kcG9pbnQgJiYgaXNPcGVuQUlTcGVlY2hBdmFpbGFibGUoKSkge1xuICAgICAgICBsb2dnZXIuaW5mbyhcIuKchSBVc2luZyBPcGVuQUkgV2ViIFJlYWx0aW1lIChXZWJSVEMpXCIpO1xuICAgICAgICByZXR1cm4gXCJvcGVuYWktd2ViXCI7XG4gICAgICB9XG4gICAgICBpZiAoc2hvdWxkV2FyblVuYXZhaWxhYmxlKSB7XG4gICAgICAgIGxvZ2dlci53YXJuKFwi4pqg77iPIE9wZW5BSSB3ZWIgc3BlZWNoIHVuYXZhaWxhYmxlXCIpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIFwibm9uZVwiO1xuICAgIH1cbiAgfVxuXG4gIC8vIE5hdGl2ZSBwbGF0Zm9ybXM6IFVzZSBuYXRpdmUgR3JvcSBpbXBsZW1lbnRhdGlvblxuICBpZiAoaXNOYXRpdmUpIHtcbiAgICBpZiAoZ3JvcS5lbmFibGVkICYmIGhhc0dyb3FLZXkgJiYgaXNOYXRpdmVSZWNvZ25pemVyQXZhaWxhYmxlKCkpIHtcbiAgICAgIGxvZ2dlci5pbmZvKFwi4pyFIFVzaW5nIEdyb3EgTmF0aXZlIChleHBvLWF1ZGlvKVwiKTtcbiAgICAgIHJldHVybiBcImdyb3EtbmF0aXZlXCI7XG4gICAgfVxuICAgIGlmIChzaG91bGRXYXJuVW5hdmFpbGFibGUpIHtcbiAgICAgIGxvZ2dlci53YXJuKFxuICAgICAgICBcIuKaoO+4jyBObyBzcGVlY2ggcmVjb2duaXRpb24gYXZhaWxhYmxlIG9uIG5hdGl2ZSAoaW5zdGFsbCBleHBvLWF1ZGlvICsgZXhwby1maWxlLXN5c3RlbSBhbmQgcnVuIGEgZGV2IGNsaWVudCBidWlsZClcIixcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBcIm5vbmVcIjtcbiAgfVxuXG4gIC8vIFdlYiBwbGF0Zm9ybTogQ2FuIHVzZSBib3RoLCBwcmVmZXIgYmFzZWQgb24gY29uZmlnXG4gIGlmIChpc1dlYikge1xuICAgIGlmIChsb2NhbE1vZGVsLmVuYWJsZWRPbldlYiAmJiBsb2NhbE1vZGVsLmJhc2VVcmwpIHtcbiAgICAgIGxvZ2dlci5pbmZvKFwi4pyFIFVzaW5nIExvY2FsIE1MWCBXaGlzcGVyIHNlcnZlclwiKTtcbiAgICAgIHJldHVybiBcIm1seC1sb2NhbFwiO1xuICAgIH1cblxuICAgIC8vIFVzZSBHcm9xIGlmIGVuYWJsZWQgYW5kIGF2YWlsYWJsZVxuICAgIGlmIChncm9xLmVuYWJsZWQgJiYgaGFzR3JvcUtleSAmJiBpc0dyb3FTcGVlY2hBdmFpbGFibGUoKSkge1xuICAgICAgbG9nZ2VyLmluZm8oXCLinIUgVXNpbmcgR3JvcSBXZWIgKEVuYWJsZWQgYW5kIGF2YWlsYWJsZSlcIik7XG4gICAgICByZXR1cm4gXCJncm9xLXdlYlwiO1xuICAgIH1cblxuICAgIC8vIEZhbGxiYWNrIHRvIFdlYiBTcGVlY2ggQVBJXG4gICAgaWYgKGNvbmZpZy5mYWxsYmFja1RvV2ViU3BlZWNoICYmIGlzV2ViU3BlZWNoQXZhaWxhYmxlKCkpIHtcbiAgICAgIGxvZ2dlci5pbmZvKFwi4pyFIFVzaW5nIFdlYiBTcGVlY2ggQVBJIChGYWxsYmFjaylcIik7XG4gICAgICByZXR1cm4gXCJ3ZWJzcGVlY2hcIjtcbiAgICB9XG4gIH1cbiAgaWYgKHNob3VsZFdhcm5VbmF2YWlsYWJsZSkge1xuICAgIGxvZ2dlci53YXJuKFwi4pqg77iPIE5vIHNwZWVjaCByZWNvZ25pdGlvbiBtZXRob2QgYXZhaWxhYmxlXCIpO1xuICB9XG4gIHJldHVybiBcIm5vbmVcIjtcbn1cblxuLyoqXG4gKiBVbmlmaWVkIFNwZWVjaCBSZWNvZ25pemVyIENvbXBvbmVudFxuICogQXV0b21hdGljYWxseSBzZWxlY3RzIGFuZCB1c2VzIHRoZSBiZXN0IHNwZWVjaCByZWNvZ25pdGlvbiBtZXRob2RcbiAqL1xuZXhwb3J0IGNvbnN0IFVuaWZpZWRTcGVlY2hSZWNvZ25pemVyOiBSZWFjdC5GQzxcbiAgVW5pZmllZFNwZWVjaFJlY29nbml6ZXJQcm9wc1xuPiA9ICh7XG4gIHNob3VsZExpc3RlbixcbiAgc3BlZWNoU3RhdHVzQ2FsbGJhY2ssXG4gIHNwZWVjaFJlc3VsdENhbGxiYWNrLFxuICBzcGVlY2hUcmFuc2xhdGlvbkNhbGxiYWNrLFxuICBzcGVlY2hSZWFkeUNhbGxiYWNrLFxuICB3YXZlZm9ybVByZXZpZXdDYWxsYmFjayxcbiAgY2xpZW50U2VjcmV0LFxuICBsYW5ndWFnZSA9IFwiZW5cIixcbiAgb25FcnJvcixcbiAgcmVxdWVzdENvbnRleHRQcm92aWRlcixcbiAgY29uZmlnLFxufTogVW5pZmllZFNwZWVjaFJlY29nbml6ZXJQcm9wcykgPT4ge1xuICAvLyBHZXQgY29uZmlndXJhdGlvblxuICBjb25zdCByZXNvbHZlZENvbmZpZyA9IGdldFNwZWVjaFJlY29nbml0aW9uQ29uZmlnKGNvbmZpZyk7XG4gIGNvbnN0IGlzV2ViQ2xpZW50UnVudGltZSA9XG4gICAgUGxhdGZvcm0uT1MgPT09IFwid2ViXCIgJiYgdHlwZW9mIHdpbmRvdyAhPT0gXCJ1bmRlZmluZWRcIjtcbiAgY29uc3Qgbm9ybWFsaXplZExhbmd1YWdlID0gbm9ybWFsaXplTGFuZ3VhZ2VUYWcobGFuZ3VhZ2UpO1xuICBjb25zdCBhcGlMYW5ndWFnZSA9IHRvU2hvcnRMYW5ndWFnZUNvZGUobm9ybWFsaXplZExhbmd1YWdlKTtcbiAgY29uc3Qgd2ViU3BlZWNoTGFuZ3VhZ2UgPSB0b1dlYlNwZWVjaExvY2FsZShub3JtYWxpemVkTGFuZ3VhZ2UpO1xuXG4gIC8vIERldGVybWluZSB3aGljaCBtZXRob2QgdG8gdXNlXG4gIGNvbnN0IG1ldGhvZCA9IHNlbGVjdFNwZWVjaFJlY29nbml0aW9uTWV0aG9kKHJlc29sdmVkQ29uZmlnLCBjbGllbnRTZWNyZXQpO1xuICBpZiAoaXNXZWJDbGllbnRSdW50aW1lKSB7XG4gICAgbG9nZ2VyLmRlYnVnKFwiU2VsZWN0ZWQgc3BlZWNoIHJlY29nbml0aW9uIG1ldGhvZDpcIiwgbWV0aG9kKTtcbiAgfVxuICBjb25zdCBncm9xQ29uZmlnID0gcmVzb2x2ZUdyb3FDb25maWcocmVzb2x2ZWRDb25maWcpO1xuICBjb25zdCBvcGVuYWlDb25maWcgPSByZXNvbHZlT3BlbkFJQ29uZmlnKHJlc29sdmVkQ29uZmlnKTtcbiAgY29uc3QgbG9jYWxNb2RlbENvbmZpZyA9IHJlc29sdmVMb2NhbE1vZGVsQ29uZmlnKHJlc29sdmVkQ29uZmlnKTtcblxuICBjb25zdCBmaW5hbEdyb3FBcGlLZXkgPSBjbGllbnRTZWNyZXQgfHwgZ3JvcUNvbmZpZy5hcGlLZXkgfHwgXCJcIjtcbiAgY29uc3QgZ3JvcUFwaUJhc2VVcmwgPSBncm9xQ29uZmlnLmFwaUJhc2VVcmw7XG4gIGNvbnN0IGdyb3FUcmFuc2NyaXB0aW9uRW5kcG9pbnQgPSBncm9xQ29uZmlnLnRyYW5zY3JpcHRpb25FbmRwb2ludDtcbiAgY29uc3Qgc3RyZWFtR3JvcSA9IGdyb3FDb25maWcuc3RyZWFtO1xuXG4gIGlmIChncm9xQ29uZmlnLmVuYWJsZWQgJiYgIWZpbmFsR3JvcUFwaUtleSkge1xuICAgIGxvZ2dlci53YXJuKFxuICAgICAgXCJHcm9xIHNwZWVjaCBpcyBlbmFibGVkIGJ1dCBubyBBUEkga2V5IHdhcyBwcm92aWRlZC4gUGFzcyBhIG5vbi1zZWNyZXQgY2xpZW50IGtleSBvciBkaXNhYmxlIEdyb3Egc3BlZWNoLlwiLFxuICAgICk7XG4gIH1cblxuICAvLyBFcnJvciBoYW5kbGVyIHdpdGggZmFsbGJhY2tcbiAgY29uc3QgaGFuZGxlRXJyb3IgPSAoZXJyb3I6IEVycm9yKSA9PiB7XG4gICAgbG9nZ2VyLmVycm9yKFwiU3BlZWNoIHJlY29nbml0aW9uIGVycm9yOlwiLCBlcnJvcik7XG5cbiAgICBpZiAob25FcnJvcikge1xuICAgICAgb25FcnJvcihlcnJvcik7XG4gICAgfVxuXG4gICAgLy8gSWYgR3JvcSBmYWlscyBhbmQgZmFsbGJhY2sgaXMgZW5hYmxlZCwgd2UgY291bGQgc3dpdGNoIHRvIFdlYiBTcGVlY2hcbiAgICAvLyAoVGhpcyB3b3VsZCByZXF1aXJlIG1vcmUgY29tcGxleCBzdGF0ZSBtYW5hZ2VtZW50KVxuICB9O1xuXG4gIC8vIFJlbmRlciBhcHByb3ByaWF0ZSBjb21wb25lbnQgYmFzZWQgb24gbWV0aG9kXG4gIHN3aXRjaCAobWV0aG9kKSB7XG4gICAgY2FzZSBcIm9wZW5haS1uYXRpdmVcIjoge1xuICAgICAgaWYgKCFvcGVuYWlDb25maWcudHJhbnNjcmlwdGlvblNlc3Npb25FbmRwb2ludCkge1xuICAgICAgICBsb2dnZXIuZXJyb3IoXG4gICAgICAgICAgXCJPcGVuQUkgdHJhbnNjcmlwdGlvbiBzZXNzaW9uIGVuZHBvaW50IGlzIHJlcXVpcmVkIGJ1dCBub3QgcHJvdmlkZWRcIixcbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG9wZW5haU5hdGl2ZU1vZHVsZSA9IGdldE9wZW5BSU5hdGl2ZVNwZWVjaE1vZHVsZSgpO1xuICAgICAgaWYgKCFvcGVuYWlOYXRpdmVNb2R1bGU/Lk9wZW5BSU5hdGl2ZVNwZWVjaFJlY29nbml6ZXIpIHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKFxuICAgICAgICAgIFwiT3BlbkFJIG5hdGl2ZSBzcGVlY2ggbW9kdWxlIHVuYXZhaWxhYmxlLiBJbnN0YWxsIHJlYWN0LW5hdGl2ZS13ZWJydGMgYW5kIHVzZSBhIG5hdGl2ZS9kZXYgYnVpbGQuXCIsXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBPcGVuQUlOYXRpdmVTcGVlY2hSZWNvZ25pemVyID1cbiAgICAgICAgb3BlbmFpTmF0aXZlTW9kdWxlLk9wZW5BSU5hdGl2ZVNwZWVjaFJlY29nbml6ZXI7XG5cbiAgICAgIHJldHVybiAoXG4gICAgICAgIDxPcGVuQUlOYXRpdmVTcGVlY2hSZWNvZ25pemVyXG4gICAgICAgICAgc2hvdWxkTGlzdGVuPXtzaG91bGRMaXN0ZW59XG4gICAgICAgICAgc3BlZWNoU3RhdHVzQ2FsbGJhY2s9e3NwZWVjaFN0YXR1c0NhbGxiYWNrfVxuICAgICAgICAgIHNwZWVjaFJlc3VsdENhbGxiYWNrPXtzcGVlY2hSZXN1bHRDYWxsYmFja31cbiAgICAgICAgICBzcGVlY2hUcmFuc2xhdGlvbkNhbGxiYWNrPXtzcGVlY2hUcmFuc2xhdGlvbkNhbGxiYWNrfVxuICAgICAgICAgIHNwZWVjaFJlYWR5Q2FsbGJhY2s9e3NwZWVjaFJlYWR5Q2FsbGJhY2t9XG4gICAgICAgICAgY2xpZW50U2VjcmV0PXtmaW5hbEdyb3FBcGlLZXl9XG4gICAgICAgICAgb3BlbmFpVHJhbnNjcmlwdGlvblNlc3Npb25FbmRwb2ludD17XG4gICAgICAgICAgICBvcGVuYWlDb25maWcudHJhbnNjcmlwdGlvblNlc3Npb25FbmRwb2ludFxuICAgICAgICAgIH1cbiAgICAgICAgICBvcGVuYWlUcmFuc2xhdGlvbkVuZHBvaW50PXtvcGVuYWlDb25maWcudHJhbnNsYXRpb25FbmRwb2ludH1cbiAgICAgICAgICBvcGVuYWlSZWFsdGltZVdlYlJ0Y1VybD17b3BlbmFpQ29uZmlnLnJlYWx0aW1lV2ViUnRjVXJsfVxuICAgICAgICAgIG9wZW5haVJlYWx0aW1lTW9kZWw9e29wZW5haUNvbmZpZy5yZWFsdGltZU1vZGVsfVxuICAgICAgICAgIG9wZW5haVRyYW5zbGF0aW9uTW9kZWw9e29wZW5haUNvbmZpZy50cmFuc2xhdGlvbk1vZGVsfVxuICAgICAgICAgIG9wZW5haVZhZEVuYWJsZWQ9e29wZW5haUNvbmZpZy52YWRFbmFibGVkfVxuICAgICAgICAgIG9wZW5haUF1dG9TdG9wT25WYWRTaWxlbmNlPXtcbiAgICAgICAgICAgIG9wZW5haUNvbmZpZy5hdXRvU3RvcE9uVmFkU2lsZW5jZVxuICAgICAgICAgIH1cbiAgICAgICAgICBvcGVuYWlWYWRUaHJlc2hvbGQ9e29wZW5haUNvbmZpZy52YWRUaHJlc2hvbGR9XG4gICAgICAgICAgb3BlbmFpVmFkUHJlZml4UGFkZGluZ01zPXtvcGVuYWlDb25maWcudmFkUHJlZml4UGFkZGluZ01zfVxuICAgICAgICAgIG9wZW5haVZhZFNpbGVuY2VEdXJhdGlvbk1zPXtcbiAgICAgICAgICAgIG9wZW5haUNvbmZpZy52YWRTaWxlbmNlRHVyYXRpb25Nc1xuICAgICAgICAgIH1cbiAgICAgICAgICBvcGVuYWlWYWRJZGxlVGltZW91dE1zPXtvcGVuYWlDb25maWcudmFkSWRsZVRpbWVvdXRNc31cbiAgICAgICAgICBvcGVuYWlQcmV3YXJtT25Nb3VudD17b3BlbmFpQ29uZmlnLnByZXdhcm1Pbk1vdW50fVxuICAgICAgICAgIGxhbmd1YWdlPXthcGlMYW5ndWFnZX1cbiAgICAgICAgICByZXF1ZXN0Q29udGV4dFByb3ZpZGVyPXtyZXF1ZXN0Q29udGV4dFByb3ZpZGVyfVxuICAgICAgICAgIG9uRXJyb3I9e2hhbmRsZUVycm9yfVxuICAgICAgICAvPlxuICAgICAgKTtcbiAgICB9XG5cbiAgICBjYXNlIFwib3BlbmFpLXdlYlwiOlxuICAgICAgaWYgKCFvcGVuYWlDb25maWcudHJhbnNjcmlwdGlvblNlc3Npb25FbmRwb2ludCkge1xuICAgICAgICBsb2dnZXIuZXJyb3IoXG4gICAgICAgICAgXCJPcGVuQUkgdHJhbnNjcmlwdGlvbiBzZXNzaW9uIGVuZHBvaW50IGlzIHJlcXVpcmVkIGJ1dCBub3QgcHJvdmlkZWRcIixcbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiAoXG4gICAgICAgIDxPcGVuQUlTcGVlY2hSZWNvZ25pemVyXG4gICAgICAgICAgc2hvdWxkTGlzdGVuPXtzaG91bGRMaXN0ZW59XG4gICAgICAgICAgc3BlZWNoU3RhdHVzQ2FsbGJhY2s9e3NwZWVjaFN0YXR1c0NhbGxiYWNrfVxuICAgICAgICAgIHNwZWVjaFJlc3VsdENhbGxiYWNrPXtzcGVlY2hSZXN1bHRDYWxsYmFja31cbiAgICAgICAgICBzcGVlY2hUcmFuc2xhdGlvbkNhbGxiYWNrPXtzcGVlY2hUcmFuc2xhdGlvbkNhbGxiYWNrfVxuICAgICAgICAgIHNwZWVjaFJlYWR5Q2FsbGJhY2s9e3NwZWVjaFJlYWR5Q2FsbGJhY2t9XG4gICAgICAgICAgY2xpZW50U2VjcmV0PXtmaW5hbEdyb3FBcGlLZXl9XG4gICAgICAgICAgb3BlbmFpVHJhbnNjcmlwdGlvblNlc3Npb25FbmRwb2ludD17XG4gICAgICAgICAgICBvcGVuYWlDb25maWcudHJhbnNjcmlwdGlvblNlc3Npb25FbmRwb2ludFxuICAgICAgICAgIH1cbiAgICAgICAgICBvcGVuYWlUcmFuc2xhdGlvbkVuZHBvaW50PXtvcGVuYWlDb25maWcudHJhbnNsYXRpb25FbmRwb2ludH1cbiAgICAgICAgICBvcGVuYWlSZWFsdGltZVdlYlJ0Y1VybD17b3BlbmFpQ29uZmlnLnJlYWx0aW1lV2ViUnRjVXJsfVxuICAgICAgICAgIG9wZW5haVJlYWx0aW1lTW9kZWw9e29wZW5haUNvbmZpZy5yZWFsdGltZU1vZGVsfVxuICAgICAgICAgIG9wZW5haVRyYW5zbGF0aW9uTW9kZWw9e29wZW5haUNvbmZpZy50cmFuc2xhdGlvbk1vZGVsfVxuICAgICAgICAgIG9wZW5haVZhZEVuYWJsZWQ9e29wZW5haUNvbmZpZy52YWRFbmFibGVkfVxuICAgICAgICAgIG9wZW5haUF1dG9TdG9wT25WYWRTaWxlbmNlPXtcbiAgICAgICAgICAgIG9wZW5haUNvbmZpZy5hdXRvU3RvcE9uVmFkU2lsZW5jZVxuICAgICAgICAgIH1cbiAgICAgICAgICBvcGVuYWlWYWRUaHJlc2hvbGQ9e29wZW5haUNvbmZpZy52YWRUaHJlc2hvbGR9XG4gICAgICAgICAgb3BlbmFpVmFkUHJlZml4UGFkZGluZ01zPXtvcGVuYWlDb25maWcudmFkUHJlZml4UGFkZGluZ01zfVxuICAgICAgICAgIG9wZW5haVZhZFNpbGVuY2VEdXJhdGlvbk1zPXtcbiAgICAgICAgICAgIG9wZW5haUNvbmZpZy52YWRTaWxlbmNlRHVyYXRpb25Nc1xuICAgICAgICAgIH1cbiAgICAgICAgICBvcGVuYWlWYWRJZGxlVGltZW91dE1zPXtvcGVuYWlDb25maWcudmFkSWRsZVRpbWVvdXRNc31cbiAgICAgICAgICBvcGVuYWlQcmV3YXJtT25Nb3VudD17b3BlbmFpQ29uZmlnLnByZXdhcm1Pbk1vdW50fVxuICAgICAgICAgIGxhbmd1YWdlPXthcGlMYW5ndWFnZX1cbiAgICAgICAgICByZXF1ZXN0Q29udGV4dFByb3ZpZGVyPXtyZXF1ZXN0Q29udGV4dFByb3ZpZGVyfVxuICAgICAgICAgIG9uRXJyb3I9e2hhbmRsZUVycm9yfVxuICAgICAgICAvPlxuICAgICAgKTtcblxuICAgIGNhc2UgXCJncm9xLW5hdGl2ZVwiOiB7XG4gICAgICBpZiAoIWZpbmFsR3JvcUFwaUtleSkge1xuICAgICAgICBsb2dnZXIuZXJyb3IoXCJHcm9xIEFQSSBrZXkgaXMgcmVxdWlyZWQgYnV0IG5vdCBwcm92aWRlZFwiKTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG5hdGl2ZU1vZHVsZSA9IGdldE5hdGl2ZVNwZWVjaE1vZHVsZSgpO1xuICAgICAgaWYgKCFuYXRpdmVNb2R1bGU/Lk5hdGl2ZVNwZWVjaFJlY29nbml6ZXIpIHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKFxuICAgICAgICAgIFwiTmF0aXZlIHNwZWVjaCBtb2R1bGUgaXMgdW5hdmFpbGFibGUuIEluc3RhbGwgZXhwby1hdWRpbyArIGV4cG8tZmlsZS1zeXN0ZW0gYW5kIHVzZSBhIGRldiBjbGllbnQgYnVpbGQuXCIsXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBOYXRpdmVTcGVlY2hSZWNvZ25pemVyID0gbmF0aXZlTW9kdWxlLk5hdGl2ZVNwZWVjaFJlY29nbml6ZXI7XG4gICAgICByZXR1cm4gKFxuICAgICAgICA8TmF0aXZlU3BlZWNoUmVjb2duaXplclxuICAgICAgICAgIHNob3VsZExpc3Rlbj17c2hvdWxkTGlzdGVufVxuICAgICAgICAgIHNwZWVjaFN0YXR1c0NhbGxiYWNrPXtzcGVlY2hTdGF0dXNDYWxsYmFja31cbiAgICAgICAgICBzcGVlY2hSZXN1bHRDYWxsYmFjaz17c3BlZWNoUmVzdWx0Q2FsbGJhY2t9XG4gICAgICAgICAgc3BlZWNoVHJhbnNsYXRpb25DYWxsYmFjaz17c3BlZWNoVHJhbnNsYXRpb25DYWxsYmFja31cbiAgICAgICAgICBjbGllbnRTZWNyZXQ9e2ZpbmFsR3JvcUFwaUtleX1cbiAgICAgICAgICBncm9xQXBpQmFzZVVybD17Z3JvcUFwaUJhc2VVcmx9XG4gICAgICAgICAgZ3JvcVRyYW5zY3JpcHRpb25FbmRwb2ludD17Z3JvcVRyYW5zY3JpcHRpb25FbmRwb2ludH1cbiAgICAgICAgICBzdHJlYW09e3N0cmVhbUdyb3F9XG4gICAgICAgICAgbGFuZ3VhZ2U9e2FwaUxhbmd1YWdlfVxuICAgICAgICAgIG9uRXJyb3I9e2hhbmRsZUVycm9yfVxuICAgICAgICAvPlxuICAgICAgKTtcbiAgICB9XG5cbiAgICBjYXNlIFwiZ3JvcS13ZWJcIjpcbiAgICAgIGlmICghZmluYWxHcm9xQXBpS2V5KSB7XG4gICAgICAgIGxvZ2dlci5lcnJvcihcIkdyb3EgQVBJIGtleSBpcyByZXF1aXJlZCBidXQgbm90IHByb3ZpZGVkXCIpO1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICAgIHJldHVybiAoXG4gICAgICAgIDxHcm9xU3BlZWNoUmVjb2duaXplclxuICAgICAgICAgIHNob3VsZExpc3Rlbj17c2hvdWxkTGlzdGVufVxuICAgICAgICAgIHNwZWVjaFN0YXR1c0NhbGxiYWNrPXtzcGVlY2hTdGF0dXNDYWxsYmFja31cbiAgICAgICAgICBzcGVlY2hSZXN1bHRDYWxsYmFjaz17c3BlZWNoUmVzdWx0Q2FsbGJhY2t9XG4gICAgICAgICAgc3BlZWNoVHJhbnNsYXRpb25DYWxsYmFjaz17c3BlZWNoVHJhbnNsYXRpb25DYWxsYmFja31cbiAgICAgICAgICBjbGllbnRTZWNyZXQ9e2ZpbmFsR3JvcUFwaUtleX1cbiAgICAgICAgICBncm9xQXBpQmFzZVVybD17Z3JvcUFwaUJhc2VVcmx9XG4gICAgICAgICAgZ3JvcVRyYW5zY3JpcHRpb25FbmRwb2ludD17Z3JvcVRyYW5zY3JpcHRpb25FbmRwb2ludH1cbiAgICAgICAgICBzdHJlYW09e3N0cmVhbUdyb3F9XG4gICAgICAgICAgbGFuZ3VhZ2U9e2FwaUxhbmd1YWdlfVxuICAgICAgICAgIG9uRXJyb3I9e2hhbmRsZUVycm9yfVxuICAgICAgICAvPlxuICAgICAgKTtcblxuICAgIGNhc2UgXCJtbHgtbG9jYWxcIjoge1xuICAgICAgY29uc3QgZWZmZWN0aXZlVXJsID0gbG9jYWxNb2RlbENvbmZpZy5iYXNlVXJsO1xuICAgICAgaWYgKCFlZmZlY3RpdmVVcmwpIHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKFwiTG9jYWwgd2hpc3BlciBVUkwgaXMgcmVxdWlyZWQgYnV0IG5vdCBwcm92aWRlZFwiKTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiAoXG4gICAgICAgIDxNTFhTcGVlY2hSZWNvZ25pemVyXG4gICAgICAgICAgc2hvdWxkTGlzdGVuPXtzaG91bGRMaXN0ZW59XG4gICAgICAgICAgc3BlZWNoU3RhdHVzQ2FsbGJhY2s9e3NwZWVjaFN0YXR1c0NhbGxiYWNrfVxuICAgICAgICAgIHNwZWVjaFJlc3VsdENhbGxiYWNrPXtzcGVlY2hSZXN1bHRDYWxsYmFja31cbiAgICAgICAgICBsYW5ndWFnZT17YXBpTGFuZ3VhZ2V9XG4gICAgICAgICAgb25FcnJvcj17aGFuZGxlRXJyb3J9XG4gICAgICAgICAgYmFzZVVybD17ZWZmZWN0aXZlVXJsfVxuICAgICAgICAgIG1vZGU9e2xvY2FsTW9kZWxDb25maWcubW9kZX1cbiAgICAgICAgICBtb2RlbE5hbWU9e2xvY2FsTW9kZWxDb25maWcubW9kZWx9XG4gICAgICAgIC8+XG4gICAgICApO1xuICAgIH1cblxuICAgIGNhc2UgXCJ3ZWJzcGVlY2hcIjpcbiAgICAgIHJldHVybiAoXG4gICAgICAgIDxXZWJTcGVlY2hSZWNvZ25pemVyXG4gICAgICAgICAgc2hvdWxkTGlzdGVuPXtzaG91bGRMaXN0ZW59XG4gICAgICAgICAgc3BlZWNoU3RhdHVzQ2FsbGJhY2s9e3NwZWVjaFN0YXR1c0NhbGxiYWNrfVxuICAgICAgICAgIHNwZWVjaFJlc3VsdENhbGxiYWNrPXtzcGVlY2hSZXN1bHRDYWxsYmFja31cbiAgICAgICAgICBsYW5ndWFnZT17d2ViU3BlZWNoTGFuZ3VhZ2V9XG4gICAgICAgIC8+XG4gICAgICApO1xuXG4gICAgY2FzZSBcIm5vbmVcIjpcbiAgICBkZWZhdWx0OlxuICAgICAgaWYgKGlzV2ViQ2xpZW50UnVudGltZSkge1xuICAgICAgICBsb2dnZXIud2FybihcIk5vIHNwZWVjaCByZWNvZ25pdGlvbiBhdmFpbGFibGVcIik7XG4gICAgICB9XG4gICAgICByZXR1cm4gbnVsbDtcbiAgfVxufTtcblxuLyoqXG4gKiBHZXQgc3BlZWNoIHJlY29nbml0aW9uIHN0YXR1cyBhbmQgY2FwYWJpbGl0aWVzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRTcGVlY2hSZWNvZ25pdGlvblN0YXR1cyhcbiAgb3ZlcnJpZGVzPzogUGFydGlhbDxTcGVlY2hSZWNvZ25pdGlvbkNvbmZpZz4sXG4pIHtcbiAgY29uc3QgY29uZmlnID0gZ2V0U3BlZWNoUmVjb2duaXRpb25Db25maWcob3ZlcnJpZGVzKTtcbiAgY29uc3QgbWV0aG9kID0gc2VsZWN0U3BlZWNoUmVjb2duaXRpb25NZXRob2QoY29uZmlnKTtcbiAgY29uc3QgbG9jYWxNb2RlbCA9IHJlc29sdmVMb2NhbE1vZGVsQ29uZmlnKGNvbmZpZyk7XG5cbiAgcmV0dXJuIHtcbiAgICBtZXRob2QsXG4gICAgY29uZmlnLFxuICAgIGNhcGFiaWxpdGllczoge1xuICAgICAgZ3JvcTogZ2V0R3JvcVNwZWVjaENhcGFiaWxpdGllcygpLFxuICAgICAgb3BlbmFpOiBnZXRPcGVuQUlTcGVlY2hDYXBhYmlsaXRpZXMoKSxcbiAgICAgIHdlYlNwZWVjaDoge1xuICAgICAgICBhdmFpbGFibGU6IGlzV2ViU3BlZWNoQXZhaWxhYmxlKCksXG4gICAgICAgIHBsYXRmb3JtOiBQbGF0Zm9ybS5PUyxcbiAgICAgIH0sXG4gICAgICBsb2NhbE1vZGVsOiB7XG4gICAgICAgIGVuYWJsZWQ6ICEhbG9jYWxNb2RlbC5lbmFibGVkT25XZWIsXG4gICAgICAgIHVybDogbG9jYWxNb2RlbC5iYXNlVXJsLFxuICAgICAgICBtb2RlOiBsb2NhbE1vZGVsLm1vZGUgfHwgXCJvbmVzaG90XCIsXG4gICAgICB9LFxuICAgIH0sXG4gICAgcmVjb21tZW5kYXRpb25zOiBnZXRSZWNvbW1lbmRhdGlvbnMobWV0aG9kLCBjb25maWcpLFxuICB9O1xufVxuXG4vKipcbiAqIEdldCByZWNvbW1lbmRhdGlvbnMgZm9yIGltcHJvdmluZyBzcGVlY2ggcmVjb2duaXRpb25cbiAqL1xuZnVuY3Rpb24gZ2V0UmVjb21tZW5kYXRpb25zKFxuICBtZXRob2Q6XG4gICAgfCBcIm9wZW5haS13ZWJcIlxuICAgIHwgXCJvcGVuYWktbmF0aXZlXCJcbiAgICB8IFwiZ3JvcS13ZWJcIlxuICAgIHwgXCJncm9xLW5hdGl2ZVwiXG4gICAgfCBcIndlYnNwZWVjaFwiXG4gICAgfCBcIm1seC1sb2NhbFwiXG4gICAgfCBcIm5vbmVcIixcbiAgY29uZmlnOiBTcGVlY2hSZWNvZ25pdGlvbkNvbmZpZyxcbik6IHN0cmluZ1tdIHtcbiAgY29uc3QgcmVjb21tZW5kYXRpb25zOiBzdHJpbmdbXSA9IFtdO1xuXG4gIGlmIChtZXRob2QgPT09IFwibm9uZVwiKSB7XG4gICAgcmVjb21tZW5kYXRpb25zLnB1c2goXCJObyBzcGVlY2ggcmVjb2duaXRpb24gYXZhaWxhYmxlXCIpO1xuXG4gICAgaWYgKCFjb25maWcuZ3JvcT8uYXBpS2V5ICYmIGNvbmZpZy5wcm92aWRlciAhPT0gXCJvcGVuYWlcIikge1xuICAgICAgcmVjb21tZW5kYXRpb25zLnB1c2goXG4gICAgICAgIFwiUHJvdmlkZSBhIEdyb3EgY2xpZW50IHNlY3JldCB2aWEgY29uZmlnIG9yIGRpc2FibGUgR3JvcSBzcGVlY2hcIixcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKFBsYXRmb3JtLk9TID09PSBcIndlYlwiKSB7XG4gICAgICBpZiAoIWlzR3JvcVNwZWVjaEF2YWlsYWJsZSgpKSB7XG4gICAgICAgIHJlY29tbWVuZGF0aW9ucy5wdXNoKFwiQnJvd3NlciBkb2VzIG5vdCBzdXBwb3J0IE1lZGlhUmVjb3JkZXIgQVBJXCIpO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWlzV2ViU3BlZWNoQXZhaWxhYmxlKCkpIHtcbiAgICAgICAgcmVjb21tZW5kYXRpb25zLnB1c2goXCJCcm93c2VyIGRvZXMgbm90IHN1cHBvcnQgV2ViIFNwZWVjaCBBUElcIik7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHJlY29tbWVuZGF0aW9ucy5wdXNoKFxuICAgICAgICBcIkluc3RhbGwgZXhwby1hdWRpbyArIGV4cG8tZmlsZS1zeXN0ZW0gYW5kIHVzZSBhIGRldiBjbGllbnQgYnVpbGRcIixcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgaWYgKG1ldGhvZCA9PT0gXCJ3ZWJzcGVlY2hcIikge1xuICAgIHJlY29tbWVuZGF0aW9ucy5wdXNoKFwiVXNpbmcgV2ViIFNwZWVjaCBBUEkgKGZyZWUgYnV0IGxlc3MgYWNjdXJhdGUpXCIpO1xuICAgIHJlY29tbWVuZGF0aW9ucy5wdXNoKFwiRW5hYmxlIEdyb3Egc3BlZWNoIGZvciBiZXR0ZXIgYWNjdXJhY3lcIik7XG4gIH1cblxuICBpZiAobWV0aG9kID09PSBcImdyb3Etd2ViXCIpIHtcbiAgICByZWNvbW1lbmRhdGlvbnMucHVzaChcIlVzaW5nIEdyb3EgV2ViIChoaWdoIGFjY3VyYWN5LCBiZXN0IGZvciB3ZWIpXCIpO1xuICB9XG5cbiAgaWYgKG1ldGhvZCA9PT0gXCJncm9xLW5hdGl2ZVwiKSB7XG4gICAgcmVjb21tZW5kYXRpb25zLnB1c2goXCJVc2luZyBHcm9xIE5hdGl2ZSBjYXB0dXJlIChleHBvLWF1ZGlvKVwiKTtcbiAgfVxuXG4gIGlmIChtZXRob2QgPT09IFwib3BlbmFpLXdlYlwiKSB7XG4gICAgcmVjb21tZW5kYXRpb25zLnB1c2goXCJVc2luZyBPcGVuQUkgV2ViIFJlYWx0aW1lIHdpdGggc2VydmVyIFZBRFwiKTtcbiAgfVxuXG4gIGlmIChtZXRob2QgPT09IFwib3BlbmFpLW5hdGl2ZVwiKSB7XG4gICAgcmVjb21tZW5kYXRpb25zLnB1c2goXCJVc2luZyBPcGVuQUkgTmF0aXZlIFJlYWx0aW1lIHdpdGggUENNIHN0cmVhbVwiKTtcbiAgfVxuXG4gIGlmIChtZXRob2QgPT09IFwibWx4LWxvY2FsXCIpIHtcbiAgICByZWNvbW1lbmRhdGlvbnMucHVzaChcIlVzaW5nIExvY2FsIE1MWCBXaGlzcGVyIHNlcnZlciAoZmFzdCwgb2ZmbGluZSlcIik7XG4gICAgaWYgKCFjb25maWcubG9jYWxNb2RlbD8uYmFzZVVybCkge1xuICAgICAgcmVjb21tZW5kYXRpb25zLnB1c2goXCJTZXQgTE9DQUxfV0hJU1BFUl9VUkwgdG8gcG9pbnQgYXQgeW91ciBzZXJ2ZXJcIik7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHJlY29tbWVuZGF0aW9ucztcbn1cblxuLy8gRXhwb3J0IGZvciBjb252ZW5pZW5jZVxuZXhwb3J0IHtcbiAgaXNHcm9xU3BlZWNoQXZhaWxhYmxlLFxuICBnZXRHcm9xU3BlZWNoQ2FwYWJpbGl0aWVzLFxuICBpc09wZW5BSVNwZWVjaEF2YWlsYWJsZSxcbiAgZ2V0T3BlbkFJU3BlZWNoQ2FwYWJpbGl0aWVzLFxufTtcblxuLy8gRGVmYXVsdCBleHBvcnRcbmV4cG9ydCBkZWZhdWx0IFVuaWZpZWRTcGVlY2hSZWNvZ25pemVyO1xuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBUUEsSUFBQUEsTUFBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUMsWUFBQSxHQUFBRCxPQUFBO0FBQ0EsSUFBQUUsa0JBQUEsR0FBQUYsT0FBQTtBQUNBLElBQUFHLHNCQUFBLEdBQUFILE9BQUE7QUFLQSxJQUFBSSxxQkFBQSxHQUFBSixPQUFBO0FBSUEsSUFBQUssd0JBQUEsR0FBQUwsT0FBQTtBQUtBLElBQUFNLE9BQUEsR0FBQVAsc0JBQUEsQ0FBQUMsT0FBQTtBQUErQixTQUFBRCx1QkFBQVEsQ0FBQSxXQUFBQSxDQUFBLElBQUFBLENBQUEsQ0FBQUMsVUFBQSxHQUFBRCxDQUFBLEtBQUFFLE9BQUEsRUFBQUYsQ0FBQTtBQUFBLFNBQUFHLFFBQUFILENBQUEsRUFBQUksQ0FBQSxRQUFBQyxDQUFBLEdBQUFDLE1BQUEsQ0FBQUMsSUFBQSxDQUFBUCxDQUFBLE9BQUFNLE1BQUEsQ0FBQUUscUJBQUEsUUFBQUMsQ0FBQSxHQUFBSCxNQUFBLENBQUFFLHFCQUFBLENBQUFSLENBQUEsR0FBQUksQ0FBQSxLQUFBSyxDQUFBLEdBQUFBLENBQUEsQ0FBQUMsTUFBQSxXQUFBTixDQUFBLFdBQUFFLE1BQUEsQ0FBQUssd0JBQUEsQ0FBQVgsQ0FBQSxFQUFBSSxDQUFBLEVBQUFRLFVBQUEsT0FBQVAsQ0FBQSxDQUFBUSxJQUFBLENBQUFDLEtBQUEsQ0FBQVQsQ0FBQSxFQUFBSSxDQUFBLFlBQUFKLENBQUE7QUFBQSxTQUFBVSxjQUFBZixDQUFBLGFBQUFJLENBQUEsTUFBQUEsQ0FBQSxHQUFBWSxTQUFBLENBQUFDLE1BQUEsRUFBQWIsQ0FBQSxVQUFBQyxDQUFBLFdBQUFXLFNBQUEsQ0FBQVosQ0FBQSxJQUFBWSxTQUFBLENBQUFaLENBQUEsUUFBQUEsQ0FBQSxPQUFBRCxPQUFBLENBQUFHLE1BQUEsQ0FBQUQsQ0FBQSxPQUFBYSxPQUFBLFdBQUFkLENBQUEsSUFBQWUsZUFBQSxDQUFBbkIsQ0FBQSxFQUFBSSxDQUFBLEVBQUFDLENBQUEsQ0FBQUQsQ0FBQSxTQUFBRSxNQUFBLENBQUFjLHlCQUFBLEdBQUFkLE1BQUEsQ0FBQWUsZ0JBQUEsQ0FBQXJCLENBQUEsRUFBQU0sTUFBQSxDQUFBYyx5QkFBQSxDQUFBZixDQUFBLEtBQUFGLE9BQUEsQ0FBQUcsTUFBQSxDQUFBRCxDQUFBLEdBQUFhLE9BQUEsV0FBQWQsQ0FBQSxJQUFBRSxNQUFBLENBQUFnQixjQUFBLENBQUF0QixDQUFBLEVBQUFJLENBQUEsRUFBQUUsTUFBQSxDQUFBSyx3QkFBQSxDQUFBTixDQUFBLEVBQUFELENBQUEsaUJBQUFKLENBQUE7QUFBQSxTQUFBbUIsZ0JBQUFuQixDQUFBLEVBQUFJLENBQUEsRUFBQUMsQ0FBQSxZQUFBRCxDQUFBLEdBQUFtQixjQUFBLENBQUFuQixDQUFBLE1BQUFKLENBQUEsR0FBQU0sTUFBQSxDQUFBZ0IsY0FBQSxDQUFBdEIsQ0FBQSxFQUFBSSxDQUFBLElBQUFvQixLQUFBLEVBQUFuQixDQUFBLEVBQUFPLFVBQUEsTUFBQWEsWUFBQSxNQUFBQyxRQUFBLFVBQUExQixDQUFBLENBQUFJLENBQUEsSUFBQUMsQ0FBQSxFQUFBTCxDQUFBO0FBQUEsU0FBQXVCLGVBQUFsQixDQUFBLFFBQUFzQixDQUFBLEdBQUFDLFlBQUEsQ0FBQXZCLENBQUEsdUNBQUFzQixDQUFBLEdBQUFBLENBQUEsR0FBQUEsQ0FBQTtBQUFBLFNBQUFDLGFBQUF2QixDQUFBLEVBQUFELENBQUEsMkJBQUFDLENBQUEsS0FBQUEsQ0FBQSxTQUFBQSxDQUFBLE1BQUFMLENBQUEsR0FBQUssQ0FBQSxDQUFBd0IsTUFBQSxDQUFBQyxXQUFBLGtCQUFBOUIsQ0FBQSxRQUFBMkIsQ0FBQSxHQUFBM0IsQ0FBQSxDQUFBK0IsSUFBQSxDQUFBMUIsQ0FBQSxFQUFBRCxDQUFBLHVDQUFBdUIsQ0FBQSxTQUFBQSxDQUFBLFlBQUFLLFNBQUEseUVBQUE1QixDQUFBLEdBQUE2QixNQUFBLEdBQUFDLE1BQUEsRUFBQTdCLENBQUEsS0F6Qi9CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBNEVBO0FBQ0E7QUFDQTtBQUNBOztBQVlBLFNBQVM4QixpQkFBaUJBLENBQ3hCWCxLQUFjLEVBQ2lCO0VBQy9CLElBQUksQ0FBQ0EsS0FBSyxFQUFFLE9BQU9ZLFNBQVM7RUFDNUIsTUFBTUMsVUFBVSxHQUFHYixLQUFLLENBQUNjLElBQUksQ0FBQyxDQUFDLENBQUNDLFdBQVcsQ0FBQyxDQUFDO0VBQzdDLElBQUlGLFVBQVUsS0FBSyxNQUFNLEVBQUUsT0FBTyxNQUFNO0VBQ3hDLElBQUlBLFVBQVUsS0FBSyxRQUFRLEVBQUUsT0FBTyxRQUFRO0VBQzVDLE9BQU9ELFNBQVM7QUFDbEI7QUFFQSxNQUFNSSxzQkFBMEQsR0FDOUQsbUJBQW1CO0FBQ3JCLE1BQU1DLHlCQUF5QixHQUFHLGNBQWM7QUFDaEQsTUFBTUMsdUNBQXVDLEdBQUcsS0FBSztBQUNyRCxNQUFNQyxzQ0FBc0MsR0FBRyxJQUFJO0FBQ25ELE1BQU1DLCtCQUErQixHQUFHLElBQUk7QUFFNUMsU0FBU0Msa0JBQWtCQSxDQUFDQyxHQUFXLEVBQXNCO0VBQzNELElBQUk7SUFDRixNQUFNQyxHQUFHLEdBQUcsT0FBT0MsT0FBTyxLQUFLLFdBQVcsR0FBR0EsT0FBTyxDQUFDRCxHQUFHLEdBQUdYLFNBQVM7SUFDcEUsTUFBTVosS0FBSyxHQUFHdUIsR0FBRyxHQUFHRCxHQUFHLENBQUM7SUFDeEIsSUFBSSxPQUFPdEIsS0FBSyxLQUFLLFFBQVEsRUFBRSxPQUFPWSxTQUFTO0lBQy9DLE1BQU1hLE9BQU8sR0FBR3pCLEtBQUssQ0FBQ2MsSUFBSSxDQUFDLENBQUM7SUFDNUIsT0FBT1csT0FBTyxDQUFDaEMsTUFBTSxHQUFHLENBQUMsR0FBR2dDLE9BQU8sR0FBR2IsU0FBUztFQUNqRCxDQUFDLENBQUMsTUFBTTtJQUNOLE9BQU9BLFNBQVM7RUFDbEI7QUFDRjtBQUVBLFNBQVNjLGVBQWVBLENBQ3RCSixHQUFXLEVBQ1hLLFFBQWlCLEVBQ1I7RUFDVCxNQUFNQyxHQUFHLEdBQUdQLGtCQUFrQixDQUFDQyxHQUFHLENBQUM7RUFDbkMsSUFBSSxDQUFDTSxHQUFHLEVBQUUsT0FBT0QsUUFBUTtFQUN6QixNQUFNZCxVQUFVLEdBQUdlLEdBQUcsQ0FBQ2IsV0FBVyxDQUFDLENBQUM7RUFDcEMsSUFBSUYsVUFBVSxLQUFLLE1BQU0sSUFBSUEsVUFBVSxLQUFLLEdBQUcsSUFBSUEsVUFBVSxLQUFLLEtBQUssSUFBSUEsVUFBVSxLQUFLLElBQUksRUFBRTtJQUM5RixPQUFPLElBQUk7RUFDYjtFQUNBLElBQUlBLFVBQVUsS0FBSyxPQUFPLElBQUlBLFVBQVUsS0FBSyxHQUFHLElBQUlBLFVBQVUsS0FBSyxJQUFJLElBQUlBLFVBQVUsS0FBSyxLQUFLLEVBQUU7SUFDL0YsT0FBTyxLQUFLO0VBQ2Q7RUFDQSxPQUFPYyxRQUFRO0FBQ2pCO0FBRUEsU0FBU0UsY0FBY0EsQ0FDckJQLEdBQVcsRUFDWEssUUFBZ0IsRUFDUjtFQUNSLE1BQU1DLEdBQUcsR0FBR1Asa0JBQWtCLENBQUNDLEdBQUcsQ0FBQztFQUNuQyxJQUFJLENBQUNNLEdBQUcsRUFBRSxPQUFPRCxRQUFRO0VBQ3pCLE1BQU1HLE1BQU0sR0FBR3BCLE1BQU0sQ0FBQ2tCLEdBQUcsQ0FBQztFQUMxQixJQUFJLENBQUNsQixNQUFNLENBQUNxQixRQUFRLENBQUNELE1BQU0sQ0FBQyxFQUFFLE9BQU9ILFFBQVE7RUFDN0MsT0FBT0csTUFBTTtBQUNmO0FBRUEsTUFBTUUsNEJBQTRCLEdBQUlDLE9BQWdCLElBQUs7RUFDekQsTUFBTVIsT0FBTyxHQUFHLENBQUNRLE9BQU8sSUFBSSxFQUFFLEVBQUVuQixJQUFJLENBQUMsQ0FBQyxDQUFDb0IsT0FBTyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUM7RUFDMUQsSUFBSSxDQUFDVCxPQUFPLEVBQUU7SUFDWixPQUFPO01BQ0xVLDRCQUE0QixFQUFFdkIsU0FBUztNQUN2Q3dCLG1CQUFtQixFQUFFeEI7SUFDdkIsQ0FBQztFQUNIO0VBQ0EsT0FBTztJQUNMdUIsNEJBQTRCLEVBQUUsR0FBR1YsT0FBTyw0Q0FBNEM7SUFDcEZXLG1CQUFtQixFQUFFLEdBQUdYLE9BQU87RUFDakMsQ0FBQztBQUNILENBQUM7QUFFRCxTQUFTWSxtQkFBbUJBLENBQzFCQyxNQUF5QyxFQUN0QjtFQUNuQixNQUFNQyxRQUEyQixHQUFHO0lBQ2xDQyxhQUFhLEVBQUV4QixzQkFBc0I7SUFDckN5QixnQkFBZ0IsRUFBRXhCLHlCQUF5QjtJQUMzQ3lCLFVBQVUsRUFBRSxJQUFJO0lBQ2hCQyxvQkFBb0IsRUFBRWpCLGVBQWUsQ0FDbkMsaUNBQWlDLEVBQ2pDUix1Q0FDRixDQUFDO0lBQ0QwQixZQUFZLEVBQUUsR0FBRztJQUNqQkMsa0JBQWtCLEVBQUUsR0FBRztJQUN2QkMsb0JBQW9CLEVBQUVqQixjQUFjLENBQ2xDLGdDQUFnQyxFQUNoQ1Ysc0NBQ0YsQ0FBQztJQUNENEIsZ0JBQWdCLEVBQUUsSUFBSTtJQUN0QkMsY0FBYyxFQUFFdEIsZUFBZSxDQUM3Qix5QkFBeUIsRUFDekJOLCtCQUNGO0VBQ0YsQ0FBQztFQUVELE1BQU02QixNQUFNLEdBQUdYLE1BQU0sRUFBRVksTUFBTSxJQUFJLENBQUMsQ0FBQztFQUNuQyxNQUFNQyxZQUFZLEdBQUdGLE1BQU0sQ0FBQ0csWUFBWTtFQUN4QyxNQUFNQyxnQkFBZ0IsR0FBR3JCLDRCQUE0QixDQUFDbUIsWUFBWSxDQUFDO0VBRW5FLE9BQUE1RCxhQUFBLENBQUFBLGFBQUEsQ0FBQUEsYUFBQSxLQUNLZ0QsUUFBUSxHQUNSVSxNQUFNO0lBQ1RkLDRCQUE0QixFQUMxQmMsTUFBTSxDQUFDZCw0QkFBNEIsSUFDbkNrQixnQkFBZ0IsQ0FBQ2xCLDRCQUE0QjtJQUMvQ0MsbUJBQW1CLEVBQ2pCYSxNQUFNLENBQUNiLG1CQUFtQixJQUFJaUIsZ0JBQWdCLENBQUNqQixtQkFBbUI7SUFDcEVrQixpQkFBaUIsRUFBRUwsTUFBTSxDQUFDSyxpQkFBaUI7SUFDM0NkLGFBQWEsRUFBRVMsTUFBTSxDQUFDVCxhQUFhLElBQUlELFFBQVEsQ0FBQ0MsYUFBYTtJQUM3REMsZ0JBQWdCLEVBQUVRLE1BQU0sQ0FBQ1IsZ0JBQWdCLElBQUlGLFFBQVEsQ0FBQ0UsZ0JBQWdCO0lBQ3RFQyxVQUFVLEVBQUVPLE1BQU0sQ0FBQ1AsVUFBVSxJQUFJSCxRQUFRLENBQUNHLFVBQVU7SUFDcERDLG9CQUFvQixFQUNsQk0sTUFBTSxDQUFDTixvQkFBb0IsSUFBSUosUUFBUSxDQUFDSSxvQkFBb0I7SUFDOURDLFlBQVksRUFBRUssTUFBTSxDQUFDTCxZQUFZLElBQUlMLFFBQVEsQ0FBQ0ssWUFBWTtJQUMxREMsa0JBQWtCLEVBQ2hCSSxNQUFNLENBQUNKLGtCQUFrQixJQUFJTixRQUFRLENBQUNNLGtCQUFrQjtJQUMxREMsb0JBQW9CLEVBQ2xCRyxNQUFNLENBQUNILG9CQUFvQixJQUFJUCxRQUFRLENBQUNPLG9CQUFvQjtJQUM5REMsZ0JBQWdCLEVBQ2RFLE1BQU0sQ0FBQ0YsZ0JBQWdCLElBQUlSLFFBQVEsQ0FBQ1EsZ0JBQWdCO0lBQ3REQyxjQUFjLEVBQ1pDLE1BQU0sQ0FBQ0QsY0FBYyxJQUFJVCxRQUFRLENBQUNTO0VBQWM7QUFFdEQ7QUFFQSxTQUFTTyxpQkFBaUJBLENBQ3hCakIsTUFBeUMsRUFDeEI7RUFDakIsTUFBTUMsUUFBeUIsR0FBRztJQUNoQ2lCLE9BQU8sRUFBRSxJQUFJO0lBQ2JDLE1BQU0sRUFBRTtFQUNWLENBQUM7RUFFRCxPQUFBbEUsYUFBQSxDQUFBQSxhQUFBLEtBQ0tnRCxRQUFRLEdBQ1BELE1BQU0sRUFBRW9CLElBQUksSUFBSSxDQUFDLENBQUM7QUFFMUI7QUFFQSxTQUFTQyx1QkFBdUJBLENBQzlCckIsTUFBeUMsRUFDbEI7RUFDdkIsTUFBTUMsUUFBK0IsR0FBRztJQUN0Q3FCLFlBQVksRUFBRSxLQUFLO0lBQ25CM0IsT0FBTyxFQUFFLHVCQUF1QjtJQUNoQzRCLElBQUksRUFBRSxTQUFTO0lBQ2ZDLEtBQUssRUFBRTtFQUNULENBQUM7RUFFRCxPQUFBdkUsYUFBQSxDQUFBQSxhQUFBLEtBQ0tnRCxRQUFRLEdBQ1BELE1BQU0sRUFBRXlCLFVBQVUsSUFBSSxDQUFDLENBQUM7QUFFaEM7O0FBRUE7QUFDQTtBQUNBO0FBQ08sU0FBU0MsMEJBQTBCQSxDQUN4Q0MsU0FBNEMsRUFDbkI7RUFDekIsTUFBTTFCLFFBQWlDLEdBQUc7SUFDeEMyQixRQUFRLEVBQUUsTUFBTTtJQUNoQkMsbUJBQW1CLEVBQUUsSUFBSTtJQUN6QlQsSUFBSSxFQUFFSCxpQkFBaUIsQ0FBQyxDQUFDO0lBQ3pCTCxNQUFNLEVBQUViLG1CQUFtQixDQUFDLENBQUM7SUFDN0IwQixVQUFVLEVBQUVKLHVCQUF1QixDQUFDO0VBQ3RDLENBQUM7RUFFRCxNQUFNUyxNQUErQixHQUFBN0UsYUFBQSxDQUFBQSxhQUFBLENBQUFBLGFBQUEsS0FDaENnRCxRQUFRLEdBQ1AwQixTQUFTLElBQUksQ0FBQyxDQUFDO0lBQ25CQyxRQUFRLEVBQ052RCxpQkFBaUIsQ0FBQ3NELFNBQVMsRUFBRUMsUUFBUSxDQUFDLElBQ3RDdkQsaUJBQWlCLENBQUM0QixRQUFRLENBQUMyQixRQUFRLENBQUMsSUFDcEM7RUFBTSxFQUNUO0VBRUQsT0FBQTNFLGFBQUEsQ0FBQUEsYUFBQSxLQUNLNkUsTUFBTTtJQUNUVixJQUFJLEVBQUVILGlCQUFpQixDQUFDYSxNQUFNLENBQUM7SUFDL0JsQixNQUFNLEVBQUViLG1CQUFtQixDQUFDK0IsTUFBTSxDQUFDO0lBQ25DTCxVQUFVLEVBQUVKLHVCQUF1QixDQUFDUyxNQUFNO0VBQUM7QUFFL0M7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsU0FBU0MsMEJBQTBCQSxDQUFBLEVBQVk7RUFDN0MsSUFBSSxPQUFPQyxNQUFNLEtBQUssV0FBVyxFQUFFO0lBQ2pDLE9BQU8sS0FBSztFQUNkO0VBRUEsT0FBTyx5QkFBeUIsSUFBSUEsTUFBTSxJQUFJLG1CQUFtQixJQUFJQSxNQUFNO0FBQzdFO0FBRU8sTUFBTUMsb0JBQW9CLEdBQUFDLE9BQUEsQ0FBQUQsb0JBQUEsR0FBR0YsMEJBQTBCO0FBRTlELE1BQU1JLG9CQUFvQixHQUFJQyxJQUFhLElBQUs7RUFDOUMsTUFBTTdELFVBQVUsR0FBRyxDQUFDNkQsSUFBSSxJQUFJLElBQUksRUFBRTVELElBQUksQ0FBQyxDQUFDLENBQUNDLFdBQVcsQ0FBQyxDQUFDO0VBQ3RELE9BQU9GLFVBQVUsQ0FBQ3BCLE1BQU0sR0FBRyxDQUFDLEdBQUdvQixVQUFVLEdBQUcsSUFBSTtBQUNsRCxDQUFDO0FBRUQsTUFBTThELG1CQUFtQixHQUFJRCxJQUFZLElBQUtBLElBQUksQ0FBQ0UsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUVoRSxNQUFNQyxpQkFBaUIsR0FBSUgsSUFBWSxJQUFLO0VBQzFDLElBQUlBLElBQUksQ0FBQ0ksVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFLE9BQU8sT0FBTztFQUN6QyxJQUFJSixJQUFJLENBQUNJLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBRSxPQUFPLE9BQU87RUFDekMsT0FBT0osSUFBSTtBQUNiLENBQUM7O0FBRUQ7QUFDQTtBQUNBOztBQVdBLElBQUlLLHVCQUE4RDtBQUVsRSxJQUFJQyw2QkFBMEU7QUFFOUUsU0FBU0MscUJBQXFCQSxDQUFBLEVBQThCO0VBQzFELElBQUlGLHVCQUF1QixLQUFLbkUsU0FBUyxFQUFFO0lBQ3pDLE9BQU9tRSx1QkFBdUI7RUFDaEM7RUFFQSxJQUFJO0lBQ0Y7SUFDQTtJQUNBQSx1QkFBdUIsR0FBRzlHLE9BQU8sQ0FBQyw2QkFBNkIsQ0FBQztFQUNsRSxDQUFDLENBQUMsT0FBT2lILEtBQUssRUFBRTtJQUNkSCx1QkFBdUIsR0FBRyxJQUFJO0lBQzlCSSxlQUFNLENBQUNDLEtBQUssQ0FBQyxtQ0FBbUMsRUFBRUYsS0FBSyxDQUFDO0VBQzFEO0VBRUEsT0FBT0gsdUJBQXVCO0FBQ2hDO0FBRUEsU0FBU00sMkJBQTJCQSxDQUFBLEVBQVk7RUFDOUMsTUFBTUMsWUFBWSxHQUFHTCxxQkFBcUIsQ0FBQyxDQUFDO0VBQzVDLE9BQU8sQ0FBQyxDQUFDSyxZQUFZLEVBQUVDLHVCQUF1QixHQUFHLENBQUM7QUFDcEQ7QUFFQSxTQUFTQywyQkFBMkJBLENBQUEsRUFBb0M7RUFDdEUsSUFBSVIsNkJBQTZCLEtBQUtwRSxTQUFTLEVBQUU7SUFDL0MsT0FBT29FLDZCQUE2QjtFQUN0QztFQUVBLElBQUk7SUFDRjtJQUNBO0lBQ0FBLDZCQUE2QixHQUFHL0csT0FBTyxDQUFDLG9DQUFvQyxDQUFDO0VBQy9FLENBQUMsQ0FBQyxPQUFPaUgsS0FBSyxFQUFFO0lBQ2RGLDZCQUE2QixHQUFHLElBQUk7SUFDcENHLGVBQU0sQ0FBQ0MsS0FBSyxDQUFDLDBDQUEwQyxFQUFFRixLQUFLLENBQUM7RUFDakU7RUFFQSxPQUFPRiw2QkFBNkI7QUFDdEM7QUFFQSxTQUFTUyxpQ0FBaUNBLENBQUEsRUFBWTtFQUNwRCxNQUFNSCxZQUFZLEdBQUdFLDJCQUEyQixDQUFDLENBQUM7RUFDbEQsT0FBTyxDQUFDLENBQUNGLFlBQVksRUFBRUksNkJBQTZCLEdBQUcsQ0FBQztBQUMxRDs7QUFFQTtBQUNBO0FBQ0E7QUFDTyxTQUFTQyw2QkFBNkJBLENBQzNDckQsTUFBK0IsRUFDL0JzRCxZQUFxQixFQUNFO0VBQ3ZCLE1BQU1DLEtBQUssR0FBR0MscUJBQVEsQ0FBQ0MsRUFBRSxLQUFLLEtBQUs7RUFDbkMsTUFBTUMsUUFBUSxHQUFHRixxQkFBUSxDQUFDQyxFQUFFLEtBQUssS0FBSyxJQUFJRCxxQkFBUSxDQUFDQyxFQUFFLEtBQUssU0FBUztFQUNuRSxNQUFNRSxrQkFBa0IsR0FBR0osS0FBSyxJQUFJLE9BQU92QixNQUFNLEtBQUssV0FBVztFQUNqRSxNQUFNNEIscUJBQXFCLEdBQUdELGtCQUFrQjtFQUNoRCxNQUFNL0IsUUFBUSxHQUFHdkQsaUJBQWlCLENBQUMyQixNQUFNLENBQUM0QixRQUFRLENBQUMsSUFBSSxNQUFNO0VBQzdELE1BQU1SLElBQUksR0FBR0gsaUJBQWlCLENBQUNqQixNQUFNLENBQUM7RUFDdEMsTUFBTVksTUFBTSxHQUFHYixtQkFBbUIsQ0FBQ0MsTUFBTSxDQUFDO0VBQzFDLE1BQU15QixVQUFVLEdBQUdKLHVCQUF1QixDQUFDckIsTUFBTSxDQUFDO0VBRWxELE1BQU02RCxVQUFVLEdBQUcsQ0FBQyxFQUFFUCxZQUFZLElBQUlsQyxJQUFJLENBQUMwQyxNQUFNLENBQUM7RUFFbEQsSUFBSWxDLFFBQVEsS0FBSyxRQUFRLEVBQUU7SUFDekIsSUFBSThCLFFBQVEsRUFBRTtNQUNaLElBQ0U5QyxNQUFNLENBQUNmLDRCQUE0QixJQUNuQ3NELGlDQUFpQyxDQUFDLENBQUMsRUFDbkM7UUFDQU4sZUFBTSxDQUFDa0IsSUFBSSxDQUFDLHlDQUF5QyxDQUFDO1FBQ3RELE9BQU8sZUFBZTtNQUN4QjtNQUNBLElBQUlILHFCQUFxQixFQUFFO1FBQ3pCZixlQUFNLENBQUNtQixJQUFJLENBQ1QsdUhBQ0YsQ0FBQztNQUNIO01BQ0EsT0FBTyxNQUFNO0lBQ2Y7SUFFQSxJQUFJVCxLQUFLLEVBQUU7TUFDVCxJQUFJM0MsTUFBTSxDQUFDZiw0QkFBNEIsSUFBSSxJQUFBb0UsZ0RBQXVCLEVBQUMsQ0FBQyxFQUFFO1FBQ3BFcEIsZUFBTSxDQUFDa0IsSUFBSSxDQUFDLHNDQUFzQyxDQUFDO1FBQ25ELE9BQU8sWUFBWTtNQUNyQjtNQUNBLElBQUlILHFCQUFxQixFQUFFO1FBQ3pCZixlQUFNLENBQUNtQixJQUFJLENBQUMsa0NBQWtDLENBQUM7TUFDakQ7TUFDQSxPQUFPLE1BQU07SUFDZjtFQUNGOztFQUVBO0VBQ0EsSUFBSU4sUUFBUSxFQUFFO0lBQ1osSUFBSXRDLElBQUksQ0FBQ0YsT0FBTyxJQUFJMkMsVUFBVSxJQUFJZCwyQkFBMkIsQ0FBQyxDQUFDLEVBQUU7TUFDL0RGLGVBQU0sQ0FBQ2tCLElBQUksQ0FBQyxrQ0FBa0MsQ0FBQztNQUMvQyxPQUFPLGFBQWE7SUFDdEI7SUFDQSxJQUFJSCxxQkFBcUIsRUFBRTtNQUN6QmYsZUFBTSxDQUFDbUIsSUFBSSxDQUNULGlIQUNGLENBQUM7SUFDSDtJQUNBLE9BQU8sTUFBTTtFQUNmOztFQUVBO0VBQ0EsSUFBSVQsS0FBSyxFQUFFO0lBQ1QsSUFBSTlCLFVBQVUsQ0FBQ0gsWUFBWSxJQUFJRyxVQUFVLENBQUM5QixPQUFPLEVBQUU7TUFDakRrRCxlQUFNLENBQUNrQixJQUFJLENBQUMsa0NBQWtDLENBQUM7TUFDL0MsT0FBTyxXQUFXO0lBQ3BCOztJQUVBO0lBQ0EsSUFBSTNDLElBQUksQ0FBQ0YsT0FBTyxJQUFJMkMsVUFBVSxJQUFJLElBQUFLLDRDQUFxQixFQUFDLENBQUMsRUFBRTtNQUN6RHJCLGVBQU0sQ0FBQ2tCLElBQUksQ0FBQywwQ0FBMEMsQ0FBQztNQUN2RCxPQUFPLFVBQVU7SUFDbkI7O0lBRUE7SUFDQSxJQUFJL0QsTUFBTSxDQUFDNkIsbUJBQW1CLElBQUlJLG9CQUFvQixDQUFDLENBQUMsRUFBRTtNQUN4RFksZUFBTSxDQUFDa0IsSUFBSSxDQUFDLG1DQUFtQyxDQUFDO01BQ2hELE9BQU8sV0FBVztJQUNwQjtFQUNGO0VBQ0EsSUFBSUgscUJBQXFCLEVBQUU7SUFDekJmLGVBQU0sQ0FBQ21CLElBQUksQ0FBQywyQ0FBMkMsQ0FBQztFQUMxRDtFQUNBLE9BQU8sTUFBTTtBQUNmOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ08sTUFBTUcsdUJBRVosR0FBR0EsQ0FBQztFQUNIQyxZQUFZO0VBQ1pDLG9CQUFvQjtFQUNwQkMsb0JBQW9CO0VBQ3BCQyx5QkFBeUI7RUFDekJDLG1CQUFtQjtFQUNuQkMsdUJBQXVCO0VBQ3ZCbkIsWUFBWTtFQUNab0IsUUFBUSxHQUFHLElBQUk7RUFDZkMsT0FBTztFQUNQQyxzQkFBc0I7RUFDdEI1RTtBQUM0QixDQUFDLEtBQUs7RUFDbEM7RUFDQSxNQUFNNkUsY0FBYyxHQUFHbkQsMEJBQTBCLENBQUMxQixNQUFNLENBQUM7RUFDekQsTUFBTTJELGtCQUFrQixHQUN0QkgscUJBQVEsQ0FBQ0MsRUFBRSxLQUFLLEtBQUssSUFBSSxPQUFPekIsTUFBTSxLQUFLLFdBQVc7RUFDeEQsTUFBTThDLGtCQUFrQixHQUFHM0Msb0JBQW9CLENBQUN1QyxRQUFRLENBQUM7RUFDekQsTUFBTUssV0FBVyxHQUFHMUMsbUJBQW1CLENBQUN5QyxrQkFBa0IsQ0FBQztFQUMzRCxNQUFNRSxpQkFBaUIsR0FBR3pDLGlCQUFpQixDQUFDdUMsa0JBQWtCLENBQUM7O0VBRS9EO0VBQ0EsTUFBTUcsTUFBTSxHQUFHNUIsNkJBQTZCLENBQUN3QixjQUFjLEVBQUV2QixZQUFZLENBQUM7RUFDMUUsSUFBSUssa0JBQWtCLEVBQUU7SUFDdEJkLGVBQU0sQ0FBQ0MsS0FBSyxDQUFDLHFDQUFxQyxFQUFFbUMsTUFBTSxDQUFDO0VBQzdEO0VBQ0EsTUFBTUMsVUFBVSxHQUFHakUsaUJBQWlCLENBQUM0RCxjQUFjLENBQUM7RUFDcEQsTUFBTU0sWUFBWSxHQUFHcEYsbUJBQW1CLENBQUM4RSxjQUFjLENBQUM7RUFDeEQsTUFBTU8sZ0JBQWdCLEdBQUcvRCx1QkFBdUIsQ0FBQ3dELGNBQWMsQ0FBQztFQUVoRSxNQUFNUSxlQUFlLEdBQUcvQixZQUFZLElBQUk0QixVQUFVLENBQUNwQixNQUFNLElBQUksRUFBRTtFQUMvRCxNQUFNd0IsY0FBYyxHQUFHSixVQUFVLENBQUNLLFVBQVU7RUFDNUMsTUFBTUMseUJBQXlCLEdBQUdOLFVBQVUsQ0FBQ08scUJBQXFCO0VBQ2xFLE1BQU1DLFVBQVUsR0FBR1IsVUFBVSxDQUFDL0QsTUFBTTtFQUVwQyxJQUFJK0QsVUFBVSxDQUFDaEUsT0FBTyxJQUFJLENBQUNtRSxlQUFlLEVBQUU7SUFDMUN4QyxlQUFNLENBQUNtQixJQUFJLENBQ1QsMEdBQ0YsQ0FBQztFQUNIOztFQUVBO0VBQ0EsTUFBTTJCLFdBQVcsR0FBSS9DLEtBQVksSUFBSztJQUNwQ0MsZUFBTSxDQUFDRCxLQUFLLENBQUMsMkJBQTJCLEVBQUVBLEtBQUssQ0FBQztJQUVoRCxJQUFJK0IsT0FBTyxFQUFFO01BQ1hBLE9BQU8sQ0FBQy9CLEtBQUssQ0FBQztJQUNoQjs7SUFFQTtJQUNBO0VBQ0YsQ0FBQzs7RUFFRDtFQUNBLFFBQVFxQyxNQUFNO0lBQ1osS0FBSyxlQUFlO01BQUU7UUFDcEIsSUFBSSxDQUFDRSxZQUFZLENBQUN0Riw0QkFBNEIsRUFBRTtVQUM5Q2dELGVBQU0sQ0FBQ0QsS0FBSyxDQUNWLG9FQUNGLENBQUM7VUFDRCxPQUFPLElBQUk7UUFDYjtRQUVBLE1BQU1nRCxrQkFBa0IsR0FBRzFDLDJCQUEyQixDQUFDLENBQUM7UUFDeEQsSUFBSSxDQUFDMEMsa0JBQWtCLEVBQUVDLDRCQUE0QixFQUFFO1VBQ3JEaEQsZUFBTSxDQUFDRCxLQUFLLENBQ1Ysa0dBQ0YsQ0FBQztVQUNELE9BQU8sSUFBSTtRQUNiO1FBRUEsTUFBTWlELDRCQUE0QixHQUNoQ0Qsa0JBQWtCLENBQUNDLDRCQUE0QjtRQUVqRCxvQkFDRXBLLE1BQUEsQ0FBQVcsT0FBQSxDQUFBMEosYUFBQSxDQUFDRCw0QkFBNEI7VUFDM0J6QixZQUFZLEVBQUVBLFlBQWE7VUFDM0JDLG9CQUFvQixFQUFFQSxvQkFBcUI7VUFDM0NDLG9CQUFvQixFQUFFQSxvQkFBcUI7VUFDM0NDLHlCQUF5QixFQUFFQSx5QkFBMEI7VUFDckRDLG1CQUFtQixFQUFFQSxtQkFBb0I7VUFDekNsQixZQUFZLEVBQUUrQixlQUFnQjtVQUM5QlUsa0NBQWtDLEVBQ2hDWixZQUFZLENBQUN0Riw0QkFDZDtVQUNEbUcseUJBQXlCLEVBQUViLFlBQVksQ0FBQ3JGLG1CQUFvQjtVQUM1RG1HLHVCQUF1QixFQUFFZCxZQUFZLENBQUNuRSxpQkFBa0I7VUFDeERrRixtQkFBbUIsRUFBRWYsWUFBWSxDQUFDakYsYUFBYztVQUNoRGlHLHNCQUFzQixFQUFFaEIsWUFBWSxDQUFDaEYsZ0JBQWlCO1VBQ3REaUcsZ0JBQWdCLEVBQUVqQixZQUFZLENBQUMvRSxVQUFXO1VBQzFDaUcsMEJBQTBCLEVBQ3hCbEIsWUFBWSxDQUFDOUUsb0JBQ2Q7VUFDRGlHLGtCQUFrQixFQUFFbkIsWUFBWSxDQUFDN0UsWUFBYTtVQUM5Q2lHLHdCQUF3QixFQUFFcEIsWUFBWSxDQUFDNUUsa0JBQW1CO1VBQzFEaUcsMEJBQTBCLEVBQ3hCckIsWUFBWSxDQUFDM0Usb0JBQ2Q7VUFDRGlHLHNCQUFzQixFQUFFdEIsWUFBWSxDQUFDMUUsZ0JBQWlCO1VBQ3REaUcsb0JBQW9CLEVBQUV2QixZQUFZLENBQUN6RSxjQUFlO1VBQ2xEZ0UsUUFBUSxFQUFFSyxXQUFZO1VBQ3RCSCxzQkFBc0IsRUFBRUEsc0JBQXVCO1VBQy9DRCxPQUFPLEVBQUVnQjtRQUFZLENBQ3RCLENBQUM7TUFFTjtJQUVBLEtBQUssWUFBWTtNQUNmLElBQUksQ0FBQ1IsWUFBWSxDQUFDdEYsNEJBQTRCLEVBQUU7UUFDOUNnRCxlQUFNLENBQUNELEtBQUssQ0FDVixvRUFDRixDQUFDO1FBQ0QsT0FBTyxJQUFJO01BQ2I7TUFFQSxvQkFDRW5ILE1BQUEsQ0FBQVcsT0FBQSxDQUFBMEosYUFBQSxDQUFDOUosd0JBQUEsQ0FBQTJLLHNCQUFzQjtRQUNyQnZDLFlBQVksRUFBRUEsWUFBYTtRQUMzQkMsb0JBQW9CLEVBQUVBLG9CQUFxQjtRQUMzQ0Msb0JBQW9CLEVBQUVBLG9CQUFxQjtRQUMzQ0MseUJBQXlCLEVBQUVBLHlCQUEwQjtRQUNyREMsbUJBQW1CLEVBQUVBLG1CQUFvQjtRQUN6Q2xCLFlBQVksRUFBRStCLGVBQWdCO1FBQzlCVSxrQ0FBa0MsRUFDaENaLFlBQVksQ0FBQ3RGLDRCQUNkO1FBQ0RtRyx5QkFBeUIsRUFBRWIsWUFBWSxDQUFDckYsbUJBQW9CO1FBQzVEbUcsdUJBQXVCLEVBQUVkLFlBQVksQ0FBQ25FLGlCQUFrQjtRQUN4RGtGLG1CQUFtQixFQUFFZixZQUFZLENBQUNqRixhQUFjO1FBQ2hEaUcsc0JBQXNCLEVBQUVoQixZQUFZLENBQUNoRixnQkFBaUI7UUFDdERpRyxnQkFBZ0IsRUFBRWpCLFlBQVksQ0FBQy9FLFVBQVc7UUFDMUNpRywwQkFBMEIsRUFDeEJsQixZQUFZLENBQUM5RSxvQkFDZDtRQUNEaUcsa0JBQWtCLEVBQUVuQixZQUFZLENBQUM3RSxZQUFhO1FBQzlDaUcsd0JBQXdCLEVBQUVwQixZQUFZLENBQUM1RSxrQkFBbUI7UUFDMURpRywwQkFBMEIsRUFDeEJyQixZQUFZLENBQUMzRSxvQkFDZDtRQUNEaUcsc0JBQXNCLEVBQUV0QixZQUFZLENBQUMxRSxnQkFBaUI7UUFDdERpRyxvQkFBb0IsRUFBRXZCLFlBQVksQ0FBQ3pFLGNBQWU7UUFDbERnRSxRQUFRLEVBQUVLLFdBQVk7UUFDdEJILHNCQUFzQixFQUFFQSxzQkFBdUI7UUFDL0NELE9BQU8sRUFBRWdCO01BQVksQ0FDdEIsQ0FBQztJQUdOLEtBQUssYUFBYTtNQUFFO1FBQ2xCLElBQUksQ0FBQ04sZUFBZSxFQUFFO1VBQ3BCeEMsZUFBTSxDQUFDRCxLQUFLLENBQUMsMkNBQTJDLENBQUM7VUFDekQsT0FBTyxJQUFJO1FBQ2I7UUFFQSxNQUFNSSxZQUFZLEdBQUdMLHFCQUFxQixDQUFDLENBQUM7UUFDNUMsSUFBSSxDQUFDSyxZQUFZLEVBQUU0RCxzQkFBc0IsRUFBRTtVQUN6Qy9ELGVBQU0sQ0FBQ0QsS0FBSyxDQUNWLHdHQUNGLENBQUM7VUFDRCxPQUFPLElBQUk7UUFDYjtRQUVBLE1BQU1nRSxzQkFBc0IsR0FBRzVELFlBQVksQ0FBQzRELHNCQUFzQjtRQUNsRSxvQkFDRW5MLE1BQUEsQ0FBQVcsT0FBQSxDQUFBMEosYUFBQSxDQUFDYyxzQkFBc0I7VUFDckJ4QyxZQUFZLEVBQUVBLFlBQWE7VUFDM0JDLG9CQUFvQixFQUFFQSxvQkFBcUI7VUFDM0NDLG9CQUFvQixFQUFFQSxvQkFBcUI7VUFDM0NDLHlCQUF5QixFQUFFQSx5QkFBMEI7VUFDckRqQixZQUFZLEVBQUUrQixlQUFnQjtVQUM5QkMsY0FBYyxFQUFFQSxjQUFlO1VBQy9CRSx5QkFBeUIsRUFBRUEseUJBQTBCO1VBQ3JEckUsTUFBTSxFQUFFdUUsVUFBVztVQUNuQmhCLFFBQVEsRUFBRUssV0FBWTtVQUN0QkosT0FBTyxFQUFFZ0I7UUFBWSxDQUN0QixDQUFDO01BRU47SUFFQSxLQUFLLFVBQVU7TUFDYixJQUFJLENBQUNOLGVBQWUsRUFBRTtRQUNwQnhDLGVBQU0sQ0FBQ0QsS0FBSyxDQUFDLDJDQUEyQyxDQUFDO1FBQ3pELE9BQU8sSUFBSTtNQUNiO01BQ0Esb0JBQ0VuSCxNQUFBLENBQUFXLE9BQUEsQ0FBQTBKLGFBQUEsQ0FBQ2hLLHNCQUFBLENBQUErSyxvQkFBb0I7UUFDbkJ6QyxZQUFZLEVBQUVBLFlBQWE7UUFDM0JDLG9CQUFvQixFQUFFQSxvQkFBcUI7UUFDM0NDLG9CQUFvQixFQUFFQSxvQkFBcUI7UUFDM0NDLHlCQUF5QixFQUFFQSx5QkFBMEI7UUFDckRqQixZQUFZLEVBQUUrQixlQUFnQjtRQUM5QkMsY0FBYyxFQUFFQSxjQUFlO1FBQy9CRSx5QkFBeUIsRUFBRUEseUJBQTBCO1FBQ3JEckUsTUFBTSxFQUFFdUUsVUFBVztRQUNuQmhCLFFBQVEsRUFBRUssV0FBWTtRQUN0QkosT0FBTyxFQUFFZ0I7TUFBWSxDQUN0QixDQUFDO0lBR04sS0FBSyxXQUFXO01BQUU7UUFDaEIsTUFBTW1CLFlBQVksR0FBRzFCLGdCQUFnQixDQUFDekYsT0FBTztRQUM3QyxJQUFJLENBQUNtSCxZQUFZLEVBQUU7VUFDakJqRSxlQUFNLENBQUNELEtBQUssQ0FBQyxnREFBZ0QsQ0FBQztVQUM5RCxPQUFPLElBQUk7UUFDYjtRQUVBLG9CQUNFbkgsTUFBQSxDQUFBVyxPQUFBLENBQUEwSixhQUFBLENBQUMvSixxQkFBQSxDQUFBZ0wsbUJBQW1CO1VBQ2xCM0MsWUFBWSxFQUFFQSxZQUFhO1VBQzNCQyxvQkFBb0IsRUFBRUEsb0JBQXFCO1VBQzNDQyxvQkFBb0IsRUFBRUEsb0JBQXFCO1VBQzNDSSxRQUFRLEVBQUVLLFdBQVk7VUFDdEJKLE9BQU8sRUFBRWdCLFdBQVk7VUFDckJoRyxPQUFPLEVBQUVtSCxZQUFhO1VBQ3RCdkYsSUFBSSxFQUFFNkQsZ0JBQWdCLENBQUM3RCxJQUFLO1VBQzVCeUYsU0FBUyxFQUFFNUIsZ0JBQWdCLENBQUM1RDtRQUFNLENBQ25DLENBQUM7TUFFTjtJQUVBLEtBQUssV0FBVztNQUNkLG9CQUNFL0YsTUFBQSxDQUFBVyxPQUFBLENBQUEwSixhQUFBLENBQUNqSyxrQkFBQSxDQUFBb0wsZ0JBQW1CO1FBQ2xCN0MsWUFBWSxFQUFFQSxZQUFhO1FBQzNCQyxvQkFBb0IsRUFBRUEsb0JBQXFCO1FBQzNDQyxvQkFBb0IsRUFBRUEsb0JBQXFCO1FBQzNDSSxRQUFRLEVBQUVNO01BQWtCLENBQzdCLENBQUM7SUFHTixLQUFLLE1BQU07SUFDWDtNQUNFLElBQUlyQixrQkFBa0IsRUFBRTtRQUN0QmQsZUFBTSxDQUFDbUIsSUFBSSxDQUFDLGlDQUFpQyxDQUFDO01BQ2hEO01BQ0EsT0FBTyxJQUFJO0VBQ2Y7QUFDRixDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUZBOUIsT0FBQSxDQUFBaUMsdUJBQUEsR0FBQUEsdUJBQUE7QUFHTyxTQUFTK0MsMEJBQTBCQSxDQUN4Q3ZGLFNBQTRDLEVBQzVDO0VBQ0EsTUFBTTNCLE1BQU0sR0FBRzBCLDBCQUEwQixDQUFDQyxTQUFTLENBQUM7RUFDcEQsTUFBTXNELE1BQU0sR0FBRzVCLDZCQUE2QixDQUFDckQsTUFBTSxDQUFDO0VBQ3BELE1BQU15QixVQUFVLEdBQUdKLHVCQUF1QixDQUFDckIsTUFBTSxDQUFDO0VBRWxELE9BQU87SUFDTGlGLE1BQU07SUFDTmpGLE1BQU07SUFDTm1ILFlBQVksRUFBRTtNQUNaL0YsSUFBSSxFQUFFLElBQUFnRyxnREFBeUIsRUFBQyxDQUFDO01BQ2pDeEcsTUFBTSxFQUFFLElBQUF5RyxvREFBMkIsRUFBQyxDQUFDO01BQ3JDQyxTQUFTLEVBQUU7UUFDVEMsU0FBUyxFQUFFdEYsb0JBQW9CLENBQUMsQ0FBQztRQUNqQ3VGLFFBQVEsRUFBRWhFLHFCQUFRLENBQUNDO01BQ3JCLENBQUM7TUFDRGhDLFVBQVUsRUFBRTtRQUNWUCxPQUFPLEVBQUUsQ0FBQyxDQUFDTyxVQUFVLENBQUNILFlBQVk7UUFDbENtRyxHQUFHLEVBQUVoRyxVQUFVLENBQUM5QixPQUFPO1FBQ3ZCNEIsSUFBSSxFQUFFRSxVQUFVLENBQUNGLElBQUksSUFBSTtNQUMzQjtJQUNGLENBQUM7SUFDRG1HLGVBQWUsRUFBRUMsa0JBQWtCLENBQUMxQyxNQUFNLEVBQUVqRixNQUFNO0VBQ3BELENBQUM7QUFDSDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxTQUFTMkgsa0JBQWtCQSxDQUN6QjFDLE1BT1UsRUFDVmpGLE1BQStCLEVBQ3JCO0VBQ1YsTUFBTTBILGVBQXlCLEdBQUcsRUFBRTtFQUVwQyxJQUFJekMsTUFBTSxLQUFLLE1BQU0sRUFBRTtJQUNyQnlDLGVBQWUsQ0FBQzNLLElBQUksQ0FBQyxpQ0FBaUMsQ0FBQztJQUV2RCxJQUFJLENBQUNpRCxNQUFNLENBQUNvQixJQUFJLEVBQUUwQyxNQUFNLElBQUk5RCxNQUFNLENBQUM0QixRQUFRLEtBQUssUUFBUSxFQUFFO01BQ3hEOEYsZUFBZSxDQUFDM0ssSUFBSSxDQUNsQixnRUFDRixDQUFDO0lBQ0g7SUFFQSxJQUFJeUcscUJBQVEsQ0FBQ0MsRUFBRSxLQUFLLEtBQUssRUFBRTtNQUN6QixJQUFJLENBQUMsSUFBQVMsNENBQXFCLEVBQUMsQ0FBQyxFQUFFO1FBQzVCd0QsZUFBZSxDQUFDM0ssSUFBSSxDQUFDLDRDQUE0QyxDQUFDO01BQ3BFO01BRUEsSUFBSSxDQUFDa0Ysb0JBQW9CLENBQUMsQ0FBQyxFQUFFO1FBQzNCeUYsZUFBZSxDQUFDM0ssSUFBSSxDQUFDLHlDQUF5QyxDQUFDO01BQ2pFO0lBQ0YsQ0FBQyxNQUFNO01BQ0wySyxlQUFlLENBQUMzSyxJQUFJLENBQ2xCLGtFQUNGLENBQUM7SUFDSDtFQUNGO0VBRUEsSUFBSWtJLE1BQU0sS0FBSyxXQUFXLEVBQUU7SUFDMUJ5QyxlQUFlLENBQUMzSyxJQUFJLENBQUMsK0NBQStDLENBQUM7SUFDckUySyxlQUFlLENBQUMzSyxJQUFJLENBQUMsd0NBQXdDLENBQUM7RUFDaEU7RUFFQSxJQUFJa0ksTUFBTSxLQUFLLFVBQVUsRUFBRTtJQUN6QnlDLGVBQWUsQ0FBQzNLLElBQUksQ0FBQyw4Q0FBOEMsQ0FBQztFQUN0RTtFQUVBLElBQUlrSSxNQUFNLEtBQUssYUFBYSxFQUFFO0lBQzVCeUMsZUFBZSxDQUFDM0ssSUFBSSxDQUFDLHdDQUF3QyxDQUFDO0VBQ2hFO0VBRUEsSUFBSWtJLE1BQU0sS0FBSyxZQUFZLEVBQUU7SUFDM0J5QyxlQUFlLENBQUMzSyxJQUFJLENBQUMsMkNBQTJDLENBQUM7RUFDbkU7RUFFQSxJQUFJa0ksTUFBTSxLQUFLLGVBQWUsRUFBRTtJQUM5QnlDLGVBQWUsQ0FBQzNLLElBQUksQ0FBQyw4Q0FBOEMsQ0FBQztFQUN0RTtFQUVBLElBQUlrSSxNQUFNLEtBQUssV0FBVyxFQUFFO0lBQzFCeUMsZUFBZSxDQUFDM0ssSUFBSSxDQUFDLGdEQUFnRCxDQUFDO0lBQ3RFLElBQUksQ0FBQ2lELE1BQU0sQ0FBQ3lCLFVBQVUsRUFBRTlCLE9BQU8sRUFBRTtNQUMvQitILGVBQWUsQ0FBQzNLLElBQUksQ0FBQywrQ0FBK0MsQ0FBQztJQUN2RTtFQUNGO0VBRUEsT0FBTzJLLGVBQWU7QUFDeEI7O0FBRUE7QUFRQTtBQUFBLElBQUFFLFFBQUEsR0FBQTFGLE9BQUEsQ0FBQTlGLE9BQUEsR0FDZStILHVCQUF1QiIsImlnbm9yZUxpc3QiOltdfQ==
|