@fhevm/sdk 0.14.0-12 → 0.14.0-14

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.
@@ -1,753 +0,0 @@
1
- /**
2
- * Auto-generated from scripts/wasm/tfhe/startWorkers.template.js.
3
- * Embedded worker base64 payload SHA-256: 5fca7aa73420d7cc3b7239496ea5c70bc2cb520dd2f3f500801da18b126b0c54
4
- */
5
-
6
- /**
7
- * Worker load mode security guarantees:
8
- *
9
- * embedded-base64 Integrity: build-time. Inherits the JS bundle's integrity.
10
- * verified-blob Integrity: runtime SHA-256 of fetched bytes; executed bytes
11
- * are the verified bytes themselves.
12
- * precheck-direct-url No integrity guarantee. The SDK fetches the URL once and
13
- * validates SHA-256, then the runtime fetches the URL a
14
- * second time and executes those (unverified) bytes. Use
15
- * for fail-fast on misconfigured URLs / wrong builds, not
16
- * for protection against on-path or CDN-edge tampering.
17
- * trusted-direct-url No integrity check. Use only when the URL is fully trusted
18
- * (e.g., same-origin static asset).
19
- * auto Tries verified-blob if workerUrl is set, falls back to
20
- * embedded-base64 on any non-SHA-256 error. SHA-256 mismatch
21
- * is always fatal and never falls back.
22
- */
23
-
24
- /**
25
- * Module invariants.
26
- *
27
- * Lifecycle (one-shot, no retry):
28
- * - setWorkerUrlConfig() and startWorkers() each at most once.
29
- * - A failed startWorkers() locks the module; no retry, no reconfigure.
30
- * - terminateWorkers() throws while startWorkers() is in flight; idempotent after.
31
- *
32
- * Concurrency:
33
- * - _started and _starting are check-and-set without intervening await.
34
- * - Parallel workers dedupe to a single fetch+verify (cached promise).
35
- *
36
- * Security:
37
- * - SHA-256 mismatch (Sha256MismatchError) is always fatal — never falls back.
38
- * - Hash is the build-time constant "2c2ef02437e5b7a41f4c5c1defa0a24dcfae737037a59a145a972bb4191571b8".
39
- * - auto silently falls back to embedded-base64 on any non-SHA-256 error.
40
- * - precheck-direct-url's SHA-256 check is informational; the runtime refetches.
41
- *
42
- * Errors:
43
- * - Partial worker-pool failure: successful workers are terminated before throw.
44
- * - Concurrent failures: only the first error is surfaced.
45
- * - __waitForMsgType has no timeout — a silent worker hangs startWorkers().
46
- *
47
- * Resources:
48
- * - Blob URLs are revoked on both success and synchronous-constructor failure.
49
- * - _verifiedWorkerUrlBytesPromise is cleared in startWorkers()'s finally.
50
- * - _workers is a strong reference (owns the shared WebAssembly memory).
51
- * - __waitForMsgType listeners are not removed if the worker never replies.
52
- *
53
- * Caller contract:
54
- * - workerUrl: URL instance (required for verified/checked/trusted-direct-url).
55
- * - logger: must expose debug(message) and error(message, cause).
56
- * - wasmAssetLoadMode: one of __wasmAssetLoadModes.
57
- */
58
-
59
- ////////////////////////////////////////////////////////////////////////////////
60
- // Load modes
61
- ////////////////////////////////////////////////////////////////////////////////
62
-
63
- // Environment detection (browser vs Node) is NOT done here: the SDK resolves it
64
- // once on the main thread (via environment.ts isBrowserLike, robust to bundler
65
- // `process` shims) and injects it through setWorkerUrlConfig({ isBrowserLike }).
66
- // See `_isBrowserLike` below.
67
-
68
- const __wasmAssetLoadModes = ['embedded-base64', 'verified-blob', 'precheck-direct-url', 'trusted-direct-url', 'auto'];
69
-
70
- function __isWasmAssetLoadMode(value) {
71
- return __wasmAssetLoadModes.includes(value);
72
- }
73
-
74
- ////////////////////////////////////////////////////////////////////////////////
75
- // SHA-256 verification
76
- ////////////////////////////////////////////////////////////////////////////////
77
-
78
- function __bytesToHex(bytes) {
79
- return [...bytes].map((b) => b.toString(16).padStart(2, '0')).join('');
80
- }
81
-
82
- /**
83
- * Computes the SHA-256 digest of worker bytes and returns it as lowercase hex.
84
- * @param {ArrayBuffer | Uint8Array} bytes Worker bytes to hash.
85
- * @returns {Promise<string>} Lowercase hexadecimal SHA-256 digest without a `0x` prefix.
86
- */
87
- async function __sha256(bytes) {
88
- if (_isBrowserLike) {
89
- if (typeof crypto === 'undefined' || !crypto.subtle || typeof crypto.subtle.digest !== 'function') {
90
- throw new Error('Web Crypto SHA-256 digest is not available');
91
- }
92
-
93
- const hash = await crypto.subtle.digest('SHA-256', bytes);
94
- return __bytesToHex(new Uint8Array(hash));
95
- }
96
-
97
- const nodeModuleName = 'crypto';
98
- const nodeModuleId = `node:${nodeModuleName}`;
99
- const { createHash } = await import(
100
- /* @vite-ignore */ /* webpackIgnore: true */ /* turbopackIgnore: true */ nodeModuleId
101
- );
102
- return createHash('sha256').update(new Uint8Array(bytes)).digest('hex');
103
- }
104
-
105
- /**
106
- * Verifies that worker bytes match the expected SHA-256 digest.
107
- * @param {ArrayBuffer | Uint8Array} bytes Worker bytes to verify.
108
- * @param {string} expectedSha256 Expected lowercase hex digest without a `0x` prefix.
109
- * @param {string} url Url to verify.
110
- * @returns {Promise<void>} Resolves when the digest matches.
111
- * @throws {Error} Throws a `Sha256MismatchError` when the digest does not match.
112
- */
113
- async function __verifySha256(bytes, expectedSha256, url) {
114
- const actualSha256 = await __sha256(bytes);
115
-
116
- if (actualSha256 !== expectedSha256) {
117
- const error = new Error(`SHA-256 mismatch: expected ${expectedSha256}, got ${actualSha256}. url=${url}`);
118
- error.name = 'Sha256MismatchError';
119
- throw error;
120
- }
121
- }
122
-
123
- function __isSha256MismatchError(error) {
124
- return error?.name === 'Sha256MismatchError';
125
- }
126
-
127
- ////////////////////////////////////////////////////////////////////////////////
128
- // Worker URL byte loading
129
- ////////////////////////////////////////////////////////////////////////////////
130
-
131
- /**
132
- * Reads worker script bytes from a URL and verifies their SHA-256 digest.
133
- * @param {URL} url Worker script URL.
134
- * @param {string} expectedSha256 Expected lowercase hex digest without a `0x` prefix.
135
- * @returns {Promise<ArrayBuffer | Uint8Array>} Verified worker script bytes.
136
- */
137
- async function __fetchAndVerifyWorkerUrlBytes(url, expectedSha256) {
138
- const bytes = await __readWorkerUrlBytes(url);
139
-
140
- await __verifySha256(bytes, expectedSha256, url);
141
-
142
- return bytes;
143
- }
144
-
145
- /**
146
- * Reads worker script bytes from a URL.
147
- * Uses the filesystem for Node `file:` URLs, otherwise falls back to `fetch`.
148
- * Assumes `fetch` exists for non-`file:` URLs.
149
- * @param {URL} url Worker script URL.
150
- * @returns {Promise<ArrayBuffer | Uint8Array>} Raw worker script bytes.
151
- */
152
- async function __readWorkerUrlBytes(url) {
153
- if (!_isBrowserLike && url.protocol === 'file:') {
154
- const fsModuleName = 'fs/promises';
155
- const fsModuleId = `node:${fsModuleName}`;
156
- const urlModuleName = 'url';
157
- const urlModuleId = `node:${urlModuleName}`;
158
- const { readFile } = await import(
159
- /* @vite-ignore */ /* webpackIgnore: true */ /* turbopackIgnore: true */ fsModuleId
160
- );
161
- const { fileURLToPath } = await import(
162
- /* @vite-ignore */ /* webpackIgnore: true */ /* turbopackIgnore: true */ urlModuleId
163
- );
164
- return await readFile(fileURLToPath(url));
165
- }
166
-
167
- const response = await fetch(url);
168
- if (!response.ok) {
169
- throw new Error(`Failed to fetch worker: ${response.status} ${response.statusText}`);
170
- }
171
-
172
- return await response.arrayBuffer();
173
- }
174
-
175
- ////////////////////////////////////////////////////////////////////////////////
176
- // Worker construction primitives
177
- ////////////////////////////////////////////////////////////////////////////////
178
-
179
- /**
180
- * Creates a browser module Worker from a Blob.
181
- * Browser-only: creates a Blob URL and returns it so the caller can revoke it after worker startup.
182
- * @param {Blob} blob JavaScript worker source Blob.
183
- * @returns {Promise<{ worker: Worker, blobUrl: string }>} Created browser worker and Blob URL to revoke.
184
- */
185
- async function __newBrowserWorkerFromBlob(blob) {
186
- const blobUrl = URL.createObjectURL(blob);
187
-
188
- try {
189
- const worker = new Worker(blobUrl, {
190
- type: 'module',
191
- name: 'wasm_bindgen_worker',
192
- });
193
-
194
- return { worker, blobUrl };
195
- } catch (e) {
196
- URL.revokeObjectURL(blobUrl);
197
- throw e;
198
- }
199
- }
200
-
201
- /**
202
- * Creates a module Worker that loads its script directly from a URL object, isomorphically.
203
- * Browsers use the global Worker; Node uses worker_threads' Worker.
204
- * @param {URL} url Worker script URL.
205
- * @returns {Promise<Worker>} Created worker.
206
- */
207
- async function __newIsomorphicWorkerFromUrl(url) {
208
- if (_isBrowserLike) {
209
- return new Worker(url, {
210
- type: 'module',
211
- name: 'wasm_bindgen_worker',
212
- });
213
- }
214
-
215
- const nodeModuleName = 'worker_threads';
216
- const nodeModuleId = `node:${nodeModuleName}`;
217
- const { Worker: NodeWorker } = await import(
218
- /* @vite-ignore */ /* webpackIgnore: true */ /* turbopackIgnore: true */ nodeModuleId
219
- );
220
- return new NodeWorker(url);
221
- }
222
-
223
- async function __newNodeWorkerFromJsCode(jsCode) {
224
- const nodeModuleName = 'worker_threads';
225
- const nodeModuleId = `node:${nodeModuleName}`;
226
- const { Worker: NodeWorker } = await import(
227
- /* @vite-ignore */ /* webpackIgnore: true */ /* turbopackIgnore: true */ nodeModuleId
228
- );
229
- return { worker: new NodeWorker(jsCode, { eval: true }), blobUrl: undefined };
230
- }
231
-
232
- /**
233
- * Creates a worker from already verified JavaScript source bytes.
234
- * 1. Caller must provide bytes returned by the SHA-256 verification path.
235
- * 2. In browsers, wrap the verified bytes in a Blob URL and create a module Worker.
236
- * 3. In Node, decode the verified bytes as UTF-8 JavaScript and create a worker_threads eval Worker.
237
- * @param {ArrayBuffer | Uint8Array} verifiedJsCodeBytes SHA-256 verified JavaScript source bytes.
238
- * @returns {Promise<{ worker: Worker, blobUrl: string | undefined }>} Created worker and optional Blob URL to revoke.
239
- */
240
- async function __newIsomorphicWorkerFromVerifiedJsCodeBytes(verifiedJsCodeBytes) {
241
- if (_isBrowserLike) {
242
- return await __newBrowserWorkerFromBlob(
243
- new Blob([verifiedJsCodeBytes], {
244
- type: 'application/javascript',
245
- }),
246
- );
247
- }
248
-
249
- return await __newNodeWorkerFromJsCode(Buffer.from(verifiedJsCodeBytes).toString('utf-8'));
250
- }
251
-
252
- /**
253
- * Creates a worker from the SDK-embedded base64 JavaScript source.
254
- * 1. In browsers, decode the base64 source into a Blob URL and create a module Worker.
255
- * 2. In Node, decode the base64 source into UTF-8 JavaScript and create a worker_threads eval Worker.
256
- * @param {string} jsCodeBase64 Base64-encoded JavaScript worker source.
257
- * @returns {Promise<{ worker: Worker, blobUrl: string | undefined }>} Created worker and optional Blob URL to revoke.
258
- */
259
- async function __newWorkerFromJsCodeBase64(jsCodeBase64) {
260
- if (_isBrowserLike) {
261
- const blob = new Blob([atob(jsCodeBase64)], {
262
- type: 'application/javascript',
263
- });
264
-
265
- const blobUrl = URL.createObjectURL(blob);
266
-
267
- try {
268
- const worker = new Worker(blobUrl, {
269
- type: 'module',
270
- name: 'wasm_bindgen_worker',
271
- });
272
-
273
- return { worker, blobUrl };
274
- } catch (e) {
275
- URL.revokeObjectURL(blobUrl);
276
- throw e;
277
- }
278
- }
279
-
280
- const code = Buffer.from(jsCodeBase64, 'base64').toString('utf-8');
281
- return await __newNodeWorkerFromJsCode(code);
282
- }
283
-
284
- ////////////////////////////////////////////////////////////////////////////////
285
- // Worker message protocol
286
- ////////////////////////////////////////////////////////////////////////////////
287
-
288
- function __waitForMsgType(target, type) {
289
- return new Promise((resolve, reject) => {
290
- function cleanup() {
291
- if (typeof target.removeEventListener === 'function') {
292
- target.removeEventListener('message', onBrowserMsg);
293
- target.removeEventListener('error', onBrowserError);
294
- } else {
295
- target.off('message', onNodeMsg);
296
- target.off('error', onNodeError);
297
- target.off('exit', onNodeExit);
298
- }
299
- }
300
-
301
- function onBrowserMsg({ data }) {
302
- if (data?.type !== type) return;
303
- cleanup();
304
- resolve(data);
305
- }
306
-
307
- function onBrowserError(e) {
308
- cleanup();
309
- reject(e.error || new Error('Worker error'));
310
- }
311
-
312
- function onNodeMsg(data) {
313
- if (data?.type !== type) return;
314
- cleanup();
315
- resolve(data);
316
- }
317
-
318
- function onNodeError(err) {
319
- cleanup();
320
- reject(err);
321
- }
322
-
323
- function onNodeExit(code) {
324
- cleanup();
325
- reject(new Error(`Worker exited with code ${code}`));
326
- }
327
-
328
- if (typeof target.removeEventListener === 'function') {
329
- target.addEventListener('message', onBrowserMsg);
330
- target.addEventListener('error', onBrowserError);
331
- } else {
332
- target.on('message', onNodeMsg);
333
- target.on('error', onNodeError);
334
- target.on('exit', onNodeExit);
335
- }
336
- });
337
- }
338
-
339
- ////////////////////////////////////////////////////////////////////////////////
340
- // Module state
341
- ////////////////////////////////////////////////////////////////////////////////
342
-
343
- let _terminating;
344
- let _configSet = false;
345
- let _workerUrl = undefined;
346
- let _wasmAssetLoadMode = 'auto';
347
- // Injected by the SDK (the main thread) via setWorkerUrlConfig — the single
348
- // source of truth for browser-vs-Node, replacing local detection.
349
- let _isBrowserLike = undefined;
350
- const _workerUrlSha256 = "2c2ef02437e5b7a41f4c5c1defa0a24dcfae737037a59a145a972bb4191571b8";
351
- let _verifiedWorkerUrlBytesPromise = undefined;
352
- let _logger = undefined;
353
- let _started = false;
354
- // True only while the body of startWorkers() is executing.
355
- // Reset by the try/finally in startWorkers, so a failed start still allows
356
- // terminateWorkers() to be called (and become a no-op when _workers is unset).
357
- let _starting = false;
358
-
359
- // Keep workers strongly referenced while they own shared WebAssembly memory.
360
- let _workers;
361
-
362
- function getTfheWorkers() {
363
- return _workers;
364
- }
365
-
366
- ////////////////////////////////////////////////////////////////////////////////
367
- // Configuration API
368
- ////////////////////////////////////////////////////////////////////////////////
369
-
370
- function __assertLogger(logger) {
371
- if (logger === undefined) {
372
- return;
373
- }
374
-
375
- if (typeof logger.debug !== 'function' || typeof logger.error !== 'function') {
376
- throw new TypeError('logger must expose debug(message) and error(message, cause) functions');
377
- }
378
- }
379
-
380
- function setWorkerUrlConfig(parameters = {}) {
381
- if (_configSet) {
382
- throw new Error('Cannot set worker URL config: config was already set');
383
- }
384
-
385
- if (_started) {
386
- throw new Error('Cannot set worker URL config after workers have started');
387
- }
388
-
389
- if (parameters === null || typeof parameters !== 'object') {
390
- throw new TypeError('setWorkerUrlConfig parameters must be an object');
391
- }
392
-
393
- const {
394
- workerUrl = undefined,
395
- wasmAssetLoadMode = 'auto',
396
- logger = undefined,
397
- isBrowserLike = undefined,
398
- } = parameters;
399
-
400
- // Check `isBrowserLike` (required: the SDK injects the resolved runtime kind;
401
- // the worker bootstrap never detects it itself).
402
- if (typeof isBrowserLike !== 'boolean') {
403
- throw new TypeError('setWorkerUrlConfig: isBrowserLike (boolean) is required');
404
- }
405
-
406
- // Check `wasmAssetLoadMode`
407
- if (!__isWasmAssetLoadMode(wasmAssetLoadMode)) {
408
- throw new TypeError(`wasmAssetLoadMode must be one of: ${__wasmAssetLoadModes.join(', ')}`);
409
- }
410
-
411
- // Check `workerUrl`
412
- if (workerUrl !== undefined) {
413
- if (!(workerUrl instanceof URL)) {
414
- throw new TypeError('workerUrl must be a URL');
415
- }
416
- _workerUrl = workerUrl;
417
- } else {
418
- if (
419
- wasmAssetLoadMode === 'verified-blob' ||
420
- wasmAssetLoadMode === 'precheck-direct-url' ||
421
- wasmAssetLoadMode === 'trusted-direct-url'
422
- ) {
423
- throw new Error(`workerUrl is required when wasmAssetLoadMode is "${wasmAssetLoadMode}"`);
424
- }
425
- }
426
-
427
- // Check `logger`
428
- __assertLogger(logger);
429
-
430
- _wasmAssetLoadMode = wasmAssetLoadMode;
431
- _logger = logger;
432
- _isBrowserLike = isBrowserLike;
433
- _configSet = true;
434
- }
435
-
436
- ////////////////////////////////////////////////////////////////////////////////
437
- // Worker source strategies
438
- ////////////////////////////////////////////////////////////////////////////////
439
-
440
- /**
441
- * Returns the cached verification promise for the configured worker URL.
442
- * The first call reads `_workerUrl` and verifies it against `_workerUrlSha256`; later calls reuse the same promise
443
- * so parallel workers do not refetch or rehash the script.
444
- * @returns {Promise<ArrayBuffer | Uint8Array>} Verified worker script bytes.
445
- * @throws {Error} If no worker URL is configured.
446
- */
447
- function __getVerifiedWorkerUrlBytesPromise() {
448
- const workerUrl = _workerUrl;
449
-
450
- if (workerUrl === undefined) {
451
- throw new Error('workerUrl is required to verify worker URL bytes');
452
- }
453
-
454
- if (_verifiedWorkerUrlBytesPromise !== undefined) {
455
- return _verifiedWorkerUrlBytesPromise;
456
- }
457
-
458
- _verifiedWorkerUrlBytesPromise = __fetchAndVerifyWorkerUrlBytes(workerUrl, _workerUrlSha256);
459
- return _verifiedWorkerUrlBytesPromise;
460
- }
461
-
462
- /**
463
- * Creates a worker from the configured URL after SHA-256 verification.
464
- * 1. Reuse cached verified bytes.
465
- * 2. Execute those exact bytes as a Blob worker in browsers.
466
- * 3. Execute those exact bytes as an eval worker in Node.
467
- * @returns {Promise<{ worker: Worker, blobUrl: string | undefined }>} Created worker and optional Blob URL to revoke.
468
- */
469
- async function __createWorkerFromVerifiedWorkerUrl() {
470
- const verifiedWorkerBytes = await __getVerifiedWorkerUrlBytesPromise();
471
- return await __newIsomorphicWorkerFromVerifiedJsCodeBytes(verifiedWorkerBytes);
472
- }
473
-
474
- /**
475
- * Creates a worker by passing the configured URL directly to the runtime.
476
- * 1. Require a configured worker URL.
477
- * 2. Do not perform SDK byte verification.
478
- * 3. Let the browser or Node runtime load and execute the URL directly.
479
- * @returns {Promise<{ worker: Worker, blobUrl: undefined }>} Created worker with no Blob URL to revoke.
480
- */
481
- async function __createWorkerFromTrustedDirectWorkerUrl() {
482
- if (_workerUrl === undefined) {
483
- throw new Error('workerUrl is required to create a trusted direct worker');
484
- }
485
-
486
- return { worker: await __newIsomorphicWorkerFromUrl(_workerUrl), blobUrl: undefined };
487
- }
488
-
489
- /**
490
- * Creates a worker by passing the configured URL directly to the runtime, after a pre-flight SHA-256 probe.
491
- *
492
- * IMPORTANT: this is NOT an integrity check. The SDK fetches the URL once to validate
493
- * the hash, then hands the URL to the runtime, which fetches it a SECOND time and
494
- * executes those bytes. The two fetches are independent — the executed bytes are
495
- * never verified. Use only for fail-fast on misconfigured URLs / build mismatches.
496
- *
497
- * For an actual integrity guarantee, use `verified-blob` (requires CSP allowing blob: workers).
498
- *
499
- * 1. Fetch the URL and verify its SHA-256 against "2c2ef02437e5b7a41f4c5c1defa0a24dcfae737037a59a145a972bb4191571b8" — fails fast on mismatch.
500
- * 2. Discard the verified bytes.
501
- * 3. Let the runtime fetch the same URL again and execute it (no verification on this fetch).
502
- * @returns {Promise<{ worker: Worker, blobUrl: undefined }>} Created worker with no Blob URL to revoke.
503
- */
504
- async function __createWorkerFromCheckedDirectWorkerUrl() {
505
- await __getVerifiedWorkerUrlBytesPromise();
506
- return await __createWorkerFromTrustedDirectWorkerUrl();
507
- }
508
-
509
- /**
510
- * Creates a worker from the SDK-embedded base64 worker source.
511
- * 1. Read the base64-encoded JavaScript source baked into this module.
512
- * 2. Decode into a Blob URL and create a module Worker in browsers.
513
- * 3. Decode into UTF-8 JavaScript and create a worker_threads eval Worker in Node.
514
- * @returns {Promise<{ worker: Worker, blobUrl: string | undefined }>} Created worker and optional Blob URL to revoke.
515
- */
516
- async function __createWorkerFromBase64() {
517
- const workerBase64 = "ZnVuY3Rpb24gX19faXNCcm93c2VyTGlrZSgpIHsKICByZXR1cm4gKAogICAgdHlwZW9mIGFkZEV2ZW50TGlzdGVuZXIgPT09ICdmdW5jdGlvbicgJiYKICAgIHR5cGVvZiByZW1vdmVFdmVudExpc3RlbmVyID09PSAnZnVuY3Rpb24nCiAgKTsKfQoKYXN5bmMgZnVuY3Rpb24gX19fZ2V0VGFyZ2V0KCkgewogIGlmIChfX19pc0Jyb3dzZXJMaWtlKCkpIHJldHVybiBzZWxmOwogIGNvbnN0IG5vZGVNb2R1bGVOYW1lID0gJ3dvcmtlcl90aHJlYWRzJzsKICBjb25zdCBub2RlTW9kdWxlSWQgPSBgbm9kZToke25vZGVNb2R1bGVOYW1lfWA7CiAgY29uc3QgeyBwYXJlbnRQb3J0IH0gPSBhd2FpdCBpbXBvcnQoLyogQHZpdGUtaWdub3JlICovIG5vZGVNb2R1bGVJZCk7CiAgcmV0dXJuIHBhcmVudFBvcnQ7Cn0KCmZ1bmN0aW9uIF9fX3dhaXRGb3JNc2dUeXBlKHRhcmdldCwgdHlwZSkgewogIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gewogICAgaWYgKHR5cGVvZiB0YXJnZXQub24gPT09ICdmdW5jdGlvbicpIHsKICAgICAgLy8gTm9kZTogRXZlbnRFbWl0dGVyLCBkYXRhIHBhc3NlZCBkaXJlY3RseQogICAgICB0YXJnZXQub24oJ21lc3NhZ2UnLCBmdW5jdGlvbiBvbk1zZyhkYXRhKSB7CiAgICAgICAgaWYgKGRhdGE/LnR5cGUgIT09IHR5cGUpIHJldHVybjsKICAgICAgICB0YXJnZXQub2ZmKCdtZXNzYWdlJywgb25Nc2cpOwogICAgICAgIHJlc29sdmUoZGF0YSk7CiAgICAgIH0pOwogICAgfSBlbHNlIHsKICAgICAgLy8gQnJvd3NlcjogRE9NIGV2ZW50cywgZGF0YSB3cmFwcGVkIGluIE1lc3NhZ2VFdmVudAogICAgICB0YXJnZXQuYWRkRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsIGZ1bmN0aW9uIG9uTXNnKHsgZGF0YSB9KSB7CiAgICAgICAgaWYgKGRhdGE/LnR5cGUgIT09IHR5cGUpIHJldHVybjsKICAgICAgICB0YXJnZXQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsIG9uTXNnKTsKICAgICAgICByZXNvbHZlKGRhdGEpOwogICAgICB9KTsKICAgIH0KICB9KTsKfQoKX19fZ2V0VGFyZ2V0KCkudGhlbigodGFyZ2V0KSA9PgogIF9fX3dhaXRGb3JNc2dUeXBlKHRhcmdldCwgJ3dhc21fYmluZGdlbl93b3JrZXJfaW5pdCcpLnRoZW4oCiAgICBhc3luYyAoeyBpbml0LCByZWNlaXZlciB9KSA9PiB7CiAgICAgIGNvbnN0IHBrZyA9IGF3YWl0IFByb21pc2UucmVzb2x2ZSgpLnRoZW4oZnVuY3Rpb24gKCkgewogICAgICAgIHJldHVybiB0ZmhlOwogICAgICB9KTsKICAgICAgYXdhaXQgcGtnLmRlZmF1bHQoaW5pdCk7CiAgICAgIHRhcmdldC5wb3N0TWVzc2FnZSh7IHR5cGU6ICd3YXNtX2JpbmRnZW5fd29ya2VyX3JlYWR5JyB9KTsKICAgICAgcGtnLndiZ19yYXlvbl9zdGFydF93b3JrZXIocmVjZWl2ZXIpOwogICAgfSwKICApLAopOwoKLyoqCiAqIEBwYXJhbSB7bnVtYmVyfSByZWNlaXZlcgogKi8KZnVuY3Rpb24gd2JnX3JheW9uX3N0YXJ0X3dvcmtlcihyZWNlaXZlcikgewogIHdhc20ud2JnX3JheW9uX3N0YXJ0X3dvcmtlcihyZWNlaXZlcik7Cn0KCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCi8vIEludGVybmFsIHdhc21iaW5kZ2VuIHRvb2xzCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCgovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwovLwovLyBJbXBvcnRzOgovLyBfX3diZ19nZXRfaW1wb3J0cwovLwovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwoKZnVuY3Rpb24gX193YmdfZ2V0X2ltcG9ydHMobWVtb3J5KSB7CiAgICBjb25zdCBpbXBvcnQwID0gewogICAgICAgIF9fcHJvdG9fXzogbnVsbCwKICAgICAgICBfX3diZ19CaWdJbnRfNTJmZjgzOTEyOTdkYTE5NDogZnVuY3Rpb24gKCkgewogICAgICAgICAgICByZXR1cm4gaGFuZGxlRXJyb3IoZnVuY3Rpb24gKGFyZzApIHsKICAgICAgICAgICAgICAgIGNvbnN0IHJldCA9IEJpZ0ludChhcmcwKTsKICAgICAgICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgICAgIH0sIGFyZ3VtZW50cyk7CiAgICAgICAgfSwKICAgICAgICBfX3diZ19CaWdJbnRfYWUyMDBlOTNjYWNiZDJiMzogZnVuY3Rpb24gKGFyZzApIHsKICAgICAgICAgICAgY29uc3QgcmV0ID0gQmlnSW50KGFyZzApOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgIH0sCiAgICAgICAgX193YmdfRXJyb3JfMzYzOWE2MGVkMTVmODdlNzogZnVuY3Rpb24gKGFyZzAsIGFyZzEpIHsKICAgICAgICAgICAgY29uc3QgcmV0ID0gRXJyb3IoZ2V0U3RyaW5nRnJvbVdhc20wKGFyZzAsIGFyZzEpKTsKICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICB9LAogICAgICAgIF9fd2JnX19fd2JpbmRnZW5fYmlnaW50X2dldF9hc19pNjRfM2FmNmQ0Y2E3NzE5M2E0YjogZnVuY3Rpb24gKGFyZzAsIGFyZzEpIHsKICAgICAgICAgICAgY29uc3QgdiA9IGFyZzE7CiAgICAgICAgICAgIGNvbnN0IHJldCA9IHR5cGVvZiAodikgPT09ICdiaWdpbnQnID8gdiA6IHVuZGVmaW5lZDsKICAgICAgICAgICAgZ2V0RGF0YVZpZXdNZW1vcnkwKCkuc2V0QmlnSW50NjQoYXJnMCArIDggKiAxLCBpc0xpa2VOb25lKHJldCkgPyBCaWdJbnQoMCkgOiByZXQsIHRydWUpOwogICAgICAgICAgICBnZXREYXRhVmlld01lbW9yeTAoKS5zZXRJbnQzMihhcmcwICsgNCAqIDAsICFpc0xpa2VOb25lKHJldCksIHRydWUpOwogICAgICAgIH0sCiAgICAgICAgX193YmdfX193YmluZGdlbl9iaXRfYW5kX2JmZWRlY2UyYmI2NTdmNGI6IGZ1bmN0aW9uIChhcmcwLCBhcmcxKSB7CiAgICAgICAgICAgIGNvbnN0IHJldCA9IGFyZzAgJiBhcmcxOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgIH0sCiAgICAgICAgX193YmdfX193YmluZGdlbl9kZWJ1Z19zdHJpbmdfMDdjYjcyY2ZjYzk1MmUyYjogZnVuY3Rpb24gKGFyZzAsIGFyZzEpIHsKICAgICAgICAgICAgY29uc3QgcmV0ID0gZGVidWdTdHJpbmcoYXJnMSk7CiAgICAgICAgICAgIGNvbnN0IHB0cjEgPSBwYXNzU3RyaW5nVG9XYXNtMChyZXQsIHdhc20uX193YmluZGdlbl9tYWxsb2MsIHdhc20uX193YmluZGdlbl9yZWFsbG9jKTsKICAgICAgICAgICAgY29uc3QgbGVuMSA9IFdBU01fVkVDVE9SX0xFTjsKICAgICAgICAgICAgZ2V0RGF0YVZpZXdNZW1vcnkwKCkuc2V0SW50MzIoYXJnMCArIDQgKiAxLCBsZW4xLCB0cnVlKTsKICAgICAgICAgICAgZ2V0RGF0YVZpZXdNZW1vcnkwKCkuc2V0SW50MzIoYXJnMCArIDQgKiAwLCBwdHIxLCB0cnVlKTsKICAgICAgICB9LAogICAgICAgIF9fd2JnX19fd2JpbmRnZW5faXNfZnVuY3Rpb25fMmYwZmQ3Y2ViODZlNjRjNTogZnVuY3Rpb24gKGFyZzApIHsKICAgICAgICAgICAgY29uc3QgcmV0ID0gdHlwZW9mIChhcmcwKSA9PT0gJ2Z1bmN0aW9uJzsKICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICB9LAogICAgICAgIF9fd2JnX19fd2JpbmRnZW5faXNfb2JqZWN0XzViMjJmZjI0MTgwNjNhOWM6IGZ1bmN0aW9uIChhcmcwKSB7CiAgICAgICAgICAgIGNvbnN0IHZhbCA9IGFyZzA7CiAgICAgICAgICAgIGNvbnN0IHJldCA9IHR5cGVvZiAodmFsKSA9PT0gJ29iamVjdCcgJiYgdmFsICE9PSBudWxsOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgIH0sCiAgICAgICAgX193YmdfX193YmluZGdlbl9pc19zdHJpbmdfZWRkYzA3YTNlZmFkNTJlNjogZnVuY3Rpb24gKGFyZzApIHsKICAgICAgICAgICAgY29uc3QgcmV0ID0gdHlwZW9mIChhcmcwKSA9PT0gJ3N0cmluZyc7CiAgICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfSwKICAgICAgICBfX3diZ19fX3diaW5kZ2VuX2lzX3VuZGVmaW5lZF8yNDRhOTJjMzRkM2I2ZWMwOiBmdW5jdGlvbiAoYXJnMCkgewogICAgICAgICAgICBjb25zdCByZXQgPSBhcmcwID09PSB1bmRlZmluZWQ7CiAgICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfSwKICAgICAgICBfX3diZ19fX3diaW5kZ2VuX2pzdmFsX2VxXzQwM2VhYTM2MTA1MDBhMjU6IGZ1bmN0aW9uIChhcmcwLCBhcmcxKSB7CiAgICAgICAgICAgIGNvbnN0IHJldCA9IGFyZzAgPT09IGFyZzE7CiAgICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfSwKICAgICAgICBfX3diZ19fX3diaW5kZ2VuX2x0X2M0ODNjYzY5NGRlNjdjM2U6IGZ1bmN0aW9uIChhcmcwLCBhcmcxKSB7CiAgICAgICAgICAgIGNvbnN0IHJldCA9IGFyZzAgPCBhcmcxOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgIH0sCiAgICAgICAgX193YmdfX193YmluZGdlbl9tZW1vcnlfYzIzNTZkZDFhMDg5ZGZiZDogZnVuY3Rpb24gKCkgewogICAgICAgICAgICBjb25zdCByZXQgPSB3YXNtLm1lbW9yeTsKICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICB9LAogICAgICAgIF9fd2JnX19fd2JpbmRnZW5fbW9kdWxlX2RmNzA0MzkzZGZkMTg1M2M6IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgY29uc3QgcmV0ID0gd2FzbU1vZHVsZTsKICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICB9LAogICAgICAgIF9fd2JnX19fd2JpbmRnZW5fbmVnXzliNGQ3MTgyM2UzYmM1MTM6IGZ1bmN0aW9uIChhcmcwKSB7CiAgICAgICAgICAgIGNvbnN0IHJldCA9IC1hcmcwOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgIH0sCiAgICAgICAgX193YmdfX193YmluZGdlbl9zaHJfZDhmODI2OGYxOGM3YTFjMzogZnVuY3Rpb24gKGFyZzAsIGFyZzEpIHsKICAgICAgICAgICAgY29uc3QgcmV0ID0gYXJnMCA+PiBhcmcxOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgIH0sCiAgICAgICAgX193YmdfX193YmluZGdlbl9zdHJpbmdfZ2V0Xzk2NTU5MjA3M2U1ZDg0OGM6IGZ1bmN0aW9uIChhcmcwLCBhcmcxKSB7CiAgICAgICAgICAgIGNvbnN0IG9iaiA9IGFyZzE7CiAgICAgICAgICAgIGNvbnN0IHJldCA9IHR5cGVvZiAob2JqKSA9PT0gJ3N0cmluZycgPyBvYmogOiB1bmRlZmluZWQ7CiAgICAgICAgICAgIHZhciBwdHIxID0gaXNMaWtlTm9uZShyZXQpID8gMCA6IHBhc3NTdHJpbmdUb1dhc20wKHJldCwgd2FzbS5fX3diaW5kZ2VuX21hbGxvYywgd2FzbS5fX3diaW5kZ2VuX3JlYWxsb2MpOwogICAgICAgICAgICB2YXIgbGVuMSA9IFdBU01fVkVDVE9SX0xFTjsKICAgICAgICAgICAgZ2V0RGF0YVZpZXdNZW1vcnkwKCkuc2V0SW50MzIoYXJnMCArIDQgKiAxLCBsZW4xLCB0cnVlKTsKICAgICAgICAgICAgZ2V0RGF0YVZpZXdNZW1vcnkwKCkuc2V0SW50MzIoYXJnMCArIDQgKiAwLCBwdHIxLCB0cnVlKTsKICAgICAgICB9LAogICAgICAgIF9fd2JnX19fd2JpbmRnZW5fdGhyb3dfOWM3NWQ0N2JmOWU3NzMxZTogZnVuY3Rpb24gKGFyZzAsIGFyZzEpIHsKICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGdldFN0cmluZ0Zyb21XYXNtMChhcmcwLCBhcmcxKSk7CiAgICAgICAgfSwKICAgICAgICBfX3diZ19jYWxsX2E0MWQ2NDIxYjMwYTMyYzU6IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgcmV0dXJuIGhhbmRsZUVycm9yKGZ1bmN0aW9uIChhcmcwLCBhcmcxLCBhcmcyKSB7CiAgICAgICAgICAgICAgICBjb25zdCByZXQgPSBhcmcwLmNhbGwoYXJnMSwgYXJnMik7CiAgICAgICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgICAgICB9LCBhcmd1bWVudHMpOwogICAgICAgIH0sCiAgICAgICAgX193YmdfY3J5cHRvXzM4ZGYyYmFiMTI2YjYzZGM6IGZ1bmN0aW9uIChhcmcwKSB7CiAgICAgICAgICAgIGNvbnN0IHJldCA9IGFyZzAuY3J5cHRvOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgIH0sCiAgICAgICAgX193YmdfZXJyb3JfYTZmYTIwMmI1OGFhMWNkMzogZnVuY3Rpb24gKGFyZzAsIGFyZzEpIHsKICAgICAgICAgICAgbGV0IGRlZmVycmVkMF8wOwogICAgICAgICAgICBsZXQgZGVmZXJyZWQwXzE7CiAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICBkZWZlcnJlZDBfMCA9IGFyZzA7CiAgICAgICAgICAgICAgICBkZWZlcnJlZDBfMSA9IGFyZzE7CiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGdldFN0cmluZ0Zyb21XYXNtMChhcmcwLCBhcmcxKSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZmluYWxseSB7CiAgICAgICAgICAgICAgICB3YXNtLl9fd2JpbmRnZW5fZnJlZShkZWZlcnJlZDBfMCwgZGVmZXJyZWQwXzEsIDEpOwogICAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICBfX3diZ19nZXRSYW5kb21WYWx1ZXNfYzQ0YTUwZDhjZmRhZWJlYjogZnVuY3Rpb24gKCkgewogICAgICAgICAgICByZXR1cm4gaGFuZGxlRXJyb3IoZnVuY3Rpb24gKGFyZzAsIGFyZzEpIHsKICAgICAgICAgICAgICAgIGFyZzAuZ2V0UmFuZG9tVmFsdWVzKGFyZzEpOwogICAgICAgICAgICB9LCBhcmd1bWVudHMpOwogICAgICAgIH0sCiAgICAgICAgX193YmdfaW5zdGFuY2VvZl9XaW5kb3dfNDE1M2MxODE4YTFjMGMwYjogZnVuY3Rpb24gKGFyZzApIHsKICAgICAgICAgICAgbGV0IHJlc3VsdDsKICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICAgIHJlc3VsdCA9IGFyZzAgaW5zdGFuY2VvZiBXaW5kb3c7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgY2F0Y2ggKF8pIHsKICAgICAgICAgICAgICAgIHJlc3VsdCA9IGZhbHNlOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGNvbnN0IHJldCA9IHJlc3VsdDsKICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICB9LAogICAgICAgIF9fd2JnX2xlbmd0aF9iYTNjMDMyNjAyZWZlMzEwOiBmdW5jdGlvbiAoYXJnMCkgewogICAgICAgICAgICBjb25zdCByZXQgPSBhcmcwLmxlbmd0aDsKICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICB9LAogICAgICAgIF9fd2JnX21zQ3J5cHRvX2JkNWEwMzRhZjk2YmNiYTY6IGZ1bmN0aW9uIChhcmcwKSB7CiAgICAgICAgICAgIGNvbnN0IHJldCA9IGFyZzAubXNDcnlwdG87CiAgICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfSwKICAgICAgICBfX3diZ19uZXdfMjI3ZDdjMDU0MTRlYjg2MTogZnVuY3Rpb24gKCkgewogICAgICAgICAgICBjb25zdCByZXQgPSBuZXcgRXJyb3IoKTsKICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICB9LAogICAgICAgIF9fd2JnX25ld193aXRoX2xlbmd0aF85MDExZjVkYTc5NGJmNWQ5OiBmdW5jdGlvbiAoYXJnMCkgewogICAgICAgICAgICBjb25zdCByZXQgPSBuZXcgVWludDhBcnJheShhcmcwID4+PiAwKTsKICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICB9LAogICAgICAgIF9fd2JnX25vZGVfODRlYTg3NTQxMTI1NGRiMTogZnVuY3Rpb24gKGFyZzApIHsKICAgICAgICAgICAgY29uc3QgcmV0ID0gYXJnMC5ub2RlOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgIH0sCiAgICAgICAgX193YmdfcHJvY2Vzc180NGM3YTE0ZTExZTlmNjllOiBmdW5jdGlvbiAoYXJnMCkgewogICAgICAgICAgICBjb25zdCByZXQgPSBhcmcwLnByb2Nlc3M7CiAgICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfSwKICAgICAgICBfX3diZ19wcm90b3R5cGVzZXRjYWxsX2ZkNDA1MGU4MDZlMWQ1MTk6IGZ1bmN0aW9uIChhcmcwLCBhcmcxLCBhcmcyKSB7CiAgICAgICAgICAgIFVpbnQ4QXJyYXkucHJvdG90eXBlLnNldC5jYWxsKGdldEFycmF5VThGcm9tV2FzbTAoYXJnMCwgYXJnMSksIGFyZzIpOwogICAgICAgIH0sCiAgICAgICAgX193YmdfcmFuZG9tRmlsbFN5bmNfNmMyNWVhYzk4NjllYjUzYzogZnVuY3Rpb24gKCkgewogICAgICAgICAgICByZXR1cm4gaGFuZGxlRXJyb3IoZnVuY3Rpb24gKGFyZzAsIGFyZzEpIHsKICAgICAgICAgICAgICAgIGFyZzAucmFuZG9tRmlsbFN5bmMoYXJnMSk7CiAgICAgICAgICAgIH0sIGFyZ3VtZW50cyk7CiAgICAgICAgfSwKICAgICAgICBfX3diZ19yZXF1aXJlX2I0ZWRiZGNmM2UyYTFlZjA6IGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgcmV0dXJuIGhhbmRsZUVycm9yKGZ1bmN0aW9uICgpIHsKICAgICAgICAgICAgICAgIGNvbnN0IHJldCA9IG1vZHVsZS5yZXF1aXJlOwogICAgICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICAgICAgfSwgYXJndW1lbnRzKTsKICAgICAgICB9LAogICAgICAgIF9fd2JnX3N0YWNrXzNiMGQ5NzRiYmYzMWU0NGY6IGZ1bmN0aW9uIChhcmcwLCBhcmcxKSB7CiAgICAgICAgICAgIGNvbnN0IHJldCA9IGFyZzEuc3RhY2s7CiAgICAgICAgICAgIGNvbnN0IHB0cjEgPSBwYXNzU3RyaW5nVG9XYXNtMChyZXQsIHdhc20uX193YmluZGdlbl9tYWxsb2MsIHdhc20uX193YmluZGdlbl9yZWFsbG9jKTsKICAgICAgICAgICAgY29uc3QgbGVuMSA9IFdBU01fVkVDVE9SX0xFTjsKICAgICAgICAgICAgZ2V0RGF0YVZpZXdNZW1vcnkwKCkuc2V0SW50MzIoYXJnMCArIDQgKiAxLCBsZW4xLCB0cnVlKTsKICAgICAgICAgICAgZ2V0RGF0YVZpZXdNZW1vcnkwKCkuc2V0SW50MzIoYXJnMCArIDQgKiAwLCBwdHIxLCB0cnVlKTsKICAgICAgICB9LAogICAgICAgIF9fd2JnX3N0YXJ0V29ya2Vyc184YjU4MmQ1N2U5MmJkMmQ0OiBmdW5jdGlvbiAoYXJnMCwgYXJnMSwgYXJnMikgewogICAgICAgICAgICBoYW5kbGVFcnJvcihmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3N0YXJ0V29ya2VycyBub3Qgc3VwcG9ydGVkIGZyb20gYSB3b3JrZXIgdGhyZWFkJyk7CiAgICAgICAgICAgIH0pOwogICAgICAgICAgICAvLyBjb25zdCByZXQgPSBzdGFydFdvcmtlcnMoYXJnMCwgYXJnMSwgd2JnX3JheW9uX1Bvb2xCdWlsZGVyLl9fd3JhcChhcmcyKSk7CiAgICAgICAgICAgIC8vIHJldHVybiByZXQ7CiAgICAgICAgfSwKICAgICAgICBfX3diZ19zdGF0aWNfYWNjZXNzb3JfR0xPQkFMX1RISVNfMWM3ZjFiZDZjNjk0MWZkYjogZnVuY3Rpb24gKCkgewogICAgICAgICAgICBjb25zdCByZXQgPSB0eXBlb2YgZ2xvYmFsVGhpcyA9PT0gJ3VuZGVmaW5lZCcgPyBudWxsIDogZ2xvYmFsVGhpczsKICAgICAgICAgICAgcmV0dXJuIGlzTGlrZU5vbmUocmV0KSA/IDAgOiBhZGRUb0V4dGVybnJlZlRhYmxlMChyZXQpOwogICAgICAgIH0sCiAgICAgICAgX193Ymdfc3RhdGljX2FjY2Vzc29yX0dMT0JBTF9lMDM5YmM5MTRmODNlNzRlOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgIGNvbnN0IHJldCA9IHR5cGVvZiBnbG9iYWwgPT09ICd1bmRlZmluZWQnID8gbnVsbCA6IGdsb2JhbDsKICAgICAgICAgICAgcmV0dXJuIGlzTGlrZU5vbmUocmV0KSA/IDAgOiBhZGRUb0V4dGVybnJlZlRhYmxlMChyZXQpOwogICAgICAgIH0sCiAgICAgICAgX193Ymdfc3RhdGljX2FjY2Vzc29yX1NFTEZfOGJmOGM0OGMyODQyMGFkNTogZnVuY3Rpb24gKCkgewogICAgICAgICAgICBjb25zdCByZXQgPSB0eXBlb2Ygc2VsZiA9PT0gJ3VuZGVmaW5lZCcgPyBudWxsIDogc2VsZjsKICAgICAgICAgICAgcmV0dXJuIGlzTGlrZU5vbmUocmV0KSA/IDAgOiBhZGRUb0V4dGVybnJlZlRhYmxlMChyZXQpOwogICAgICAgIH0sCiAgICAgICAgX193Ymdfc3RhdGljX2FjY2Vzc29yX1dJTkRPV182YWVlZTliNTE2NTJlZTBmOiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgIGNvbnN0IHJldCA9IHR5cGVvZiB3aW5kb3cgPT09ICd1bmRlZmluZWQnID8gbnVsbCA6IHdpbmRvdzsKICAgICAgICAgICAgcmV0dXJuIGlzTGlrZU5vbmUocmV0KSA/IDAgOiBhZGRUb0V4dGVybnJlZlRhYmxlMChyZXQpOwogICAgICAgIH0sCiAgICAgICAgX193Ymdfc3ViYXJyYXlfZmJlM2NlZjI5MGUxZmE0MzogZnVuY3Rpb24gKGFyZzAsIGFyZzEsIGFyZzIpIHsKICAgICAgICAgICAgY29uc3QgcmV0ID0gYXJnMC5zdWJhcnJheShhcmcxID4+PiAwLCBhcmcyID4+PiAwKTsKICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICB9LAogICAgICAgIF9fd2JnX3RvU3RyaW5nXzE1NjU2YWY4ZDhlNzFmMTY6IGZ1bmN0aW9uIChhcmcwLCBhcmcxLCBhcmcyKSB7CiAgICAgICAgICAgIGNvbnN0IHJldCA9IGFyZzEudG9TdHJpbmcoYXJnMik7CiAgICAgICAgICAgIGNvbnN0IHB0cjEgPSBwYXNzU3RyaW5nVG9XYXNtMChyZXQsIHdhc20uX193YmluZGdlbl9tYWxsb2MsIHdhc20uX193YmluZGdlbl9yZWFsbG9jKTsKICAgICAgICAgICAgY29uc3QgbGVuMSA9IFdBU01fVkVDVE9SX0xFTjsKICAgICAgICAgICAgZ2V0RGF0YVZpZXdNZW1vcnkwKCkuc2V0SW50MzIoYXJnMCArIDQgKiAxLCBsZW4xLCB0cnVlKTsKICAgICAgICAgICAgZ2V0RGF0YVZpZXdNZW1vcnkwKCkuc2V0SW50MzIoYXJnMCArIDQgKiAwLCBwdHIxLCB0cnVlKTsKICAgICAgICB9LAogICAgICAgIF9fd2JnX3RvU3RyaW5nXzhkODc0NDg5YmFkN2U1YTI6IGZ1bmN0aW9uIChhcmcwKSB7CiAgICAgICAgICAgIGNvbnN0IHJldCA9IGFyZzAudG9TdHJpbmcoKTsKICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICB9LAogICAgICAgIF9fd2JnX3ZlcnNpb25zXzI3NmIyNzk1YjFjNmEyMTk6IGZ1bmN0aW9uIChhcmcwKSB7CiAgICAgICAgICAgIGNvbnN0IHJldCA9IGFyZzAudmVyc2lvbnM7CiAgICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfSwKICAgICAgICBfX3diaW5kZ2VuX2Nhc3RfMDAwMDAwMDAwMDAwMDAwMTogZnVuY3Rpb24gKGFyZzApIHsKICAgICAgICAgICAgLy8gQ2FzdCBpbnRyaW5zaWMgZm9yIGBGNjQgLT4gRXh0ZXJucmVmYC4KICAgICAgICAgICAgY29uc3QgcmV0ID0gYXJnMDsKICAgICAgICAgICAgcmV0dXJuIHJldDsKICAgICAgICB9LAogICAgICAgIF9fd2JpbmRnZW5fY2FzdF8wMDAwMDAwMDAwMDAwMDAyOiBmdW5jdGlvbiAoYXJnMCkgewogICAgICAgICAgICAvLyBDYXN0IGludHJpbnNpYyBmb3IgYEk2NCAtPiBFeHRlcm5yZWZgLgogICAgICAgICAgICBjb25zdCByZXQgPSBhcmcwOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgIH0sCiAgICAgICAgX193YmluZGdlbl9jYXN0XzAwMDAwMDAwMDAwMDAwMDM6IGZ1bmN0aW9uIChhcmcwLCBhcmcxKSB7CiAgICAgICAgICAgIC8vIENhc3QgaW50cmluc2ljIGZvciBgUmVmKFNsaWNlKFU4KSkgLT4gTmFtZWRFeHRlcm5yZWYoIlVpbnQ4QXJyYXkiKWAuCiAgICAgICAgICAgIGNvbnN0IHJldCA9IGdldEFycmF5VThGcm9tV2FzbTAoYXJnMCwgYXJnMSk7CiAgICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfSwKICAgICAgICBfX3diaW5kZ2VuX2Nhc3RfMDAwMDAwMDAwMDAwMDAwNDogZnVuY3Rpb24gKGFyZzAsIGFyZzEpIHsKICAgICAgICAgICAgLy8gQ2FzdCBpbnRyaW5zaWMgZm9yIGBSZWYoU3RyaW5nKSAtPiBFeHRlcm5yZWZgLgogICAgICAgICAgICBjb25zdCByZXQgPSBnZXRTdHJpbmdGcm9tV2FzbTAoYXJnMCwgYXJnMSk7CiAgICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgfSwKICAgICAgICBfX3diaW5kZ2VuX2Nhc3RfMDAwMDAwMDAwMDAwMDAwNTogZnVuY3Rpb24gKGFyZzApIHsKICAgICAgICAgICAgLy8gQ2FzdCBpbnRyaW5zaWMgZm9yIGBVNjQgLT4gRXh0ZXJucmVmYC4KICAgICAgICAgICAgY29uc3QgcmV0ID0gQmlnSW50LmFzVWludE4oNjQsIGFyZzApOwogICAgICAgICAgICByZXR1cm4gcmV0OwogICAgICAgIH0sCiAgICAgICAgX193YmluZGdlbl9pbml0X2V4dGVybnJlZl90YWJsZTogZnVuY3Rpb24gKCkgewogICAgICAgICAgICBjb25zdCB0YWJsZSA9IHdhc20uX193YmluZGdlbl9leHRlcm5yZWZzOwogICAgICAgICAgICBjb25zdCBvZmZzZXQgPSB0YWJsZS5ncm93KDQpOwogICAgICAgICAgICB0YWJsZS5zZXQoMCwgdW5kZWZpbmVkKTsKICAgICAgICAgICAgdGFibGUuc2V0KG9mZnNldCArIDAsIHVuZGVmaW5lZCk7CiAgICAgICAgICAgIHRhYmxlLnNldChvZmZzZXQgKyAxLCBudWxsKTsKICAgICAgICAgICAgdGFibGUuc2V0KG9mZnNldCArIDIsIHRydWUpOwogICAgICAgICAgICB0YWJsZS5zZXQob2Zmc2V0ICsgMywgZmFsc2UpOwogICAgICAgIH0sCiAgICAgICAgbWVtb3J5OiBtZW1vcnkgfHwgbmV3IFdlYkFzc2VtYmx5Lk1lbW9yeSh7IGluaXRpYWw6IDE5LCBtYXhpbXVtOiAxNjM4NCwgc2hhcmVkOiB0cnVlIH0pLAogICAgfTsKICAgIHJldHVybiB7CiAgICAgICAgX19wcm90b19fOiBudWxsLAogICAgICAgICIuL3RmaGVfYmcuanMiOiBpbXBvcnQwLAogICAgfTsKfQoKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KLy8gYWRkVG9FeHRlcm5yZWZUYWJsZTAKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KCmZ1bmN0aW9uIGFkZFRvRXh0ZXJucmVmVGFibGUwKG9iaikgewogICAgY29uc3QgaWR4ID0gd2FzbS5fX2V4dGVybnJlZl90YWJsZV9hbGxvYygpOwogICAgd2FzbS5fX3diaW5kZ2VuX2V4dGVybnJlZnMuc2V0KGlkeCwgb2JqKTsKICAgIHJldHVybiBpZHg7Cn0KCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCi8vIGRlYnVnU3RyaW5nCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCgpmdW5jdGlvbiBkZWJ1Z1N0cmluZyh2YWwpIHsKICAgIC8vIHByaW1pdGl2ZSB0eXBlcwogICAgY29uc3QgdHlwZSA9IHR5cGVvZiB2YWw7CiAgICBpZiAodHlwZSA9PSAnbnVtYmVyJyB8fCB0eXBlID09ICdib29sZWFuJyB8fCB2YWwgPT0gbnVsbCkgewogICAgICAgIHJldHVybiBgJHt2YWx9YDsKICAgIH0KICAgIGlmICh0eXBlID09ICdzdHJpbmcnKSB7CiAgICAgICAgcmV0dXJuIGAiJHt2YWx9ImA7CiAgICB9CiAgICBpZiAodHlwZSA9PSAnc3ltYm9sJykgewogICAgICAgIGNvbnN0IGRlc2NyaXB0aW9uID0gdmFsLmRlc2NyaXB0aW9uOwogICAgICAgIGlmIChkZXNjcmlwdGlvbiA9PSBudWxsKSB7CiAgICAgICAgICAgIHJldHVybiAnU3ltYm9sJzsKICAgICAgICB9CiAgICAgICAgZWxzZSB7CiAgICAgICAgICAgIHJldHVybiBgU3ltYm9sKCR7ZGVzY3JpcHRpb259KWA7CiAgICAgICAgfQogICAgfQogICAgaWYgKHR5cGUgPT0gJ2Z1bmN0aW9uJykgewogICAgICAgIGNvbnN0IG5hbWUgPSB2YWwubmFtZTsKICAgICAgICBpZiAodHlwZW9mIG5hbWUgPT0gJ3N0cmluZycgJiYgbmFtZS5sZW5ndGggPiAwKSB7CiAgICAgICAgICAgIHJldHVybiBgRnVuY3Rpb24oJHtuYW1lfSlgOwogICAgICAgIH0KICAgICAgICBlbHNlIHsKICAgICAgICAgICAgcmV0dXJuICdGdW5jdGlvbic7CiAgICAgICAgfQogICAgfQogICAgLy8gb2JqZWN0cwogICAgaWYgKEFycmF5LmlzQXJyYXkodmFsKSkgewogICAgICAgIGNvbnN0IGxlbmd0aCA9IHZhbC5sZW5ndGg7CiAgICAgICAgbGV0IGRlYnVnID0gJ1snOwogICAgICAgIGlmIChsZW5ndGggPiAwKSB7CiAgICAgICAgICAgIGRlYnVnICs9IGRlYnVnU3RyaW5nKHZhbFswXSk7CiAgICAgICAgfQogICAgICAgIGZvciAobGV0IGkgPSAxOyBpIDwgbGVuZ3RoOyBpKyspIHsKICAgICAgICAgICAgZGVidWcgKz0gJywgJyArIGRlYnVnU3RyaW5nKHZhbFtpXSk7CiAgICAgICAgfQogICAgICAgIGRlYnVnICs9ICddJzsKICAgICAgICByZXR1cm4gZGVidWc7CiAgICB9CiAgICAvLyBUZXN0IGZvciBidWlsdC1pbgogICAgY29uc3QgYnVpbHRJbk1hdGNoZXMgPSAvXFtvYmplY3QgKFteXF1dKylcXS8uZXhlYyh0b1N0cmluZy5jYWxsKHZhbCkpOwogICAgbGV0IGNsYXNzTmFtZTsKICAgIGlmIChidWlsdEluTWF0Y2hlcyAmJiBidWlsdEluTWF0Y2hlcy5sZW5ndGggPiAxKSB7CiAgICAgICAgY2xhc3NOYW1lID0gYnVpbHRJbk1hdGNoZXNbMV07CiAgICB9CiAgICBlbHNlIHsKICAgICAgICAvLyBGYWlsZWQgdG8gbWF0Y2ggdGhlIHN0YW5kYXJkICdbb2JqZWN0IENsYXNzTmFtZV0nCiAgICAgICAgcmV0dXJuIHRvU3RyaW5nLmNhbGwodmFsKTsKICAgIH0KICAgIGlmIChjbGFzc05hbWUgPT0gJ09iamVjdCcpIHsKICAgICAgICAvLyB3ZSdyZSBhIHVzZXIgZGVmaW5lZCBjbGFzcyBvciBPYmplY3QKICAgICAgICAvLyBKU09OLnN0cmluZ2lmeSBhdm9pZHMgcHJvYmxlbXMgd2l0aCBjeWNsZXMsIGFuZCBpcyBnZW5lcmFsbHkgbXVjaAogICAgICAgIC8vIGVhc2llciB0aGFuIGxvb3BpbmcgdGhyb3VnaCBvd25Qcm9wZXJ0aWVzIG9mIGB2YWxgLgogICAgICAgIHRyeSB7CiAgICAgICAgICAgIHJldHVybiAnT2JqZWN0KCcgKyBKU09OLnN0cmluZ2lmeSh2YWwpICsgJyknOwogICAgICAgIH0KICAgICAgICBjYXRjaCAoXykgewogICAgICAgICAgICByZXR1cm4gJ09iamVjdCc7CiAgICAgICAgfQogICAgfQogICAgLy8gZXJyb3JzCiAgICBpZiAodmFsIGluc3RhbmNlb2YgRXJyb3IpIHsKICAgICAgICByZXR1cm4gYCR7dmFsLm5hbWV9OiAke3ZhbC5tZXNzYWdlfVxuJHt2YWwuc3RhY2t9YDsKICAgIH0KICAgIC8vIFRPRE8gd2UgY291bGQgdGVzdCBmb3IgbW9yZSB0aGluZ3MgaGVyZSwgbGlrZSBgU2V0YHMgYW5kIGBNYXBgcy4KICAgIHJldHVybiBjbGFzc05hbWU7Cn0KCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCi8vIGdldEFycmF5VThGcm9tV2FzbTAKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KCmZ1bmN0aW9uIGdldEFycmF5VThGcm9tV2FzbTAocHRyLCBsZW4pIHsKICAgIHB0ciA9IHB0ciA+Pj4gMDsKICAgIHJldHVybiBnZXRVaW50OEFycmF5TWVtb3J5MCgpLnN1YmFycmF5KHB0ciAvIDEsIHB0ciAvIDEgKyBsZW4pOwp9CgovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwovLyBjYWNoZWREYXRhVmlld01lbW9yeTAKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KCmxldCBjYWNoZWREYXRhVmlld01lbW9yeTAgPSBudWxsOwoKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KLy8gZ2V0RGF0YVZpZXdNZW1vcnkwCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCgpmdW5jdGlvbiBnZXREYXRhVmlld01lbW9yeTAoKSB7CiAgICBpZiAoY2FjaGVkRGF0YVZpZXdNZW1vcnkwID09PSBudWxsIHx8IGNhY2hlZERhdGFWaWV3TWVtb3J5MC5idWZmZXIgIT09IHdhc20ubWVtb3J5LmJ1ZmZlcikgewogICAgICAgIGNhY2hlZERhdGFWaWV3TWVtb3J5MCA9IG5ldyBEYXRhVmlldyh3YXNtLm1lbW9yeS5idWZmZXIpOwogICAgfQogICAgcmV0dXJuIGNhY2hlZERhdGFWaWV3TWVtb3J5MDsKfQoKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KLy8gZ2V0U3RyaW5nRnJvbVdhc20wCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCgpmdW5jdGlvbiBnZXRTdHJpbmdGcm9tV2FzbTAocHRyLCBsZW4pIHsKICAgIHJldHVybiBkZWNvZGVUZXh0KHB0ciA+Pj4gMCwgbGVuKTsKfQoKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KLy8gY2FjaGVkVWludDhBcnJheU1lbW9yeTAKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KCmxldCBjYWNoZWRVaW50OEFycmF5TWVtb3J5MCA9IG51bGw7CgovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwovLyBnZXRVaW50OEFycmF5TWVtb3J5MAovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwoKZnVuY3Rpb24gZ2V0VWludDhBcnJheU1lbW9yeTAoKSB7CiAgICBpZiAoY2FjaGVkVWludDhBcnJheU1lbW9yeTAgPT09IG51bGwgfHwgY2FjaGVkVWludDhBcnJheU1lbW9yeTAuYnVmZmVyICE9PSB3YXNtLm1lbW9yeS5idWZmZXIpIHsKICAgICAgICBjYWNoZWRVaW50OEFycmF5TWVtb3J5MCA9IG5ldyBVaW50OEFycmF5KHdhc20ubWVtb3J5LmJ1ZmZlcik7CiAgICB9CiAgICByZXR1cm4gY2FjaGVkVWludDhBcnJheU1lbW9yeTA7Cn0KCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCi8vIGhhbmRsZUVycm9yCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCgpmdW5jdGlvbiBoYW5kbGVFcnJvcihmLCBhcmdzKSB7CiAgICB0cnkgewogICAgICAgIHJldHVybiBmLmFwcGx5KHRoaXMsIGFyZ3MpOwogICAgfQogICAgY2F0Y2ggKGUpIHsKICAgICAgICBjb25zdCBpZHggPSBhZGRUb0V4dGVybnJlZlRhYmxlMChlKTsKICAgICAgICB3YXNtLl9fd2JpbmRnZW5fZXhuX3N0b3JlKGlkeCk7CiAgICB9Cn0KCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCi8vIGlzTGlrZU5vbmUKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KCmZ1bmN0aW9uIGlzTGlrZU5vbmUoeCkgewogICAgcmV0dXJuIHggPT09IHVuZGVmaW5lZCB8fCB4ID09PSBudWxsOwp9CgovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwovLyBwYXNzU3RyaW5nVG9XYXNtMAovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwoKZnVuY3Rpb24gcGFzc1N0cmluZ1RvV2FzbTAoYXJnLCBtYWxsb2MsIHJlYWxsb2MpIHsKICAgIGlmIChyZWFsbG9jID09PSB1bmRlZmluZWQpIHsKICAgICAgICBjb25zdCBidWYgPSBjYWNoZWRUZXh0RW5jb2Rlci5lbmNvZGUoYXJnKTsKICAgICAgICBjb25zdCBwdHIgPSBtYWxsb2MoYnVmLmxlbmd0aCwgMSkgPj4+IDA7CiAgICAgICAgZ2V0VWludDhBcnJheU1lbW9yeTAoKS5zdWJhcnJheShwdHIsIHB0ciArIGJ1Zi5sZW5ndGgpLnNldChidWYpOwogICAgICAgIFdBU01fVkVDVE9SX0xFTiA9IGJ1Zi5sZW5ndGg7CiAgICAgICAgcmV0dXJuIHB0cjsKICAgIH0KICAgIGxldCBsZW4gPSBhcmcubGVuZ3RoOwogICAgbGV0IHB0ciA9IG1hbGxvYyhsZW4sIDEpID4+PiAwOwogICAgY29uc3QgbWVtID0gZ2V0VWludDhBcnJheU1lbW9yeTAoKTsKICAgIGxldCBvZmZzZXQgPSAwOwogICAgZm9yICg7IG9mZnNldCA8IGxlbjsgb2Zmc2V0KyspIHsKICAgICAgICBjb25zdCBjb2RlID0gYXJnLmNoYXJDb2RlQXQob2Zmc2V0KTsKICAgICAgICBpZiAoY29kZSA+IDB4N0YpCiAgICAgICAgICAgIGJyZWFrOwogICAgICAgIG1lbVtwdHIgKyBvZmZzZXRdID0gY29kZTsKICAgIH0KICAgIGlmIChvZmZzZXQgIT09IGxlbikgewogICAgICAgIGlmIChvZmZzZXQgIT09IDApIHsKICAgICAgICAgICAgYXJnID0gYXJnLnNsaWNlKG9mZnNldCk7CiAgICAgICAgfQogICAgICAgIHB0ciA9IHJlYWxsb2MocHRyLCBsZW4sIGxlbiA9IG9mZnNldCArIGFyZy5sZW5ndGggKiAzLCAxKSA+Pj4gMDsKICAgICAgICBjb25zdCB2aWV3ID0gZ2V0VWludDhBcnJheU1lbW9yeTAoKS5zdWJhcnJheShwdHIgKyBvZmZzZXQsIHB0ciArIGxlbik7CiAgICAgICAgY29uc3QgcmV0ID0gY2FjaGVkVGV4dEVuY29kZXIuZW5jb2RlSW50byhhcmcsIHZpZXcpOwogICAgICAgIG9mZnNldCArPSByZXQud3JpdHRlbjsKICAgICAgICBwdHIgPSByZWFsbG9jKHB0ciwgbGVuLCBvZmZzZXQsIDEpID4+PiAwOwogICAgfQogICAgV0FTTV9WRUNUT1JfTEVOID0gb2Zmc2V0OwogICAgcmV0dXJuIHB0cjsKfQoKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KLy8gY2FjaGVkVGV4dERlY29kZXIKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KCmxldCBjYWNoZWRUZXh0RGVjb2RlciA9ICh0eXBlb2YgVGV4dERlY29kZXIgIT09ICd1bmRlZmluZWQnID8gbmV3IFRleHREZWNvZGVyKCd1dGYtOCcsIHsgaWdub3JlQk9NOiB0cnVlLCBmYXRhbDogdHJ1ZSB9KSA6IHVuZGVmaW5lZCk7CgppZiAoY2FjaGVkVGV4dERlY29kZXIpCiAgICBjYWNoZWRUZXh0RGVjb2Rlci5kZWNvZGUoKTsKCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCi8vIE1BWF9TQUZBUklfREVDT0RFX0JZVEVTCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCgpjb25zdCBNQVhfU0FGQVJJX0RFQ09ERV9CWVRFUyA9IDIxNDY0MzUwNzI7CgovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwovLyBudW1CeXRlc0RlY29kZWQKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KCmxldCBudW1CeXRlc0RlY29kZWQgPSAwOwoKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KLy8gZGVjb2RlVGV4dAovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwoKZnVuY3Rpb24gZGVjb2RlVGV4dChwdHIsIGxlbikgewogICAgbnVtQnl0ZXNEZWNvZGVkICs9IGxlbjsKICAgIGlmIChudW1CeXRlc0RlY29kZWQgPj0gTUFYX1NBRkFSSV9ERUNPREVfQllURVMpIHsKICAgICAgICBjYWNoZWRUZXh0RGVjb2RlciA9IG5ldyBUZXh0RGVjb2RlcigndXRmLTgnLCB7IGlnbm9yZUJPTTogdHJ1ZSwgZmF0YWw6IHRydWUgfSk7CiAgICAgICAgY2FjaGVkVGV4dERlY29kZXIuZGVjb2RlKCk7CiAgICAgICAgbnVtQnl0ZXNEZWNvZGVkID0gbGVuOwogICAgfQogICAgcmV0dXJuIGNhY2hlZFRleHREZWNvZGVyLmRlY29kZShnZXRVaW50OEFycmF5TWVtb3J5MCgpLnNsaWNlKHB0ciwgcHRyICsgbGVuKSk7Cn0KCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCi8vIGNhY2hlZFRleHRFbmNvZGVyCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCgpjb25zdCBjYWNoZWRUZXh0RW5jb2RlciA9ICh0eXBlb2YgVGV4dEVuY29kZXIgIT09ICd1bmRlZmluZWQnID8gbmV3IFRleHRFbmNvZGVyKCkgOiB1bmRlZmluZWQpOwoKaWYgKGNhY2hlZFRleHRFbmNvZGVyKSB7CiAgICBjYWNoZWRUZXh0RW5jb2Rlci5lbmNvZGVJbnRvID0gZnVuY3Rpb24gKGFyZywgdmlldykgewogICAgICAgIGNvbnN0IGJ1ZiA9IGNhY2hlZFRleHRFbmNvZGVyLmVuY29kZShhcmcpOwogICAgICAgIHZpZXcuc2V0KGJ1Zik7CiAgICAgICAgcmV0dXJuIHsKICAgICAgICAgICAgcmVhZDogYXJnLmxlbmd0aCwKICAgICAgICAgICAgd3JpdHRlbjogYnVmLmxlbmd0aAogICAgICAgIH07CiAgICB9Owp9CgovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwovLyBXQVNNX1ZFQ1RPUl9MRU4gaXMgYSBtb2R1bGUtbGV2ZWwgdmFyaWFibGUgdGhhdCBzdG9yZXMgdGhlIGJ5dGUgbGVuZ3RoIG9mCi8vIHRoZSBkYXRhIGp1c3Qgd3JpdHRlbiBpbnRvIFdBU00gbWVtb3J5LiBJdCBhY3RzIGFzIGFuIG91dC1wYXJhbWV0ZXIuCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCgpsZXQgV0FTTV9WRUNUT1JfTEVOID0gMDsKCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCi8vIFdBU00gbW9kdWxlIHN0YXRlCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCgpsZXQgd2FzbU1vZHVsZSwgd2FzbUluc3RhbmNlLCB3YXNtOwoKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KLy8gSW5pdDoKLy8gX193YmdfZmluYWxpemVfaW5pdAovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwoKZnVuY3Rpb24gX193YmdfZmluYWxpemVfaW5pdChpbnN0YW5jZSwgbW9kdWxlLCB0aHJlYWRfc3RhY2tfc2l6ZSkgewogICAgd2FzbUluc3RhbmNlID0gaW5zdGFuY2U7CiAgICB3YXNtID0gaW5zdGFuY2UuZXhwb3J0czsKICAgIHdhc21Nb2R1bGUgPSBtb2R1bGU7CiAgICBjYWNoZWREYXRhVmlld01lbW9yeTAgPSBudWxsOwogICAgY2FjaGVkVWludDhBcnJheU1lbW9yeTAgPSBudWxsOwogICAgaWYgKHR5cGVvZiB0aHJlYWRfc3RhY2tfc2l6ZSAhPT0gJ3VuZGVmaW5lZCcgJiYgKHR5cGVvZiB0aHJlYWRfc3RhY2tfc2l6ZSAhPT0gJ251bWJlcicgfHwgdGhyZWFkX3N0YWNrX3NpemUgPT09IDAgfHwgdGhyZWFkX3N0YWNrX3NpemUgJSA2NTUzNiAhPT0gMCkpIHsKICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgc3RhY2sgc2l6ZScpOwogICAgfQogICAgd2FzbS5fX3diaW5kZ2VuX3N0YXJ0KHRocmVhZF9zdGFja19zaXplKTsKICAgIHJldHVybiB3YXNtOwp9CgovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwovLyBJbml0OgovLyBfX3diZ19sb2FkCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCgphc3luYyBmdW5jdGlvbiBfX3diZ19sb2FkKG1vZHVsZSwgaW1wb3J0cykgewogICAgaWYgKHR5cGVvZiBSZXNwb25zZSA9PT0gJ2Z1bmN0aW9uJyAmJiBtb2R1bGUgaW5zdGFuY2VvZiBSZXNwb25zZSkgewogICAgICAgIGlmICh0eXBlb2YgV2ViQXNzZW1ibHkuaW5zdGFudGlhdGVTdHJlYW1pbmcgPT09ICdmdW5jdGlvbicpIHsKICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICAgIHJldHVybiBhd2FpdCBXZWJBc3NlbWJseS5pbnN0YW50aWF0ZVN0cmVhbWluZyhtb2R1bGUsIGltcG9ydHMpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgICBjb25zdCB2YWxpZFJlc3BvbnNlID0gbW9kdWxlLm9rICYmIGV4cGVjdGVkUmVzcG9uc2VUeXBlKG1vZHVsZS50eXBlKTsKICAgICAgICAgICAgICAgIGlmICh2YWxpZFJlc3BvbnNlICYmIG1vZHVsZS5oZWFkZXJzLmdldCgnQ29udGVudC1UeXBlJykgIT09ICdhcHBsaWNhdGlvbi93YXNtJykgewogICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybigiYFdlYkFzc2VtYmx5Lmluc3RhbnRpYXRlU3RyZWFtaW5nYCBmYWlsZWQgYmVjYXVzZSB5b3VyIHNlcnZlciBkb2VzIG5vdCBzZXJ2ZSBXYXNtIHdpdGggYGFwcGxpY2F0aW9uL3dhc21gIE1JTUUgdHlwZS4gRmFsbGluZyBiYWNrIHRvIGBXZWJBc3NlbWJseS5pbnN0YW50aWF0ZWAgd2hpY2ggaXMgc2xvd2VyLiBPcmlnaW5hbCBlcnJvcjpcbiIsIGUpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgdGhyb3cgZTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBjb25zdCBieXRlcyA9IGF3YWl0IG1vZHVsZS5hcnJheUJ1ZmZlcigpOwogICAgICAgIHJldHVybiBhd2FpdCBXZWJBc3NlbWJseS5pbnN0YW50aWF0ZShieXRlcywgaW1wb3J0cyk7CiAgICB9CiAgICBlbHNlIHsKICAgICAgICBjb25zdCBpbnN0YW5jZSA9IGF3YWl0IFdlYkFzc2VtYmx5Lmluc3RhbnRpYXRlKG1vZHVsZSwgaW1wb3J0cyk7CiAgICAgICAgaWYgKGluc3RhbmNlIGluc3RhbmNlb2YgV2ViQXNzZW1ibHkuSW5zdGFuY2UpIHsKICAgICAgICAgICAgcmV0dXJuIHsgaW5zdGFuY2UsIG1vZHVsZSB9OwogICAgICAgIH0KICAgICAgICBlbHNlIHsKICAgICAgICAgICAgcmV0dXJuIGluc3RhbmNlOwogICAgICAgIH0KICAgIH0KICAgIGZ1bmN0aW9uIGV4cGVjdGVkUmVzcG9uc2VUeXBlKHR5cGUpIHsKICAgICAgICBzd2l0Y2ggKHR5cGUpIHsKICAgICAgICAgICAgY2FzZSAnYmFzaWMnOgogICAgICAgICAgICBjYXNlICdjb3JzJzoKICAgICAgICAgICAgY2FzZSAnZGVmYXVsdCc6IHJldHVybiB0cnVlOwogICAgICAgIH0KICAgICAgICByZXR1cm4gZmFsc2U7CiAgICB9Cn0KCi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCi8vIEluaXQ6Ci8vIF9fd2JnX2luaXQKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KCmFzeW5jIGZ1bmN0aW9uIF9fd2JnX2luaXQobW9kdWxlX29yX3BhdGgsIG1lbW9yeSkgewogICAgaWYgKHdhc20gIT09IHVuZGVmaW5lZCkKICAgICAgICByZXR1cm4gd2FzbTsKICAgIGxldCB0aHJlYWRfc3RhY2tfc2l6ZTsKICAgIGlmIChtb2R1bGVfb3JfcGF0aCAhPT0gdW5kZWZpbmVkKSB7CiAgICAgICAgaWYgKE9iamVjdC5nZXRQcm90b3R5cGVPZihtb2R1bGVfb3JfcGF0aCkgPT09IE9iamVjdC5wcm90b3R5cGUpIHsKICAgICAgICAgICAgKHsgbW9kdWxlX29yX3BhdGgsIG1lbW9yeSwgdGhyZWFkX3N0YWNrX3NpemUgfSA9IG1vZHVsZV9vcl9wYXRoKTsKICAgICAgICB9CiAgICAgICAgZWxzZSB7CiAgICAgICAgICAgIGNvbnNvbGUud2FybigndXNpbmcgZGVwcmVjYXRlZCBwYXJhbWV0ZXJzIGZvciB0aGUgaW5pdGlhbGl6YXRpb24gZnVuY3Rpb247IHBhc3MgYSBzaW5nbGUgb2JqZWN0IGluc3RlYWQnKTsKICAgICAgICB9CiAgICB9CiAgICAvLyAgIGlmIChtb2R1bGVfb3JfcGF0aCA9PT0gdW5kZWZpbmVkKSB7CiAgICAvLyAgICAgbW9kdWxlX29yX3BhdGggPSBuZXcgVVJMKCd0ZmhlX2JnLndhc20nLCBpbXBvcnQubWV0YS51cmwpOwogICAgLy8gICB9CiAgICBjb25zdCBpbXBvcnRzID0gX193YmdfZ2V0X2ltcG9ydHMobWVtb3J5KTsKICAgIC8vICAgaWYgKAogICAgLy8gICAgIHR5cGVvZiBtb2R1bGVfb3JfcGF0aCA9PT0gJ3N0cmluZycgfHwKICAgIC8vICAgICAodHlwZW9mIFJlcXVlc3QgPT09ICdmdW5jdGlvbicgJiYgbW9kdWxlX29yX3BhdGggaW5zdGFuY2VvZiBSZXF1ZXN0KSB8fAogICAgLy8gICAgICh0eXBlb2YgVVJMID09PSAnZnVuY3Rpb24nICYmIG1vZHVsZV9vcl9wYXRoIGluc3RhbmNlb2YgVVJMKQogICAgLy8gICApIHsKICAgIC8vICAgICBtb2R1bGVfb3JfcGF0aCA9IGZldGNoKG1vZHVsZV9vcl9wYXRoKTsKICAgIC8vICAgfQogICAgY29uc3QgeyBpbnN0YW5jZSwgbW9kdWxlIH0gPSBhd2FpdCBfX3diZ19sb2FkKGF3YWl0IG1vZHVsZV9vcl9wYXRoLCBpbXBvcnRzKTsKICAgIHJldHVybiBfX3diZ19maW5hbGl6ZV9pbml0KGluc3RhbmNlLCBtb2R1bGUsIHRocmVhZF9zdGFja19zaXplKTsKfQoKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KLy8KLy8gVGhlICd0ZmhlJyBnbG9iYWwgb2JqZWN0Ci8vID09PT09PT09PT09PT09PT09PT09PT09PQovLyBGaW5hbCB0ZmhlIG9iamVjdCBnbG9iYWwgZGVjbGFyYXRpb24gY2FsbGVkIGJ5ICd3YWl0Rm9yTXNnVHlwZScgb25seQovLwovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwoKdmFyIHRmaGUgPSAvKiNfX1BVUkVfXyovIE9iamVjdC5mcmVlemUoewogIF9fcHJvdG9fXzogbnVsbCwKICBkZWZhdWx0OiBfX3diZ19pbml0LAogIHdiZ19yYXlvbl9zdGFydF93b3JrZXI6IHdiZ19yYXlvbl9zdGFydF93b3JrZXIsCn0pOwoK";
518
- return await __newWorkerFromJsCodeBase64(workerBase64);
519
- }
520
-
521
- ////////////////////////////////////////////////////////////////////////////////
522
- // Worker initialization helpers
523
- ////////////////////////////////////////////////////////////////////////////////
524
-
525
- async function __createAndInitWorker(createWorker, workerInit, workerIndex, label) {
526
- let blobUrl = undefined;
527
- let worker = undefined;
528
-
529
- try {
530
- const result = await createWorker();
531
- worker = result.worker;
532
- blobUrl = result.blobUrl;
533
-
534
- _logger?.debug(`[Worker #${workerIndex}] - created with ${label}`);
535
- worker.postMessage(workerInit);
536
- await __waitForMsgType(worker, 'wasm_bindgen_worker_ready');
537
-
538
- if (blobUrl) {
539
- URL.revokeObjectURL(blobUrl);
540
- blobUrl = undefined;
541
- }
542
-
543
- _logger?.debug(`[Worker #${workerIndex}] - ready`);
544
- return worker;
545
- } catch (e) {
546
- if (blobUrl) {
547
- URL.revokeObjectURL(blobUrl);
548
- }
549
-
550
- if (worker) {
551
- try {
552
- await worker.terminate();
553
- } catch {
554
- // Preserve the worker creation/init error that triggered cleanup.
555
- }
556
- }
557
-
558
- throw e;
559
- }
560
- }
561
-
562
- ////////////////////////////////////////////////////////////////////////////////
563
-
564
- /**
565
- * Mode: `embedded-base64`
566
- */
567
- async function __createAndInitWorkerFromEmbeddedBase64(workerInit, workerIndex) {
568
- return await __createAndInitWorker(
569
- () => __createWorkerFromBase64(),
570
- workerInit,
571
- workerIndex,
572
- 'embedded base64 worker',
573
- );
574
- }
575
-
576
- /**
577
- * Mode: `verified-blob`
578
- */
579
- async function __createAndInitWorkerFromVerifiedBlob(workerInit, workerIndex) {
580
- return await __createAndInitWorker(
581
- () => __createWorkerFromVerifiedWorkerUrl(),
582
- workerInit,
583
- workerIndex,
584
- 'verified worker URL',
585
- );
586
- }
587
-
588
- /**
589
- * Mode: `trusted-direct-url`
590
- */
591
- async function __createAndInitWorkerFromTrustedDirectUrl(workerInit, workerIndex) {
592
- return await __createAndInitWorker(
593
- () => __createWorkerFromTrustedDirectWorkerUrl(),
594
- workerInit,
595
- workerIndex,
596
- 'trusted direct worker URL',
597
- );
598
- }
599
-
600
- /**
601
- * Mode: `precheck-direct-url`
602
- */
603
- async function __createAndInitWorkerFromCheckedDirectUrl(workerInit, workerIndex) {
604
- return await __createAndInitWorker(
605
- () => __createWorkerFromCheckedDirectWorkerUrl(),
606
- workerInit,
607
- workerIndex,
608
- 'checked direct worker URL',
609
- );
610
- }
611
-
612
- /**
613
- * Mode: `auto`
614
- */
615
- async function __createAndInitWorkerAuto(workerInit, workerIndex) {
616
- if (_workerUrl) {
617
- try {
618
- /**
619
- * Mode: `verified-blob`
620
- */
621
- return await __createAndInitWorkerFromVerifiedBlob(workerInit, workerIndex);
622
- } catch (e) {
623
- if (__isSha256MismatchError(e)) {
624
- throw e;
625
- }
626
-
627
- _logger?.error(`[Worker #${workerIndex}] - verified worker URL failed; falling back to embedded base64`, e);
628
- }
629
- }
630
-
631
- try {
632
- /**
633
- * Mode: `embedded-base64`
634
- */
635
- return await __createAndInitWorkerFromEmbeddedBase64(workerInit, workerIndex);
636
- } catch (e) {
637
- throw new Error('All worker creation methods failed. Check CSP, COOP/COEP headers, and cross-origin policies.', {
638
- cause: e,
639
- });
640
- }
641
- }
642
-
643
- ////////////////////////////////////////////////////////////////////////////////
644
- // Worker load mode dispatcher
645
- ////////////////////////////////////////////////////////////////////////////////
646
-
647
- async function __createAndInitConfiguredWorker(workerInit, workerIndex) {
648
- switch (_wasmAssetLoadMode) {
649
- case 'embedded-base64':
650
- return await __createAndInitWorkerFromEmbeddedBase64(workerInit, workerIndex);
651
-
652
- case 'verified-blob':
653
- return await __createAndInitWorkerFromVerifiedBlob(workerInit, workerIndex);
654
-
655
- case 'precheck-direct-url':
656
- return await __createAndInitWorkerFromCheckedDirectUrl(workerInit, workerIndex);
657
-
658
- case 'trusted-direct-url':
659
- return await __createAndInitWorkerFromTrustedDirectUrl(workerInit, workerIndex);
660
-
661
- case 'auto':
662
- return await __createAndInitWorkerAuto(workerInit, workerIndex);
663
-
664
- default:
665
- throw new Error(`Unsupported wasmAssetLoadMode: ${_wasmAssetLoadMode}`);
666
- }
667
- }
668
-
669
- ////////////////////////////////////////////////////////////////////////////////
670
- // Worker pool lifecycle
671
- ////////////////////////////////////////////////////////////////////////////////
672
-
673
- async function startWorkers(module, memory, builder) {
674
- if (_started) {
675
- throw new Error('Already started');
676
- }
677
-
678
- _started = true;
679
- _starting = true;
680
-
681
- try {
682
- if (_terminating) {
683
- throw new Error('Cannot start workers while termination is in progress');
684
- }
685
-
686
- if (builder.numThreads() === 0) {
687
- throw new Error(`num_threads must be > 0.`);
688
- }
689
-
690
- const workerInit = {
691
- type: 'wasm_bindgen_worker_init',
692
- init: { module_or_path: module, memory },
693
- receiver: builder.receiver(),
694
- };
695
- const results = await Promise.allSettled(
696
- Array.from({ length: builder.numThreads() }, async (_, workerIndex) => {
697
- return await __createAndInitConfiguredWorker(workerInit, workerIndex);
698
- }),
699
- );
700
-
701
- const workers = [];
702
- const errors = [];
703
-
704
- for (const result of results) {
705
- if (result.status === 'fulfilled') {
706
- workers.push(result.value);
707
- } else {
708
- errors.push(result.reason);
709
- }
710
- }
711
-
712
- if (errors.length > 0) {
713
- await Promise.allSettled(workers.map((w) => w.terminate()));
714
- throw errors[0];
715
- }
716
-
717
- _workers = workers;
718
- builder.build();
719
- } finally {
720
- _starting = false;
721
- // Drop the verified-bytes cache: each spawned worker now holds its own copy
722
- // of the script (via Blob URL or eval source), so the SDK no longer needs
723
- // to keep the bytes around. On failure the module is one-shot anyway, so
724
- // the cache would never be reused.
725
- _verifiedWorkerUrlBytesPromise = undefined;
726
- }
727
- }
728
-
729
- async function terminateWorkers() {
730
- if (_starting) {
731
- throw new Error('Cannot terminate while startWorkers() is in progress. Await the startWorkers() promise first.');
732
- }
733
-
734
- if (_terminating) {
735
- return _terminating;
736
- }
737
-
738
- if (!_workers) {
739
- return;
740
- }
741
-
742
- const workers = _workers;
743
- _workers = undefined;
744
- _terminating = Promise.allSettled(workers.map((w) => w.terminate()));
745
-
746
- return _terminating;
747
- }
748
-
749
- ////////////////////////////////////////////////////////////////////////////////
750
- // Public exports
751
- ////////////////////////////////////////////////////////////////////////////////
752
-
753
- export { getTfheWorkers, startWorkers, terminateWorkers, setWorkerUrlConfig };